]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/IdeBusPei/AtapiPeim.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / IdeBusPei / AtapiPeim.c
CommitLineData
ea060cfa 1/** @file\r
25c80c55
FT
2PEIM to produce gEfiPeiVirtualBlockIoPpiGuid & gEfiPeiVirtualBlockIo2PpiGuid PPI for\r
3ATA controllers in the platform.\r
4\r
5This PPI can be consumed by PEIM which produce gEfiPeiDeviceRecoveryModulePpiGuid\r
ea060cfa 6for Atapi CD ROM device.\r
7\r
d1102dba 8Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
ea060cfa 9\r
9d510e61 10SPDX-License-Identifier: BSD-2-Clause-Patent\r
ea060cfa 11\r
12**/\r
13\r
14#include "AtapiPeim.h"\r
15\r
16/**\r
d1102dba
LG
17 Initializes the Atapi Block Io PPI.\r
18\r
ea060cfa 19 @param[in] FileHandle Handle of the file being invoked.\r
20 @param[in] PeiServices Describes the list of possible PEI Services.\r
21\r
22 @retval EFI_SUCCESS Operation performed successfully.\r
23 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate.\r
24\r
25**/\r
26EFI_STATUS\r
27EFIAPI\r
28AtapiPeimEntry (\r
1436aea4
MK
29 IN EFI_PEI_FILE_HANDLE FileHandle,\r
30 IN CONST EFI_PEI_SERVICES **PeiServices\r
ea060cfa 31 )\r
32{\r
33 PEI_ATA_CONTROLLER_PPI *AtaControllerPpi;\r
34 EFI_STATUS Status;\r
35 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
36\r
37 Status = PeiServicesRegisterForShadow (FileHandle);\r
38 if (!EFI_ERROR (Status)) {\r
39 return Status;\r
40 }\r
41\r
42 Status = PeiServicesLocatePpi (\r
1436aea4
MK
43 &gPeiAtaControllerPpiGuid,\r
44 0,\r
45 NULL,\r
46 (VOID **)&AtaControllerPpi\r
47 );\r
ea060cfa 48 ASSERT_EFI_ERROR (Status);\r
49\r
50 AtapiBlkIoDev = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*AtapiBlkIoDev)));\r
51 if (AtapiBlkIoDev == NULL) {\r
52 return EFI_OUT_OF_RESOURCES;\r
53 }\r
54\r
55 AtapiBlkIoDev->Signature = ATAPI_BLK_IO_DEV_SIGNATURE;\r
56 AtapiBlkIoDev->AtaControllerPpi = AtaControllerPpi;\r
57\r
58 //\r
59 // atapi device enumeration and build private data\r
60 //\r
61 AtapiEnumerateDevices (AtapiBlkIoDev);\r
62\r
1436aea4
MK
63 AtapiBlkIoDev->AtapiBlkIo.GetNumberOfBlockDevices = AtapiGetNumberOfBlockDevices;\r
64 AtapiBlkIoDev->AtapiBlkIo.GetBlockDeviceMediaInfo = AtapiGetBlockDeviceMediaInfo;\r
65 AtapiBlkIoDev->AtapiBlkIo.ReadBlocks = AtapiReadBlocks;\r
25c80c55
FT
66 AtapiBlkIoDev->AtapiBlkIo2.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;\r
67 AtapiBlkIoDev->AtapiBlkIo2.GetNumberOfBlockDevices = AtapiGetNumberOfBlockDevices2;\r
68 AtapiBlkIoDev->AtapiBlkIo2.GetBlockDeviceMediaInfo = AtapiGetBlockDeviceMediaInfo2;\r
69 AtapiBlkIoDev->AtapiBlkIo2.ReadBlocks = AtapiReadBlocks2;\r
ea060cfa 70\r
1436aea4
MK
71 AtapiBlkIoDev->PpiDescriptor.Flags = EFI_PEI_PPI_DESCRIPTOR_PPI;\r
72 AtapiBlkIoDev->PpiDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid;\r
73 AtapiBlkIoDev->PpiDescriptor.Ppi = &AtapiBlkIoDev->AtapiBlkIo;\r
ea060cfa 74\r
1436aea4
MK
75 AtapiBlkIoDev->PpiDescriptor2.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
76 AtapiBlkIoDev->PpiDescriptor2.Guid = &gEfiPeiVirtualBlockIo2PpiGuid;\r
77 AtapiBlkIoDev->PpiDescriptor2.Ppi = &AtapiBlkIoDev->AtapiBlkIo2;\r
25c80c55 78\r
87000d77 79 DEBUG ((DEBUG_INFO, "Atatpi Device Count is %d\n", AtapiBlkIoDev->DeviceCount));\r
ea060cfa 80 if (AtapiBlkIoDev->DeviceCount != 0) {\r
81 Status = PeiServicesInstallPpi (&AtapiBlkIoDev->PpiDescriptor);\r
82 if (EFI_ERROR (Status)) {\r
83 return EFI_OUT_OF_RESOURCES;\r
84 }\r
85 }\r
86\r
87 return EFI_SUCCESS;\r
88}\r
89\r
90/**\r
91 Gets the count of block I/O devices that one specific block driver detects.\r
92\r
d1102dba 93 This function is used for getting the count of block I/O devices that one\r
ea060cfa 94 specific block driver detects. To the PEI ATAPI driver, it returns the number\r
d1102dba
LG
95 of all the detected ATAPI devices it detects during the enumeration process.\r
96 To the PEI legacy floppy driver, it returns the number of all the legacy\r
97 devices it finds during its enumeration process. If no device is detected,\r
98 then the function will return zero.\r
99\r
100 @param[in] PeiServices General-purpose services that are available\r
ea060cfa 101 to every PEIM.\r
d1102dba 102 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI\r
ea060cfa 103 instance.\r
104 @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
105\r
106 @retval EFI_SUCCESS Operation performed successfully.\r
107\r
108**/\r
109EFI_STATUS\r
110EFIAPI\r
111AtapiGetNumberOfBlockDevices (\r
1436aea4
MK
112 IN EFI_PEI_SERVICES **PeiServices,\r
113 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
114 OUT UINTN *NumberBlockDevices\r
ea060cfa 115 )\r
116{\r
117 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
118\r
119 AtapiBlkIoDev = NULL;\r
120\r
1436aea4 121 AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS (This);\r
ea060cfa 122\r
123 *NumberBlockDevices = AtapiBlkIoDev->DeviceCount;\r
124\r
125 return EFI_SUCCESS;\r
126}\r
127\r
128/**\r
129 Gets a block device's media information.\r
130\r
d1102dba
LG
131 This function will provide the caller with the specified block device's media\r
132 information. If the media changes, calling this function will update the media\r
ea060cfa 133 information accordingly.\r
134\r
135 @param[in] PeiServices General-purpose services that are available to every\r
136 PEIM\r
137 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
d1102dba
LG
138 @param[in] DeviceIndex Specifies the block device to which the function wants\r
139 to talk. Because the driver that implements Block I/O\r
140 PPIs will manage multiple block devices, the PPIs that\r
141 want to talk to a single device must specify the\r
ea060cfa 142 device index that was assigned during the enumeration\r
d1102dba 143 process. This index is a number from one to\r
ea060cfa 144 NumberBlockDevices.\r
d1102dba
LG
145 @param[out] MediaInfo The media information of the specified block media.\r
146 The caller is responsible for the ownership of this\r
ea060cfa 147 data structure.\r
d1102dba
LG
148\r
149 @retval EFI_SUCCESS Media information about the specified block device\r
ea060cfa 150 was obtained successfully.\r
d1102dba 151 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
ea060cfa 152 error.\r
153 @retval Others Other failure occurs.\r
154\r
155**/\r
156EFI_STATUS\r
157EFIAPI\r
158AtapiGetBlockDeviceMediaInfo (\r
1436aea4
MK
159 IN EFI_PEI_SERVICES **PeiServices,\r
160 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
161 IN UINTN DeviceIndex,\r
162 OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo\r
ea060cfa 163 )\r
164{\r
165 UINTN DeviceCount;\r
166 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
167 EFI_STATUS Status;\r
168 UINTN Index;\r
169\r
170 AtapiBlkIoDev = NULL;\r
171\r
1436aea4 172 if ((This == NULL) || (MediaInfo == NULL)) {\r
ea060cfa 173 return EFI_INVALID_PARAMETER;\r
174 }\r
175\r
176 AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS (This);\r
177\r
1436aea4 178 DeviceCount = AtapiBlkIoDev->DeviceCount;\r
ea060cfa 179\r
180 //\r
181 // DeviceIndex is a value from 1 to NumberBlockDevices.\r
182 //\r
183 if ((DeviceIndex < 1) || (DeviceIndex > DeviceCount) || (DeviceIndex > MAX_IDE_DEVICES)) {\r
184 return EFI_INVALID_PARAMETER;\r
185 }\r
186\r
187 Index = DeviceIndex - 1;\r
188\r
189 //\r
190 // probe media and retrieve latest media information\r
191 //\r
87000d77
MK
192 DEBUG ((DEBUG_INFO, "Atatpi GetInfo DevicePosition is %d\n", AtapiBlkIoDev->DeviceInfo[Index].DevicePosition));\r
193 DEBUG ((DEBUG_INFO, "Atatpi GetInfo DeviceType is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.DeviceType));\r
194 DEBUG ((DEBUG_INFO, "Atatpi GetInfo MediaPresent is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.MediaPresent));\r
195 DEBUG ((DEBUG_INFO, "Atatpi GetInfo BlockSize is 0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.BlockSize));\r
196 DEBUG ((DEBUG_INFO, "Atatpi GetInfo LastBlock is 0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.LastBlock));\r
ea060cfa 197\r
198 Status = DetectMedia (\r
199 AtapiBlkIoDev,\r
200 AtapiBlkIoDev->DeviceInfo[Index].DevicePosition,\r
25c80c55
FT
201 &AtapiBlkIoDev->DeviceInfo[Index].MediaInfo,\r
202 &AtapiBlkIoDev->DeviceInfo[Index].MediaInfo2\r
ea060cfa 203 );\r
204 if (Status != EFI_SUCCESS) {\r
205 return EFI_DEVICE_ERROR;\r
206 }\r
207\r
87000d77
MK
208 DEBUG ((DEBUG_INFO, "Atatpi GetInfo DevicePosition is %d\n", AtapiBlkIoDev->DeviceInfo[Index].DevicePosition));\r
209 DEBUG ((DEBUG_INFO, "Atatpi GetInfo DeviceType is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.DeviceType));\r
210 DEBUG ((DEBUG_INFO, "Atatpi GetInfo MediaPresent is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.MediaPresent));\r
211 DEBUG ((DEBUG_INFO, "Atatpi GetInfo BlockSize is 0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.BlockSize));\r
212 DEBUG ((DEBUG_INFO, "Atatpi GetInfo LastBlock is 0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.LastBlock));\r
d1102dba 213\r
ea060cfa 214 //\r
215 // Get media info from AtapiBlkIoDev\r
216 //\r
1436aea4 217 CopyMem (MediaInfo, &AtapiBlkIoDev->DeviceInfo[Index].MediaInfo, sizeof (EFI_PEI_BLOCK_IO_MEDIA));\r
ea060cfa 218\r
219 return EFI_SUCCESS;\r
220}\r
221\r
222/**\r
223 Reads the requested number of blocks from the specified block device.\r
224\r
d1102dba 225 The function reads the requested number of blocks from the device. All the\r
ea060cfa 226 blocks are read, or an error is returned. If there is no media in the device,\r
227 the function returns EFI_NO_MEDIA.\r
228\r
d1102dba 229 @param[in] PeiServices General-purpose services that are available to\r
ea060cfa 230 every PEIM.\r
231 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
d1102dba
LG
232 @param[in] DeviceIndex Specifies the block device to which the function wants\r
233 to talk. Because the driver that implements Block I/O\r
234 PPIs will manage multiple block devices, the PPIs that\r
235 want to talk to a single device must specify the device\r
236 index that was assigned during the enumeration process.\r
ea060cfa 237 This index is a number from one to NumberBlockDevices.\r
238 @param[in] StartLBA The starting logical block address (LBA) to read from\r
239 on the device\r
240 @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
241 a multiple of the intrinsic block size of the device.\r
242 @param[out] Buffer A pointer to the destination buffer for the data.\r
d1102dba 243 The caller is responsible for the ownership of the\r
ea060cfa 244 buffer.\r
d1102dba 245\r
ea060cfa 246 @retval EFI_SUCCESS The data was read correctly from the device.\r
d1102dba 247 @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
ea060cfa 248 to perform the read operation.\r
d1102dba 249 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
ea060cfa 250 valid, or the buffer is not properly aligned.\r
251 @retval EFI_NO_MEDIA There is no media in the device.\r
252 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
253 the intrinsic block size of the device.\r
254\r
255**/\r
256EFI_STATUS\r
257EFIAPI\r
258AtapiReadBlocks (\r
1436aea4
MK
259 IN EFI_PEI_SERVICES **PeiServices,\r
260 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
261 IN UINTN DeviceIndex,\r
262 IN EFI_PEI_LBA StartLBA,\r
263 IN UINTN BufferSize,\r
264 OUT VOID *Buffer\r
ea060cfa 265 )\r
266{\r
ea060cfa 267 EFI_PEI_BLOCK_IO_MEDIA MediaInfo;\r
25c80c55
FT
268 EFI_STATUS Status;\r
269 UINTN NumberOfBlocks;\r
270 UINTN BlockSize;\r
271 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
ea060cfa 272\r
273 AtapiBlkIoDev = NULL;\r
274\r
275 if (This == NULL) {\r
276 return EFI_INVALID_PARAMETER;\r
277 }\r
278\r
279 AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS (This);\r
280\r
281 if (Buffer == NULL) {\r
282 return EFI_INVALID_PARAMETER;\r
283 }\r
284\r
285 if (BufferSize == 0) {\r
286 return EFI_SUCCESS;\r
287 }\r
288\r
289 Status = AtapiGetBlockDeviceMediaInfo (\r
1436aea4
MK
290 PeiServices,\r
291 This,\r
292 DeviceIndex,\r
293 &MediaInfo\r
294 );\r
ea060cfa 295 if (Status != EFI_SUCCESS) {\r
296 return EFI_DEVICE_ERROR;\r
297 }\r
298\r
299 if (!MediaInfo.MediaPresent) {\r
300 return EFI_NO_MEDIA;\r
301 }\r
302\r
303 BlockSize = MediaInfo.BlockSize;\r
304\r
305 if (BufferSize % BlockSize != 0) {\r
306 return EFI_BAD_BUFFER_SIZE;\r
307 }\r
308\r
309 NumberOfBlocks = BufferSize / BlockSize;\r
310\r
25c80c55 311 if ((StartLBA + NumberOfBlocks - 1) > AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].MediaInfo2.LastBlock) {\r
ea060cfa 312 return EFI_INVALID_PARAMETER;\r
313 }\r
314\r
315 Status = ReadSectors (\r
1436aea4
MK
316 AtapiBlkIoDev,\r
317 AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].DevicePosition,\r
318 Buffer,\r
319 StartLBA,\r
320 NumberOfBlocks,\r
321 BlockSize\r
322 );\r
ea060cfa 323 if (EFI_ERROR (Status)) {\r
324 return EFI_DEVICE_ERROR;\r
325 }\r
326\r
327 return EFI_SUCCESS;\r
328}\r
329\r
25c80c55
FT
330/**\r
331 Gets the count of block I/O devices that one specific block driver detects.\r
332\r
333 This function is used for getting the count of block I/O devices that one\r
334 specific block driver detects. To the PEI ATAPI driver, it returns the number\r
335 of all the detected ATAPI devices it detects during the enumeration process.\r
336 To the PEI legacy floppy driver, it returns the number of all the legacy\r
337 devices it finds during its enumeration process. If no device is detected,\r
338 then the function will return zero.\r
339\r
340 @param[in] PeiServices General-purpose services that are available\r
341 to every PEIM.\r
342 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI\r
343 instance.\r
344 @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
345\r
346 @retval EFI_SUCCESS Operation performed successfully.\r
347\r
348**/\r
349EFI_STATUS\r
350EFIAPI\r
351AtapiGetNumberOfBlockDevices2 (\r
1436aea4
MK
352 IN EFI_PEI_SERVICES **PeiServices,\r
353 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
354 OUT UINTN *NumberBlockDevices\r
25c80c55
FT
355 )\r
356{\r
357 EFI_STATUS Status;\r
358 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
359\r
360 AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO2_THIS (This);\r
361\r
362 Status = AtapiGetNumberOfBlockDevices (\r
363 PeiServices,\r
364 &AtapiBlkIoDev->AtapiBlkIo,\r
365 NumberBlockDevices\r
366 );\r
367\r
368 return Status;\r
369}\r
370\r
371/**\r
372 Gets a block device's media information.\r
373\r
374 This function will provide the caller with the specified block device's media\r
375 information. If the media changes, calling this function will update the media\r
376 information accordingly.\r
377\r
378 @param[in] PeiServices General-purpose services that are available to every\r
379 PEIM\r
380 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
381 @param[in] DeviceIndex Specifies the block device to which the function wants\r
382 to talk. Because the driver that implements Block I/O\r
383 PPIs will manage multiple block devices, the PPIs that\r
384 want to talk to a single device must specify the\r
385 device index that was assigned during the enumeration\r
386 process. This index is a number from one to\r
387 NumberBlockDevices.\r
388 @param[out] MediaInfo The media information of the specified block media.\r
389 The caller is responsible for the ownership of this\r
390 data structure.\r
391\r
392 @retval EFI_SUCCESS Media information about the specified block device\r
393 was obtained successfully.\r
394 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
395 error.\r
396 @retval Others Other failure occurs.\r
397\r
398**/\r
399EFI_STATUS\r
400EFIAPI\r
401AtapiGetBlockDeviceMediaInfo2 (\r
1436aea4
MK
402 IN EFI_PEI_SERVICES **PeiServices,\r
403 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
404 IN UINTN DeviceIndex,\r
405 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo\r
25c80c55
FT
406 )\r
407{\r
1436aea4
MK
408 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
409 EFI_STATUS Status;\r
410 EFI_PEI_BLOCK_IO_MEDIA Media;\r
25c80c55
FT
411\r
412 AtapiBlkIoDev = NULL;\r
413\r
1436aea4 414 if ((This == NULL) || (MediaInfo == NULL)) {\r
25c80c55
FT
415 return EFI_INVALID_PARAMETER;\r
416 }\r
417\r
418 AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO2_THIS (This);\r
419\r
420 Status = AtapiGetBlockDeviceMediaInfo (\r
421 PeiServices,\r
422 &AtapiBlkIoDev->AtapiBlkIo,\r
423 DeviceIndex,\r
424 &Media\r
425 );\r
426 if (EFI_ERROR (Status)) {\r
427 return Status;\r
428 }\r
1436aea4 429\r
25c80c55
FT
430 //\r
431 // Get media info from AtapiBlkIoDev\r
432 //\r
1436aea4 433 CopyMem (MediaInfo, &AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].MediaInfo2, sizeof (EFI_PEI_BLOCK_IO2_MEDIA));\r
25c80c55
FT
434\r
435 return EFI_SUCCESS;\r
436}\r
437\r
438/**\r
439 Reads the requested number of blocks from the specified block device.\r
440\r
441 The function reads the requested number of blocks from the device. All the\r
442 blocks are read, or an error is returned. If there is no media in the device,\r
443 the function returns EFI_NO_MEDIA.\r
444\r
445 @param[in] PeiServices General-purpose services that are available to\r
446 every PEIM.\r
447 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
448 @param[in] DeviceIndex Specifies the block device to which the function wants\r
449 to talk. Because the driver that implements Block I/O\r
450 PPIs will manage multiple block devices, the PPIs that\r
451 want to talk to a single device must specify the device\r
452 index that was assigned during the enumeration process.\r
453 This index is a number from one to NumberBlockDevices.\r
454 @param[in] StartLBA The starting logical block address (LBA) to read from\r
455 on the device\r
456 @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
457 a multiple of the intrinsic block size of the device.\r
458 @param[out] Buffer A pointer to the destination buffer for the data.\r
459 The caller is responsible for the ownership of the\r
460 buffer.\r
461\r
462 @retval EFI_SUCCESS The data was read correctly from the device.\r
463 @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
464 to perform the read operation.\r
465 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
466 valid, or the buffer is not properly aligned.\r
467 @retval EFI_NO_MEDIA There is no media in the device.\r
468 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
469 the intrinsic block size of the device.\r
470\r
471**/\r
472EFI_STATUS\r
473EFIAPI\r
474AtapiReadBlocks2 (\r
1436aea4
MK
475 IN EFI_PEI_SERVICES **PeiServices,\r
476 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
477 IN UINTN DeviceIndex,\r
478 IN EFI_PEI_LBA StartLBA,\r
479 IN UINTN BufferSize,\r
480 OUT VOID *Buffer\r
25c80c55
FT
481 )\r
482{\r
1436aea4
MK
483 EFI_STATUS Status;\r
484 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
25c80c55
FT
485\r
486 AtapiBlkIoDev = NULL;\r
487\r
488 if (This == NULL) {\r
489 return EFI_INVALID_PARAMETER;\r
490 }\r
491\r
492 AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO2_THIS (This);\r
493\r
494 Status = AtapiReadBlocks (\r
495 PeiServices,\r
496 &AtapiBlkIoDev->AtapiBlkIo,\r
497 DeviceIndex,\r
498 StartLBA,\r
499 BufferSize,\r
500 Buffer\r
501 );\r
502\r
503 return Status;\r
504}\r
505\r
ea060cfa 506/**\r
507 Enumerate Atapi devices.\r
508\r
509 This function is used to enumerate Atatpi device in Ide channel.\r
510\r
511 @param[in] AtapiBlkIoDev A pointer to atapi block IO device\r
512\r
513**/\r
514VOID\r
515AtapiEnumerateDevices (\r
516 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev\r
517 )\r
518{\r
1436aea4
MK
519 UINT8 Index1;\r
520 UINT8 Index2;\r
521 UINTN DevicePosition;\r
522 EFI_PEI_BLOCK_IO_MEDIA MediaInfo;\r
523 EFI_PEI_BLOCK_IO2_MEDIA MediaInfo2;\r
524 EFI_STATUS Status;\r
525 UINTN DeviceCount;\r
526 UINT16 CommandBlockBaseAddr;\r
527 UINT16 ControlBlockBaseAddr;\r
528 UINT32 IdeEnabledNumber;\r
529 IDE_REGS_BASE_ADDR IdeRegsBaseAddr[MAX_IDE_CHANNELS];\r
530\r
531 DeviceCount = 0;\r
ea060cfa 532 DevicePosition = 0;\r
533\r
534 //\r
535 // Scan IDE bus for ATAPI devices\r
536 //\r
537\r
538 //\r
539 // Enable Sata and IDE controller.\r
540 //\r
541 AtapiBlkIoDev->AtaControllerPpi->EnableAtaChannel (\r
1436aea4
MK
542 (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),\r
543 AtapiBlkIoDev->AtaControllerPpi,\r
544 PEI_ICH_IDE_PRIMARY | PEI_ICH_IDE_SECONDARY\r
545 );\r
ea060cfa 546\r
547 //\r
d1102dba 548 // Allow SATA Devices to spin-up. This is needed if\r
ea060cfa 549 // SEC and PEI phase is too short, for example Release Build.\r
550 //\r
87000d77 551 DEBUG ((DEBUG_INFO, "Delay for %d seconds for SATA devices to spin-up\n", PcdGet16 (PcdSataSpinUpDelayInSecForRecoveryPath)));\r
ea060cfa 552 MicroSecondDelay (PcdGet16 (PcdSataSpinUpDelayInSecForRecoveryPath) * 1000 * 1000); //\r
553\r
554 //\r
555 // Get four channels (primary or secondary Pata, Sata Channel) Command and Control Regs Base address.\r
556 //\r
557 IdeEnabledNumber = AtapiBlkIoDev->AtaControllerPpi->GetIdeRegsBaseAddr (\r
1436aea4
MK
558 (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),\r
559 AtapiBlkIoDev->AtaControllerPpi,\r
560 IdeRegsBaseAddr\r
561 );\r
ea060cfa 562\r
563 //\r
564 // Using Command and Control Regs Base Address to fill other registers.\r
565 //\r
1436aea4
MK
566 for (Index1 = 0; Index1 < IdeEnabledNumber; Index1++) {\r
567 CommandBlockBaseAddr = IdeRegsBaseAddr[Index1].CommandBlockBaseAddr;\r
ea060cfa 568 AtapiBlkIoDev->IdeIoPortReg[Index1].Data = CommandBlockBaseAddr;\r
1436aea4
MK
569 AtapiBlkIoDev->IdeIoPortReg[Index1].Reg1.Feature = (UINT16)(CommandBlockBaseAddr + 0x1);\r
570 AtapiBlkIoDev->IdeIoPortReg[Index1].SectorCount = (UINT16)(CommandBlockBaseAddr + 0x2);\r
571 AtapiBlkIoDev->IdeIoPortReg[Index1].SectorNumber = (UINT16)(CommandBlockBaseAddr + 0x3);\r
572 AtapiBlkIoDev->IdeIoPortReg[Index1].CylinderLsb = (UINT16)(CommandBlockBaseAddr + 0x4);\r
573 AtapiBlkIoDev->IdeIoPortReg[Index1].CylinderMsb = (UINT16)(CommandBlockBaseAddr + 0x5);\r
574 AtapiBlkIoDev->IdeIoPortReg[Index1].Head = (UINT16)(CommandBlockBaseAddr + 0x6);\r
575 AtapiBlkIoDev->IdeIoPortReg[Index1].Reg.Command = (UINT16)(CommandBlockBaseAddr + 0x7);\r
576\r
577 ControlBlockBaseAddr = IdeRegsBaseAddr[Index1].ControlBlockBaseAddr;\r
ea060cfa 578 AtapiBlkIoDev->IdeIoPortReg[Index1].Alt.DeviceControl = ControlBlockBaseAddr;\r
1436aea4 579 AtapiBlkIoDev->IdeIoPortReg[Index1].DriveAddress = (UINT16)(ControlBlockBaseAddr + 0x1);\r
d1102dba 580\r
ea060cfa 581 //\r
582 // Scan IDE bus for ATAPI devices IDE or Sata device\r
583 //\r
584 for (Index2 = IdeMaster; Index2 < IdeMaxDevice; Index2++) {\r
585 //\r
586 // Pata & Sata, Primary & Secondary channel, Master & Slave device\r
587 //\r
16f69227 588 DevicePosition = Index1 * 2 + Index2;\r
ea060cfa 589\r
25c80c55 590 if (DiscoverAtapiDevice (AtapiBlkIoDev, DevicePosition, &MediaInfo, &MediaInfo2)) {\r
ea060cfa 591 //\r
592 // ATAPI Device at DevicePosition is found.\r
593 //\r
594 AtapiBlkIoDev->DeviceInfo[DeviceCount].DevicePosition = DevicePosition;\r
595 //\r
596 // Retrieve Media Info\r
597 //\r
1436aea4 598 Status = DetectMedia (AtapiBlkIoDev, DevicePosition, &MediaInfo, &MediaInfo2);\r
ea060cfa 599 CopyMem (&(AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo), &MediaInfo, sizeof (MediaInfo));\r
25c80c55
FT
600 CopyMem (&(AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2), &MediaInfo2, sizeof (MediaInfo2));\r
601\r
87000d77
MK
602 DEBUG ((DEBUG_INFO, "Atatpi Device Position is %d\n", DevicePosition));\r
603 DEBUG ((DEBUG_INFO, "Atatpi DeviceType is %d\n", MediaInfo.DeviceType));\r
604 DEBUG ((DEBUG_INFO, "Atatpi MediaPresent is %d\n", MediaInfo.MediaPresent));\r
605 DEBUG ((DEBUG_INFO, "Atatpi BlockSize is 0x%x\n", MediaInfo.BlockSize));\r
ea060cfa 606\r
607 if (EFI_ERROR (Status)) {\r
1436aea4
MK
608 AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo.MediaPresent = FALSE;\r
609 AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo.LastBlock = 0;\r
25c80c55
FT
610 AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2.MediaPresent = FALSE;\r
611 AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2.LastBlock = 0;\r
ea060cfa 612 }\r
1436aea4 613\r
ea060cfa 614 DeviceCount += 1;\r
615 }\r
616 }\r
617 }\r
618\r
619 AtapiBlkIoDev->DeviceCount = DeviceCount;\r
620}\r
621\r
622/**\r
623 Detect Atapi devices.\r
d1102dba 624\r
ea060cfa 625 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
626 @param[in] DevicePosition An integer to signify device position.\r
627 @param[out] MediaInfo The media information of the specified block media.\r
25c80c55 628 @param[out] MediaInfo2 The media information 2 of the specified block media.\r
ea060cfa 629\r
630 @retval TRUE Atapi device exists in specified position.\r
631 @retval FALSE Atapi device does not exist in specified position.\r
632\r
633**/\r
634BOOLEAN\r
635DiscoverAtapiDevice (\r
1436aea4
MK
636 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
637 IN UINTN DevicePosition,\r
638 OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,\r
639 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2\r
ea060cfa 640 )\r
641{\r
642 EFI_STATUS Status;\r
643\r
644 if (!DetectIDEController (AtapiBlkIoDev, DevicePosition)) {\r
645 return FALSE;\r
646 }\r
1436aea4 647\r
ea060cfa 648 //\r
649 // test if it is an ATAPI device (only supported device)\r
650 //\r
651 if (ATAPIIdentify (AtapiBlkIoDev, DevicePosition) == EFI_SUCCESS) {\r
25c80c55 652 Status = Inquiry (AtapiBlkIoDev, DevicePosition, MediaInfo, MediaInfo2);\r
ea060cfa 653 if (!EFI_ERROR (Status)) {\r
654 return TRUE;\r
655 }\r
656 }\r
657\r
658 return FALSE;\r
659}\r
660\r
661/**\r
662 Check power mode of Atapi devices.\r
d1102dba 663\r
ea060cfa 664 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
665 @param[in] DevicePosition An integer to signify device position.\r
666 @param[in] AtaCommand The Ata Command passed in.\r
667\r
668 @retval EFI_SUCCESS The Atapi device support power mode.\r
669 @retval EFI_NOT_FOUND The Atapi device not found.\r
670 @retval EFI_TIMEOUT Atapi command transaction is time out.\r
671 @retval EFI_ABORTED Atapi command abort.\r
672\r
673**/\r
674EFI_STATUS\r
675CheckPowerMode (\r
1436aea4
MK
676 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
677 IN UINTN DevicePosition,\r
678 IN UINT8 AtaCommand\r
ea060cfa 679 )\r
680{\r
681 UINT8 Channel;\r
682 UINT8 Device;\r
683 UINT16 StatusRegister;\r
684 UINT16 HeadRegister;\r
685 UINT16 CommandRegister;\r
686 UINT16 ErrorRegister;\r
687 UINT16 SectorCountRegister;\r
688 EFI_STATUS Status;\r
689 UINT8 StatusValue;\r
690 UINT8 ErrorValue;\r
691 UINT8 SectorCountValue;\r
692\r
1436aea4
MK
693 Channel = (UINT8)(DevicePosition / 2);\r
694 Device = (UINT8)(DevicePosition % 2);\r
ea060cfa 695\r
696 ASSERT (Channel < MAX_IDE_CHANNELS);\r
697\r
698 StatusRegister = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Status;\r
699 HeadRegister = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;\r
700 CommandRegister = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;\r
701 ErrorRegister = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg1.Error;\r
702 SectorCountRegister = AtapiBlkIoDev->IdeIoPortReg[Channel].SectorCount;\r
703\r
704 //\r
705 // select device\r
706 //\r
1436aea4 707 IoWrite8 (HeadRegister, (UINT8)((Device << 4) | 0xe0));\r
ea060cfa 708\r
709 //\r
710 // refresh the SectorCount register\r
711 //\r
712 SectorCountValue = 0x55;\r
713 IoWrite8 (SectorCountRegister, SectorCountValue);\r
714\r
715 //\r
716 // select device\r
717 //\r
1436aea4 718 IoWrite8 (HeadRegister, (UINT8)((Device << 4) | 0xe0));\r
ea060cfa 719\r
720 Status = DRDYReady (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 100);\r
721\r
722 //\r
723 // select device\r
724 //\r
1436aea4 725 IoWrite8 (HeadRegister, (UINT8)((Device << 4) | 0xe0));\r
ea060cfa 726 //\r
727 // send 'check power' commandd via Command Register\r
728 //\r
729 IoWrite8 (CommandRegister, AtaCommand);\r
730\r
731 Status = WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 3000);\r
732 if (EFI_ERROR (Status)) {\r
733 return EFI_TIMEOUT;\r
734 }\r
735\r
736 StatusValue = IoRead8 (StatusRegister);\r
737\r
738 //\r
739 // command returned status is DRDY, indicating device supports the command,\r
740 // so device is present.\r
741 //\r
742 if ((StatusValue & ATA_STSREG_DRDY) == ATA_STSREG_DRDY) {\r
743 return EFI_SUCCESS;\r
744 }\r
745\r
746 SectorCountValue = IoRead8 (SectorCountRegister);\r
747\r
748 //\r
749 // command returned status is ERR & ABRT_ERR, indicating device does not support\r
750 // the command, so device is present.\r
751 //\r
752 if ((StatusValue & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
753 ErrorValue = IoRead8 (ErrorRegister);\r
754 if ((ErrorValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
755 return EFI_ABORTED;\r
756 } else {\r
757 //\r
758 // According to spec, no other error code is valid\r
759 //\r
760 return EFI_NOT_FOUND;\r
761 }\r
762 }\r
763\r
764 if ((SectorCountValue == 0x00) || (SectorCountValue == 0x80) || (SectorCountValue == 0xff)) {\r
765 //\r
766 // Write SectorCount 0x55 but return valid state value. Maybe no device\r
767 // exists or some slow kind of ATAPI device exists.\r
768 //\r
1436aea4 769 IoWrite8 (HeadRegister, (UINT8)((Device << 4) | 0xe0));\r
ea060cfa 770\r
771 //\r
772 // write 0x55 and 0xaa to SectorCounter register,\r
773 // if the data could be written into the register,\r
774 // indicating the device is present, otherwise the device is not present.\r
775 //\r
776 SectorCountValue = 0x55;\r
777 IoWrite8 (SectorCountRegister, SectorCountValue);\r
778 MicroSecondDelay (10000);\r
779\r
780 SectorCountValue = IoRead8 (SectorCountRegister);\r
781 if (SectorCountValue != 0x55) {\r
782 return EFI_NOT_FOUND;\r
783 }\r
1436aea4 784\r
ea060cfa 785 //\r
786 // Send a "ATAPI TEST UNIT READY" command ... slow but accurate\r
787 //\r
788 Status = TestUnitReady (AtapiBlkIoDev, DevicePosition);\r
789 return Status;\r
790 }\r
791\r
792 return EFI_NOT_FOUND;\r
793}\r
794\r
795/**\r
796 Detect if an IDE controller exists in specified position.\r
d1102dba 797\r
ea060cfa 798 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
799 @param[in] DevicePosition An integer to signify device position.\r
800\r
801 @retval TRUE The Atapi device exists.\r
802 @retval FALSE The Atapi device does not present.\r
803\r
804**/\r
805BOOLEAN\r
806DetectIDEController (\r
1436aea4
MK
807 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
808 IN UINTN DevicePosition\r
ea060cfa 809 )\r
810{\r
811 UINT8 Channel;\r
812 EFI_STATUS Status;\r
813 UINT8 AtaCommand;\r
814\r
1436aea4 815 Channel = (UINT8)(DevicePosition / 2);\r
ea060cfa 816\r
817 ASSERT (Channel < MAX_IDE_CHANNELS);\r
818 //\r
819 // Wait 31 seconds for BSY clear\r
820 //\r
821 Status = WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 31000);\r
822 if (EFI_ERROR (Status)) {\r
823 return FALSE;\r
824 }\r
1436aea4 825\r
ea060cfa 826 //\r
827 // Send 'check power' command for IDE device\r
828 //\r
1436aea4
MK
829 AtaCommand = 0xE5;\r
830 Status = CheckPowerMode (AtapiBlkIoDev, DevicePosition, AtaCommand);\r
ea060cfa 831 if ((Status == EFI_ABORTED) || (Status == EFI_SUCCESS)) {\r
832 return TRUE;\r
833 }\r
834\r
835 return FALSE;\r
836}\r
837\r
838/**\r
839 Wait specified time interval to poll for BSY bit clear in the Status Register.\r
d1102dba 840\r
ea060cfa 841 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
842 @param[in] IdeIoRegisters A pointer to IDE IO registers.\r
843 @param[in] TimeoutInMilliSeconds Time specified in milliseconds.\r
844\r
845 @retval EFI_SUCCESS BSY bit is cleared in the specified time interval.\r
846 @retval EFI_TIMEOUT BSY bit is not cleared in the specified time interval.\r
847\r
848**/\r
849EFI_STATUS\r
850WaitForBSYClear (\r
851 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
852 IN IDE_BASE_REGISTERS *IdeIoRegisters,\r
853 IN UINTN TimeoutInMilliSeconds\r
854 )\r
855{\r
856 UINTN Delay;\r
857 UINT16 StatusRegister;\r
858 UINT8 StatusValue;\r
859\r
1436aea4 860 StatusValue = 0;\r
ea060cfa 861\r
1436aea4 862 StatusRegister = IdeIoRegisters->Reg.Status;\r
ea060cfa 863\r
1436aea4 864 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
ea060cfa 865 do {\r
866 StatusValue = IoRead8 (StatusRegister);\r
867 if ((StatusValue & ATA_STSREG_BSY) == 0x00) {\r
868 break;\r
869 }\r
1436aea4 870\r
ea060cfa 871 MicroSecondDelay (250);\r
872\r
873 Delay--;\r
ea060cfa 874 } while (Delay != 0);\r
875\r
876 if (Delay == 0) {\r
877 return EFI_TIMEOUT;\r
878 }\r
879\r
880 return EFI_SUCCESS;\r
881}\r
882\r
883/**\r
884 Wait specified time interval to poll for DRDY bit set in the Status register.\r
d1102dba 885\r
ea060cfa 886 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
887 @param[in] IdeIoRegisters A pointer to IDE IO registers.\r
888 @param[in] TimeoutInMilliSeconds Time specified in milliseconds.\r
889\r
890 @retval EFI_SUCCESS DRDY bit is set in the specified time interval.\r
891 @retval EFI_TIMEOUT DRDY bit is not set in the specified time interval.\r
892\r
893**/\r
894EFI_STATUS\r
895DRDYReady (\r
896 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
897 IN IDE_BASE_REGISTERS *IdeIoRegisters,\r
898 IN UINTN TimeoutInMilliSeconds\r
899 )\r
900{\r
901 UINTN Delay;\r
902 UINT16 StatusRegister;\r
903 UINT8 StatusValue;\r
904 UINT8 ErrValue;\r
905\r
1436aea4 906 StatusValue = 0;\r
ea060cfa 907\r
1436aea4 908 StatusRegister = IdeIoRegisters->Reg.Status;\r
ea060cfa 909\r
1436aea4 910 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
ea060cfa 911 do {\r
912 StatusValue = IoRead8 (StatusRegister);\r
913 //\r
914 // BSY == 0 , DRDY == 1\r
915 //\r
916 if ((StatusValue & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
917 break;\r
918 }\r
919\r
1436aea4
MK
920 if ((StatusValue & (ATA_STSREG_ERR | ATA_STSREG_BSY)) == ATA_STSREG_ERR) {\r
921 ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);\r
922 if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
923 return EFI_ABORTED;\r
924 }\r
ea060cfa 925 }\r
d1102dba 926\r
ea060cfa 927 MicroSecondDelay (250);\r
928\r
929 Delay--;\r
ea060cfa 930 } while (Delay != 0);\r
931\r
932 if (Delay == 0) {\r
933 return EFI_TIMEOUT;\r
934 }\r
935\r
936 return EFI_SUCCESS;\r
937}\r
938\r
939/**\r
940 Wait specified time interval to poll for DRQ bit clear in the Status Register.\r
d1102dba 941\r
ea060cfa 942 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
943 @param[in] IdeIoRegisters A pointer to IDE IO registers.\r
944 @param[in] TimeoutInMilliSeconds Time specified in milliseconds.\r
945\r
946 @retval EFI_SUCCESS DRQ bit is cleared in the specified time interval.\r
947 @retval EFI_TIMEOUT DRQ bit is not cleared in the specified time interval.\r
948\r
949**/\r
950EFI_STATUS\r
951DRQClear (\r
952 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
953 IN IDE_BASE_REGISTERS *IdeIoRegisters,\r
954 IN UINTN TimeoutInMilliSeconds\r
955 )\r
956{\r
957 UINTN Delay;\r
958 UINT16 StatusRegister;\r
959 UINT8 StatusValue;\r
960 UINT8 ErrValue;\r
961\r
1436aea4 962 StatusValue = 0;\r
ea060cfa 963\r
1436aea4 964 StatusRegister = IdeIoRegisters->Reg.Status;\r
ea060cfa 965\r
1436aea4 966 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
ea060cfa 967 do {\r
ea060cfa 968 StatusValue = IoRead8 (StatusRegister);\r
969\r
970 //\r
971 // wait for BSY == 0 and DRQ == 0\r
972 //\r
973 if ((StatusValue & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
974 break;\r
975 }\r
976\r
1436aea4
MK
977 if ((StatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
978 ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);\r
979 if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
980 return EFI_ABORTED;\r
981 }\r
ea060cfa 982 }\r
d1102dba 983\r
ea060cfa 984 MicroSecondDelay (250);\r
985\r
986 Delay--;\r
987 } while (Delay != 0);\r
988\r
989 if (Delay == 0) {\r
990 return EFI_TIMEOUT;\r
991 }\r
992\r
993 return EFI_SUCCESS;\r
994}\r
995\r
996/**\r
997 Wait specified time interval to poll for DRQ bit clear in the Alternate Status Register.\r
d1102dba 998\r
ea060cfa 999 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1000 @param[in] IdeIoRegisters A pointer to IDE IO registers.\r
1001 @param[in] TimeoutInMilliSeconds Time specified in milliseconds.\r
1002\r
1003 @retval EFI_SUCCESS DRQ bit is cleared in the specified time interval.\r
1004 @retval EFI_TIMEOUT DRQ bit is not cleared in the specified time interval.\r
1005\r
1006**/\r
1007EFI_STATUS\r
1008DRQClear2 (\r
1009 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1010 IN IDE_BASE_REGISTERS *IdeIoRegisters,\r
1011 IN UINTN TimeoutInMilliSeconds\r
1012 )\r
1013{\r
1014 UINTN Delay;\r
1015 UINT16 AltStatusRegister;\r
1016 UINT8 AltStatusValue;\r
1017 UINT8 ErrValue;\r
1018\r
1436aea4 1019 AltStatusValue = 0;\r
ea060cfa 1020\r
1021 AltStatusRegister = IdeIoRegisters->Alt.AltStatus;\r
1022\r
1436aea4 1023 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
ea060cfa 1024 do {\r
ea060cfa 1025 AltStatusValue = IoRead8 (AltStatusRegister);\r
1026\r
1027 //\r
1028 // wait for BSY == 0 and DRQ == 0\r
1029 //\r
1030 if ((AltStatusValue & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
1031 break;\r
1032 }\r
1033\r
1436aea4
MK
1034 if ((AltStatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
1035 ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);\r
1036 if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
1037 return EFI_ABORTED;\r
1038 }\r
ea060cfa 1039 }\r
d1102dba 1040\r
ea060cfa 1041 MicroSecondDelay (250);\r
1042\r
1043 Delay--;\r
1044 } while (Delay != 0);\r
1045\r
1046 if (Delay == 0) {\r
1047 return EFI_TIMEOUT;\r
1048 }\r
1049\r
1050 return EFI_SUCCESS;\r
1051}\r
1052\r
1053/**\r
1054 Wait specified time interval to poll for DRQ bit set in the Status Register.\r
1055\r
1056 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1057 @param[in] IdeIoRegisters A pointer to IDE IO registers.\r
1058 @param[in] TimeoutInMilliSeconds Time specified in milliseconds.\r
1059\r
1060 @retval EFI_SUCCESS DRQ bit is set in the specified time interval.\r
1061 @retval EFI_TIMEOUT DRQ bit is not set in the specified time interval.\r
1062 @retval EFI_ABORTED Operation Aborted.\r
1063\r
1064**/\r
1065EFI_STATUS\r
1066DRQReady (\r
1067 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1068 IN IDE_BASE_REGISTERS *IdeIoRegisters,\r
1069 IN UINTN TimeoutInMilliSeconds\r
1070 )\r
1071{\r
1072 UINTN Delay;\r
1073 UINT16 StatusRegister;\r
1074 UINT8 StatusValue;\r
1075 UINT8 ErrValue;\r
1076\r
1436aea4
MK
1077 StatusValue = 0;\r
1078 ErrValue = 0;\r
ea060cfa 1079\r
1436aea4 1080 StatusRegister = IdeIoRegisters->Reg.Status;\r
ea060cfa 1081\r
1436aea4 1082 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
ea060cfa 1083 do {\r
1084 //\r
1085 // read Status Register will clear interrupt\r
1086 //\r
1087 StatusValue = IoRead8 (StatusRegister);\r
1088\r
1089 //\r
1090 // BSY==0,DRQ==1\r
1091 //\r
1092 if ((StatusValue & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
1093 break;\r
1094 }\r
1095\r
1096 if ((StatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ea060cfa 1097 ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);\r
1098 if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
1099 return EFI_ABORTED;\r
1100 }\r
1101 }\r
1436aea4 1102\r
ea060cfa 1103 MicroSecondDelay (250);\r
1104\r
1105 Delay--;\r
1106 } while (Delay != 0);\r
1107\r
1108 if (Delay == 0) {\r
1109 return EFI_TIMEOUT;\r
1110 }\r
1111\r
1112 return EFI_SUCCESS;\r
1113}\r
1114\r
1115/**\r
1116 Wait specified time interval to poll for DRQ bit set in the Alternate Status Register.\r
1117\r
1118 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1119 @param[in] IdeIoRegisters A pointer to IDE IO registers.\r
1120 @param[in] TimeoutInMilliSeconds Time specified in milliseconds.\r
1121\r
1122 @retval EFI_SUCCESS DRQ bit is set in the specified time interval.\r
1123 @retval EFI_TIMEOUT DRQ bit is not set in the specified time interval.\r
1124 @retval EFI_ABORTED Operation Aborted.\r
1125\r
1126**/\r
1127EFI_STATUS\r
1128DRQReady2 (\r
1129 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1130 IN IDE_BASE_REGISTERS *IdeIoRegisters,\r
1131 IN UINTN TimeoutInMilliSeconds\r
1132 )\r
1133{\r
1134 UINTN Delay;\r
1135 UINT16 AltStatusRegister;\r
1136 UINT8 AltStatusValue;\r
1137 UINT8 ErrValue;\r
1138\r
1436aea4 1139 AltStatusValue = 0;\r
ea060cfa 1140\r
1141 AltStatusRegister = IdeIoRegisters->Alt.AltStatus;\r
1142\r
1436aea4 1143 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
ea060cfa 1144 do {\r
ea060cfa 1145 AltStatusValue = IoRead8 (AltStatusRegister);\r
1146\r
1147 //\r
1148 // BSY==0,DRQ==1\r
1149 //\r
1150 if ((AltStatusValue & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
1151 break;\r
1152 }\r
1153\r
1154 if ((AltStatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ea060cfa 1155 ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);\r
1156 if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
1157 return EFI_ABORTED;\r
1158 }\r
1159 }\r
1436aea4 1160\r
ea060cfa 1161 MicroSecondDelay (250);\r
1162\r
1163 Delay--;\r
1164 } while (Delay != 0);\r
1165\r
1166 if (Delay == 0) {\r
1167 return EFI_TIMEOUT;\r
1168 }\r
1169\r
1170 return EFI_SUCCESS;\r
1171}\r
1172\r
1173/**\r
1174 Check if there is an error in Status Register.\r
1175\r
1176 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1177 @param[in] StatusReg The address to IDE IO registers.\r
1178\r
1179 @retval EFI_SUCCESS Operation success.\r
1180 @retval EFI_DEVICE_ERROR Device error.\r
1181\r
1182**/\r
1183EFI_STATUS\r
1184CheckErrorStatus (\r
1436aea4
MK
1185 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1186 IN UINT16 StatusReg\r
ea060cfa 1187 )\r
1188{\r
1436aea4 1189 UINT8 StatusValue;\r
ea060cfa 1190\r
1191 StatusValue = IoRead8 (StatusReg);\r
1192\r
1193 if ((StatusValue & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {\r
ea060cfa 1194 return EFI_SUCCESS;\r
1195 }\r
1196\r
1197 return EFI_DEVICE_ERROR;\r
ea060cfa 1198}\r
1199\r
1200/**\r
1201 Idendify Atapi devices.\r
1202\r
1203 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1204 @param[in] DevicePosition An integer to signify device position.\r
1205\r
1206 @retval EFI_SUCCESS Identify successfully.\r
1207 @retval EFI_DEVICE_ERROR Device cannot be identified successfully.\r
1208\r
1209**/\r
1210EFI_STATUS\r
1211ATAPIIdentify (\r
1436aea4
MK
1212 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1213 IN UINTN DevicePosition\r
ea060cfa 1214 )\r
1215{\r
1216 ATAPI_IDENTIFY_DATA AtapiIdentifyData;\r
25c80c55
FT
1217 UINT8 Channel;\r
1218 UINT8 Device;\r
1219 UINT16 StatusReg;\r
1220 UINT16 HeadReg;\r
1221 UINT16 CommandReg;\r
1222 UINT16 DataReg;\r
1223 UINT16 SectorCountReg;\r
1224 UINT16 SectorNumberReg;\r
1225 UINT16 CylinderLsbReg;\r
1226 UINT16 CylinderMsbReg;\r
1227\r
1436aea4
MK
1228 UINT32 WordCount;\r
1229 UINT32 Increment;\r
1230 UINT32 Index;\r
1231 UINT32 ByteCount;\r
1232 UINT16 *Buffer16;\r
25c80c55 1233\r
1436aea4 1234 EFI_STATUS Status;\r
ea060cfa 1235\r
1436aea4
MK
1236 ByteCount = sizeof (AtapiIdentifyData);\r
1237 Buffer16 = (UINT16 *)&AtapiIdentifyData;\r
ea060cfa 1238\r
1436aea4
MK
1239 Channel = (UINT8)(DevicePosition / 2);\r
1240 Device = (UINT8)(DevicePosition % 2);\r
ea060cfa 1241\r
1242 ASSERT (Channel < MAX_IDE_CHANNELS);\r
1243\r
1244 StatusReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Status;\r
1245 HeadReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;\r
1246 CommandReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;\r
1247 DataReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Data;\r
1248 SectorCountReg = AtapiBlkIoDev->IdeIoPortReg[Channel].SectorCount;\r
1249 SectorNumberReg = AtapiBlkIoDev->IdeIoPortReg[Channel].SectorNumber;\r
1250 CylinderLsbReg = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderLsb;\r
1251 CylinderMsbReg = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderMsb;\r
1252\r
1253 //\r
1254 // Send ATAPI Identify Command to get IDENTIFY data.\r
1255 //\r
1256 if (WaitForBSYClear (\r
1257 AtapiBlkIoDev,\r
1258 &(AtapiBlkIoDev->IdeIoPortReg[Channel]),\r
1259 ATATIMEOUT\r
1436aea4
MK
1260 ) != EFI_SUCCESS)\r
1261 {\r
ea060cfa 1262 return EFI_DEVICE_ERROR;\r
1263 }\r
1436aea4 1264\r
ea060cfa 1265 //\r
1266 // select device via Head/Device register.\r
1267 // Before write Head/Device register, BSY and DRQ must be 0.\r
1268 //\r
1269 if (DRQClear2 (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), ATATIMEOUT) != EFI_SUCCESS) {\r
1270 return EFI_DEVICE_ERROR;\r
1271 }\r
1436aea4 1272\r
ea060cfa 1273 //\r
1274 // e0:1110,0000-- bit7 and bit5 are reserved bits.\r
1275 // bit6 set means LBA mode\r
1276 //\r
1436aea4 1277 IoWrite8 (HeadReg, (UINT8)((Device << 4) | 0xe0));\r
ea060cfa 1278\r
1279 //\r
1280 // set all the command parameters\r
1281 // Before write to all the following registers, BSY and DRQ must be 0.\r
1282 //\r
1283 if (DRQClear2 (\r
1284 AtapiBlkIoDev,\r
1285 &(AtapiBlkIoDev->IdeIoPortReg[Channel]),\r
1286 ATATIMEOUT\r
1436aea4
MK
1287 ) != EFI_SUCCESS)\r
1288 {\r
ea060cfa 1289 return EFI_DEVICE_ERROR;\r
1290 }\r
1291\r
1292 IoWrite8 (SectorCountReg, 0);\r
1293 IoWrite8 (SectorNumberReg, 0);\r
1294 IoWrite8 (CylinderLsbReg, 0);\r
1295 IoWrite8 (CylinderMsbReg, 0);\r
1296\r
1297 //\r
1298 // send command via Command Register\r
1299 //\r
1300 IoWrite8 (CommandReg, ATA_CMD_IDENTIFY_DEVICE);\r
1301\r
1302 //\r
1303 // According to PIO data in protocol, host can perform a series of reads to the\r
1304 // data register after each time device set DRQ ready;\r
1305 // The data size of "a series of read" is command specific.\r
1306 // For most ATA command, data size received from device will not exceed 1 sector,\r
1307 // hense the data size for "a series of read" can be the whole data size of one command request.\r
1308 // For ATA command such as Read Sector command, whole data size of one ATA command request is often larger\r
1309 // than 1 sector, according to the Read Sector command, the data size of "a series of read" is exactly\r
1310 // 1 sector.\r
1311 // Here for simplification reason, we specify the data size for "a series of read" to\r
1312 // 1 sector (256 words) if whole data size of one ATA commmand request is larger than 256 words.\r
1313 //\r
1314 Increment = 256;\r
1315 //\r
1316 // 256 words\r
1317 //\r
1318 WordCount = 0;\r
1319 //\r
1320 // WordCount is used to record bytes of currently transfered data\r
1321 //\r
1322 while (WordCount < ByteCount / 2) {\r
1323 //\r
1324 // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
1325 //\r
1326 Status = DRQReady2 (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), ATATIMEOUT);\r
1327 if (Status != EFI_SUCCESS) {\r
1328 return Status;\r
1329 }\r
1330\r
1331 if (CheckErrorStatus (AtapiBlkIoDev, StatusReg) != EFI_SUCCESS) {\r
ea060cfa 1332 return EFI_DEVICE_ERROR;\r
1333 }\r
1436aea4 1334\r
ea060cfa 1335 //\r
1336 // Get the byte count for one series of read\r
1337 //\r
1338 if ((WordCount + Increment) > ByteCount / 2) {\r
1339 Increment = ByteCount / 2 - WordCount;\r
1340 }\r
1436aea4 1341\r
ea060cfa 1342 //\r
1343 // perform a series of read without check DRQ ready\r
1344 //\r
1345 for (Index = 0; Index < Increment; Index++) {\r
1346 *Buffer16++ = IoRead16 (DataReg);\r
1347 }\r
1348\r
1349 WordCount += Increment;\r
ea060cfa 1350 }\r
1436aea4 1351\r
ea060cfa 1352 //\r
1353 // while\r
1354 //\r
1355 if (DRQClear (\r
1356 AtapiBlkIoDev,\r
1357 &(AtapiBlkIoDev->IdeIoPortReg[Channel]),\r
1358 ATATIMEOUT\r
1436aea4
MK
1359 ) != EFI_SUCCESS)\r
1360 {\r
ea060cfa 1361 return CheckErrorStatus (AtapiBlkIoDev, StatusReg);\r
1362 }\r
1363\r
1364 return EFI_SUCCESS;\r
ea060cfa 1365}\r
1366\r
1367/**\r
1368 Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
1369 to find out whether device is accessible.\r
1370\r
1371 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1372 @param[in] DevicePosition An integer to signify device position.\r
1373\r
1374 @retval EFI_SUCCESS TestUnit command executed successfully.\r
1375 @retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully.\r
1376\r
1377**/\r
1378EFI_STATUS\r
1379TestUnitReady (\r
1436aea4
MK
1380 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1381 IN UINTN DevicePosition\r
ea060cfa 1382 )\r
1383{\r
1384 ATAPI_PACKET_COMMAND Packet;\r
1385 EFI_STATUS Status;\r
1386\r
1387 //\r
1388 // fill command packet\r
1389 //\r
1390 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1391 Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;\r
1392\r
1393 //\r
1394 // send command packet\r
1395 //\r
1396 Status = AtapiPacketCommandIn (AtapiBlkIoDev, DevicePosition, &Packet, NULL, 0, ATAPITIMEOUT);\r
1397 return Status;\r
1398}\r
1399\r
1400/**\r
1401 Send out ATAPI commands conforms to the Packet Command with PIO Data In Protocol.\r
d1102dba 1402\r
ea060cfa 1403 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1404 @param[in] DevicePosition An integer to signify device position.\r
1405 @param[in] Packet A pointer to ATAPI command packet.\r
1406 @param[in] Buffer Buffer to contain requested transfer data from device.\r
1407 @param[in] ByteCount Requested transfer data length.\r
1408 @param[in] TimeoutInMilliSeconds Time out value, in unit of milliseconds.\r
1409\r
1410 @retval EFI_SUCCESS Command executed successfully.\r
1411 @retval EFI_DEVICE_ERROR Device cannot be executed command successfully.\r
1412\r
1413**/\r
1414EFI_STATUS\r
1415AtapiPacketCommandIn (\r
1416 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1417 IN UINTN DevicePosition,\r
1418 IN ATAPI_PACKET_COMMAND *Packet,\r
1419 IN UINT16 *Buffer,\r
1420 IN UINT32 ByteCount,\r
1421 IN UINTN TimeoutInMilliSeconds\r
1422 )\r
1423{\r
1424 UINT8 Channel;\r
1425 UINT8 Device;\r
1426 UINT16 StatusReg;\r
1427 UINT16 HeadReg;\r
1428 UINT16 CommandReg;\r
1429 UINT16 FeatureReg;\r
1430 UINT16 CylinderLsbReg;\r
1431 UINT16 CylinderMsbReg;\r
1432 UINT16 DeviceControlReg;\r
1433 UINT16 DataReg;\r
1434 EFI_STATUS Status;\r
1435 UINT32 Count;\r
1436 UINT16 *CommandIndex;\r
1437 UINT16 *PtrBuffer;\r
1438 UINT32 Index;\r
1439 UINT8 StatusValue;\r
1440 UINT32 WordCount;\r
1441\r
1442 //\r
1443 // required transfer data in word unit.\r
1444 //\r
1436aea4 1445 UINT32 RequiredWordCount;\r
ea060cfa 1446\r
1447 //\r
1448 // actual transfer data in word unit.\r
1449 //\r
1436aea4 1450 UINT32 ActualWordCount;\r
ea060cfa 1451\r
1436aea4
MK
1452 Channel = (UINT8)(DevicePosition / 2);\r
1453 Device = (UINT8)(DevicePosition % 2);\r
ea060cfa 1454\r
1455 ASSERT (Channel < MAX_IDE_CHANNELS);\r
1456\r
1436aea4
MK
1457 StatusReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Status;\r
1458 HeadReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;\r
1459 CommandReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;\r
1460 FeatureReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg1.Feature;\r
1461 CylinderLsbReg = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderLsb;\r
1462 CylinderMsbReg = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderMsb;\r
1463 DeviceControlReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Alt.DeviceControl;\r
1464 DataReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Data;\r
ea060cfa 1465\r
1466 //\r
1467 // Set all the command parameters by fill related registers.\r
1468 // Before write to all the following registers, BSY and DRQ must be 0.\r
1469 //\r
1470 if (DRQClear2 (\r
1471 AtapiBlkIoDev,\r
1472 &(AtapiBlkIoDev->IdeIoPortReg[Channel]),\r
1473 ATATIMEOUT\r
1436aea4
MK
1474 ) != EFI_SUCCESS)\r
1475 {\r
ea060cfa 1476 return EFI_DEVICE_ERROR;\r
1477 }\r
1436aea4 1478\r
ea060cfa 1479 //\r
1480 // Select device via Device/Head Register.\r
1481 // DEFAULT_CMD: 0xa0 (1010,0000)\r
1482 //\r
1436aea4 1483 IoWrite8 (HeadReg, (UINT8)((Device << 4) | ATA_DEFAULT_CMD));\r
ea060cfa 1484\r
1485 //\r
1486 // No OVL; No DMA\r
1487 //\r
1488 IoWrite8 (FeatureReg, 0x00);\r
1489\r
1490 //\r
1491 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device\r
1492 // determine how many data should be transfered.\r
1493 //\r
1436aea4
MK
1494 IoWrite8 (CylinderLsbReg, (UINT8)(ATAPI_MAX_BYTE_COUNT & 0x00ff));\r
1495 IoWrite8 (CylinderMsbReg, (UINT8)(ATAPI_MAX_BYTE_COUNT >> 8));\r
ea060cfa 1496\r
1497 //\r
1498 // DEFAULT_CTL:0x0a (0000,1010)\r
1499 // Disable interrupt\r
1500 //\r
1501 IoWrite8 (DeviceControlReg, ATA_DEFAULT_CTL);\r
1502\r
1503 //\r
1504 // Send Packet command to inform device\r
1505 // that the following data bytes are command packet.\r
1506 //\r
1507 IoWrite8 (CommandReg, ATA_CMD_PACKET);\r
1508\r
1509 Status = DRQReady (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), TimeoutInMilliSeconds);\r
1510 if (Status != EFI_SUCCESS) {\r
1511 return Status;\r
1512 }\r
1436aea4 1513\r
ea060cfa 1514 //\r
1515 // Send out command packet\r
1516 //\r
1517 CommandIndex = Packet->Data16;\r
1518 for (Count = 0; Count < 6; Count++, CommandIndex++) {\r
1519 IoWrite16 (DataReg, *CommandIndex);\r
1520 MicroSecondDelay (10);\r
1521 }\r
1522\r
1523 StatusValue = IoRead8 (StatusReg);\r
1524 if ((StatusValue & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
1525 //\r
1526 // Trouble! Something's wrong here... Wait some time and return. 3 second is\r
1527 // supposed to be long enough for a device reset latency or error recovery\r
1528 //\r
1529 MicroSecondDelay (3000000);\r
1530 return EFI_DEVICE_ERROR;\r
1531 }\r
1532\r
1436aea4 1533 if ((Buffer == NULL) || (ByteCount == 0)) {\r
ea060cfa 1534 return EFI_SUCCESS;\r
1535 }\r
1436aea4 1536\r
ea060cfa 1537 //\r
1538 // call PioReadWriteData() function to get\r
1539 // requested transfer data form device.\r
1540 //\r
1541 PtrBuffer = Buffer;\r
1542 RequiredWordCount = ByteCount / 2;\r
1543 //\r
1544 // ActuralWordCount means the word count of data really transfered.\r
1545 //\r
1546 ActualWordCount = 0;\r
1547\r
1436aea4 1548 Status = EFI_SUCCESS;\r
ea060cfa 1549 while ((Status == EFI_SUCCESS) && (ActualWordCount < RequiredWordCount)) {\r
1550 //\r
1551 // before each data transfer stream, the host should poll DRQ bit ready,\r
1552 // which informs device is ready to transfer data.\r
1553 //\r
1554 if (DRQReady2 (\r
1555 AtapiBlkIoDev,\r
1556 &(AtapiBlkIoDev->IdeIoPortReg[Channel]),\r
1557 TimeoutInMilliSeconds\r
1436aea4
MK
1558 ) != EFI_SUCCESS)\r
1559 {\r
ea060cfa 1560 return CheckErrorStatus (AtapiBlkIoDev, StatusReg);\r
1561 }\r
1436aea4 1562\r
ea060cfa 1563 //\r
1564 // read Status Register will clear interrupt\r
1565 //\r
1566 StatusValue = IoRead8 (StatusReg);\r
1567\r
1568 //\r
1569 // get current data transfer size from Cylinder Registers.\r
1570 //\r
1436aea4
MK
1571 WordCount = IoRead8 (CylinderMsbReg) << 8;\r
1572 WordCount = WordCount | IoRead8 (CylinderLsbReg);\r
1573 WordCount = WordCount & 0xffff;\r
ea060cfa 1574 WordCount /= 2;\r
1575\r
1576 //\r
1577 // perform a series data In/Out.\r
1578 //\r
1579 for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {\r
ea060cfa 1580 *PtrBuffer = IoRead16 (DataReg);\r
1581\r
1582 PtrBuffer++;\r
ea060cfa 1583 }\r
1584\r
1436aea4 1585 if ((((ATAPI_REQUEST_SENSE_CMD *)Packet)->opcode == ATA_CMD_REQUEST_SENSE) && (ActualWordCount >= 4)) {\r
ea060cfa 1586 RequiredWordCount = MIN (\r
1587 RequiredWordCount,\r
1436aea4 1588 (UINT32)(4 + (((ATAPI_REQUEST_SENSE_DATA *)Buffer)->addnl_sense_length / 2))\r
ea060cfa 1589 );\r
1590 }\r
ea060cfa 1591 }\r
1436aea4 1592\r
ea060cfa 1593 //\r
1594 // After data transfer is completed, normally, DRQ bit should clear.\r
1595 //\r
1596 Status = DRQClear2 (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), TimeoutInMilliSeconds);\r
1597 if (Status != EFI_SUCCESS) {\r
1598 return EFI_DEVICE_ERROR;\r
1599 }\r
1436aea4 1600\r
ea060cfa 1601 //\r
1602 // read status register to check whether error happens.\r
1603 //\r
1604 Status = CheckErrorStatus (AtapiBlkIoDev, StatusReg);\r
1605 return Status;\r
1606}\r
1607\r
1608/**\r
1609 Sends out ATAPI Inquiry Packet Command to the specified device.\r
1610 This command will return INQUIRY data of the device.\r
1611\r
1612 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1613 @param[in] DevicePosition An integer to signify device position.\r
1614 @param[out] MediaInfo The media information of the specified block media.\r
25c80c55 1615 @param[out] MediaInfo2 The media information 2 of the specified block media.\r
ea060cfa 1616\r
1617 @retval EFI_SUCCESS Command executed successfully.\r
1618 @retval EFI_DEVICE_ERROR Device cannot be executed command successfully.\r
1619 @retval EFI_UNSUPPORTED Unsupported device type.\r
1620\r
1621**/\r
1622EFI_STATUS\r
1623Inquiry (\r
1436aea4
MK
1624 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1625 IN UINTN DevicePosition,\r
1626 OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,\r
1627 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2\r
ea060cfa 1628 )\r
1629{\r
1436aea4
MK
1630 ATAPI_PACKET_COMMAND Packet;\r
1631 EFI_STATUS Status;\r
1632 ATAPI_INQUIRY_DATA Idata;\r
ea060cfa 1633\r
1634 //\r
1635 // prepare command packet for the ATAPI Inquiry Packet Command.\r
1636 //\r
1637 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
523f48e7 1638 ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA));\r
ea060cfa 1639\r
1436aea4
MK
1640 Packet.Inquiry.opcode = ATA_CMD_INQUIRY;\r
1641 Packet.Inquiry.page_code = 0;\r
1642 Packet.Inquiry.allocation_length = (UINT8)sizeof (ATAPI_INQUIRY_DATA);\r
ea060cfa 1643\r
1644 //\r
1645 // Send command packet and get requested Inquiry data.\r
1646 //\r
1647 Status = AtapiPacketCommandIn (\r
1436aea4
MK
1648 AtapiBlkIoDev,\r
1649 DevicePosition,\r
1650 &Packet,\r
1651 (UINT16 *)(&Idata),\r
1652 sizeof (ATAPI_INQUIRY_DATA),\r
1653 ATAPITIMEOUT\r
1654 // 50\r
1655 );\r
ea060cfa 1656\r
1657 if (Status != EFI_SUCCESS) {\r
1658 return EFI_DEVICE_ERROR;\r
1659 }\r
1436aea4 1660\r
ea060cfa 1661 //\r
1662 // Identify device type via INQUIRY data.\r
1663 //\r
1664 switch (Idata.peripheral_type & 0x1f) {\r
1436aea4
MK
1665 case 0x00:\r
1666 //\r
1667 // Magnetic Disk\r
1668 //\r
1669 MediaInfo->DeviceType = IdeLS120;\r
1670 MediaInfo->MediaPresent = FALSE;\r
1671 MediaInfo->LastBlock = 0;\r
1672 MediaInfo->BlockSize = 0x200;\r
1673 MediaInfo2->InterfaceType = MSG_ATAPI_DP;\r
1674 MediaInfo2->RemovableMedia = TRUE;\r
1675 MediaInfo2->MediaPresent = FALSE;\r
1676 MediaInfo2->ReadOnly = FALSE;\r
1677 MediaInfo2->BlockSize = 0x200;\r
1678 MediaInfo2->LastBlock = 0;\r
1679 break;\r
1680\r
1681 case 0x05:\r
1682 //\r
1683 // CD-ROM\r
1684 //\r
1685 MediaInfo->DeviceType = IdeCDROM;\r
1686 MediaInfo->MediaPresent = FALSE;\r
1687 MediaInfo->LastBlock = 0;\r
1688 MediaInfo->BlockSize = 0x800;\r
1689 MediaInfo2->InterfaceType = MSG_ATAPI_DP;\r
1690 MediaInfo2->RemovableMedia = TRUE;\r
1691 MediaInfo2->MediaPresent = FALSE;\r
1692 MediaInfo2->ReadOnly = TRUE;\r
1693 MediaInfo2->BlockSize = 0x200;\r
1694 MediaInfo2->LastBlock = 0;\r
1695 break;\r
1696\r
1697 default:\r
1698 return EFI_UNSUPPORTED;\r
ea060cfa 1699 }\r
1700\r
1701 return EFI_SUCCESS;\r
1702}\r
1703\r
d1102dba
LG
1704/**\r
1705 Used before read/write blocks from/to ATAPI device media.\r
ea060cfa 1706 Since ATAPI device media is removable, it is necessary to detect\r
1707 whether media is present and get current present media's information.\r
1708\r
1709 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1710 @param[in] DevicePosition An integer to signify device position.\r
25c80c55
FT
1711 @param[in, out] MediaInfo The media information of the specified block media.\r
1712 @param[in, out] MediaInfo2 The media information 2 of the specified block media.\r
ea060cfa 1713\r
1714 @retval EFI_SUCCESS Command executed successfully.\r
1715 @retval EFI_DEVICE_ERROR Some device errors happen.\r
1716 @retval EFI_OUT_OF_RESOURCES Can not allocate required resources.\r
1717\r
1718**/\r
1719EFI_STATUS\r
1720DetectMedia (\r
1436aea4
MK
1721 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1722 IN UINTN DevicePosition,\r
1723 IN OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,\r
1724 IN OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2\r
ea060cfa 1725 )\r
1726{\r
25c80c55
FT
1727 UINTN Index;\r
1728 UINTN RetryNum;\r
1729 UINTN MaxRetryNum;\r
1730 ATAPI_REQUEST_SENSE_DATA *SenseBuffers;\r
1731 BOOLEAN NeedReadCapacity;\r
1732 BOOLEAN NeedRetry;\r
1733 EFI_STATUS Status;\r
1734 UINT8 SenseCounts;\r
ea060cfa 1735\r
1736 SenseBuffers = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*SenseBuffers)));\r
1737 if (SenseBuffers == NULL) {\r
1738 return EFI_OUT_OF_RESOURCES;\r
1739 }\r
d1102dba 1740\r
ea060cfa 1741 //\r
1742 // Test Unit Ready command is used to detect whether device is accessible,\r
1743 // the device will produce corresponding Sense data.\r
1744 //\r
1745 for (Index = 0; Index < 2; Index++) {\r
ea060cfa 1746 Status = TestUnitReady (AtapiBlkIoDev, DevicePosition);\r
1747 if (Status != EFI_SUCCESS) {\r
1748 Status = ResetDevice (AtapiBlkIoDev, DevicePosition, FALSE);\r
1749\r
1750 if (Status != EFI_SUCCESS) {\r
1751 ResetDevice (AtapiBlkIoDev, DevicePosition, TRUE);\r
1752 }\r
ea060cfa 1753 } else {\r
1754 break;\r
1755 }\r
1756 }\r
1757\r
1436aea4
MK
1758 SenseCounts = MAX_SENSE_KEY_COUNT;\r
1759 Status = EFI_SUCCESS;\r
1760 NeedReadCapacity = TRUE;\r
ea060cfa 1761\r
1762 for (Index = 0; Index < 5; Index++) {\r
1763 SenseCounts = MAX_SENSE_KEY_COUNT;\r
1436aea4
MK
1764 Status = RequestSense (\r
1765 AtapiBlkIoDev,\r
1766 DevicePosition,\r
1767 SenseBuffers,\r
1768 &SenseCounts\r
1769 );\r
87000d77 1770 DEBUG ((DEBUG_INFO, "Atapi Request Sense Count is %d\n", SenseCounts));\r
ea060cfa 1771 if (IsDeviceStateUnclear (SenseBuffers, SenseCounts) || IsNoMedia (SenseBuffers, SenseCounts)) {\r
1772 //\r
1773 // We are not sure whether the media is present or not, try again\r
1774 //\r
1775 TestUnitReady (AtapiBlkIoDev, DevicePosition);\r
1776 } else {\r
1777 break;\r
1778 }\r
1779 }\r
1780\r
1781 if (Status == EFI_SUCCESS) {\r
ea060cfa 1782 if (IsNoMedia (SenseBuffers, SenseCounts)) {\r
1436aea4
MK
1783 NeedReadCapacity = FALSE;\r
1784 MediaInfo->MediaPresent = FALSE;\r
1785 MediaInfo->LastBlock = 0;\r
25c80c55
FT
1786 MediaInfo2->MediaPresent = FALSE;\r
1787 MediaInfo2->LastBlock = 0;\r
ea060cfa 1788 }\r
1789\r
1790 if (IsMediaError (SenseBuffers, SenseCounts)) {\r
1791 return EFI_DEVICE_ERROR;\r
1792 }\r
1793 }\r
1794\r
1795 if (NeedReadCapacity) {\r
1796 //\r
1797 // at most retry 5 times\r
1798 //\r
1799 MaxRetryNum = 5;\r
1800 RetryNum = 1;\r
1801 //\r
1802 // initial retry once\r
1803 //\r
1804 for (Index = 0; (Index < RetryNum) && (Index < MaxRetryNum); Index++) {\r
25c80c55 1805 Status = ReadCapacity (AtapiBlkIoDev, DevicePosition, MediaInfo, MediaInfo2);\r
ea060cfa 1806 MicroSecondDelay (200000);\r
1807 SenseCounts = MAX_SENSE_KEY_COUNT;\r
1808\r
1809 if (Status != EFI_SUCCESS) {\r
ea060cfa 1810 Status = RequestSense (AtapiBlkIoDev, DevicePosition, SenseBuffers, &SenseCounts);\r
1811 //\r
1812 // If Request Sense data failed, reset the device and retry.\r
1813 //\r
1814 if (Status != EFI_SUCCESS) {\r
ea060cfa 1815 Status = ResetDevice (AtapiBlkIoDev, DevicePosition, FALSE);\r
1816 //\r
1817 // if ATAPI soft reset fail,\r
1818 // use stronger reset mechanism -- ATA soft reset.\r
1819 //\r
1820 if (Status != EFI_SUCCESS) {\r
1821 ResetDevice (AtapiBlkIoDev, DevicePosition, TRUE);\r
1822 }\r
1823\r
1824 RetryNum++;\r
1825 //\r
1826 // retry once more\r
1827 //\r
1828 continue;\r
1829 }\r
1436aea4 1830\r
ea060cfa 1831 //\r
1832 // No Media\r
1833 //\r
1834 if (IsNoMedia (SenseBuffers, SenseCounts)) {\r
1436aea4
MK
1835 MediaInfo->MediaPresent = FALSE;\r
1836 MediaInfo->LastBlock = 0;\r
25c80c55
FT
1837 MediaInfo2->MediaPresent = FALSE;\r
1838 MediaInfo2->LastBlock = 0;\r
ea060cfa 1839 break;\r
1840 }\r
1841\r
1842 if (IsMediaError (SenseBuffers, SenseCounts)) {\r
1843 return EFI_DEVICE_ERROR;\r
1844 }\r
1845\r
1846 if (!IsDriveReady (SenseBuffers, SenseCounts, &NeedRetry)) {\r
1847 //\r
1848 // Drive not ready: if NeedRetry, then retry once more;\r
1849 // else return error\r
1850 //\r
1851 if (NeedRetry) {\r
1852 RetryNum++;\r
1853 continue;\r
1854 } else {\r
1855 return EFI_DEVICE_ERROR;\r
1856 }\r
1857 }\r
1436aea4 1858\r
ea060cfa 1859 //\r
1860 // if read capacity fail not for above reasons, retry once more\r
1861 //\r
1862 RetryNum++;\r
ea060cfa 1863 }\r
ea060cfa 1864 }\r
ea060cfa 1865 }\r
1866\r
1867 return EFI_SUCCESS;\r
1868}\r
1869\r
d1102dba 1870/**\r
ea060cfa 1871 Reset specified Atapi device.\r
1872\r
1873 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1874 @param[in] DevicePosition An integer to signify device position.\r
1875 @param[in] Extensive If TRUE, use ATA soft reset, otherwise use Atapi soft reset.\r
1876\r
1877 @retval EFI_SUCCESS Command executed successfully.\r
1878 @retval EFI_DEVICE_ERROR Some device errors happen.\r
1879\r
1880**/\r
1881EFI_STATUS\r
1882ResetDevice (\r
1883 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1884 IN UINTN DevicePosition,\r
1885 IN BOOLEAN Extensive\r
1886 )\r
1887{\r
1888 UINT8 DevControl;\r
1889 UINT8 Command;\r
1890 UINT8 DeviceSelect;\r
1891 UINT16 DeviceControlReg;\r
1892 UINT16 CommandReg;\r
1893 UINT16 HeadReg;\r
1894 UINT8 Channel;\r
1895 UINT8 Device;\r
1896\r
1436aea4
MK
1897 Channel = (UINT8)(DevicePosition / 2);\r
1898 Device = (UINT8)(DevicePosition % 2);\r
ea060cfa 1899\r
1900 ASSERT (Channel < MAX_IDE_CHANNELS);\r
1901\r
1436aea4
MK
1902 DeviceControlReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Alt.DeviceControl;\r
1903 CommandReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;\r
1904 HeadReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;\r
ea060cfa 1905\r
1906 if (Extensive) {\r
1436aea4 1907 DevControl = 0;\r
ea060cfa 1908 DevControl |= ATA_CTLREG_SRST;\r
1909 //\r
1910 // set SRST bit to initiate soft reset\r
1911 //\r
1912 DevControl |= BIT1;\r
1913 //\r
1914 // disable Interrupt\r
1915 //\r
1916 IoWrite8 (DeviceControlReg, DevControl);\r
1917\r
1918 //\r
1919 // Wait 10us\r
1920 //\r
1921 MicroSecondDelay (10);\r
1922\r
1923 //\r
1924 // Clear SRST bit\r
1925 //\r
1926 DevControl &= 0xfb;\r
1927 //\r
1928 // 0xfb:1111,1011\r
1929 //\r
1930 IoWrite8 (DeviceControlReg, DevControl);\r
1931\r
1932 //\r
1933 // slave device needs at most 31s to clear BSY\r
1934 //\r
1935 if (WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 31000) == EFI_TIMEOUT) {\r
1936 return EFI_DEVICE_ERROR;\r
1937 }\r
ea060cfa 1938 } else {\r
1939 //\r
1940 // for ATAPI device, no need to wait DRDY ready after device selecting.\r
1941 // bit7 and bit5 are both set to 1 for backward compatibility\r
1942 //\r
1436aea4 1943 DeviceSelect = (UINT8)(((BIT7 | BIT5) | (Device << 4)));\r
ea060cfa 1944 IoWrite8 (HeadReg, DeviceSelect);\r
1945\r
1946 Command = ATA_CMD_SOFT_RESET;\r
1947 IoWrite8 (CommandReg, Command);\r
1948\r
1949 //\r
1950 // BSY cleared is the only status return to the host by the device when reset is completed\r
1951 // slave device needs at most 31s to clear BSY\r
1952 //\r
1953 if (WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 31000) != EFI_SUCCESS) {\r
1954 return EFI_DEVICE_ERROR;\r
1955 }\r
1436aea4 1956\r
ea060cfa 1957 //\r
1958 // stall 5 seconds to make the device status stable\r
1959 //\r
1960 MicroSecondDelay (STALL_1_SECONDS * 5);\r
1961 }\r
1962\r
1963 return EFI_SUCCESS;\r
ea060cfa 1964}\r
1965\r
d1102dba 1966/**\r
ea060cfa 1967 Sends out ATAPI Request Sense Packet Command to the specified device.\r
1968\r
1969 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1970 @param[in] DevicePosition An integer to signify device position.\r
1971 @param[in] SenseBuffers Pointer to sense buffer.\r
1972 @param[in, out] SenseCounts Length of sense buffer.\r
1973\r
1974 @retval EFI_SUCCESS Command executed successfully.\r
1975 @retval EFI_DEVICE_ERROR Some device errors happen.\r
1976\r
1977**/\r
1978EFI_STATUS\r
1979RequestSense (\r
1436aea4
MK
1980 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1981 IN UINTN DevicePosition,\r
1982 IN ATAPI_REQUEST_SENSE_DATA *SenseBuffers,\r
1983 IN OUT UINT8 *SenseCounts\r
ea060cfa 1984 )\r
1985{\r
1436aea4
MK
1986 EFI_STATUS Status;\r
1987 ATAPI_REQUEST_SENSE_DATA *Sense;\r
1988 UINT16 *Ptr;\r
1989 BOOLEAN SenseReq;\r
1990 ATAPI_PACKET_COMMAND Packet;\r
ea060cfa 1991\r
1992 ZeroMem (SenseBuffers, sizeof (ATAPI_REQUEST_SENSE_DATA) * (*SenseCounts));\r
1993 //\r
1994 // fill command packet for Request Sense Packet Command\r
1995 //\r
1996 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1997 Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE;\r
1436aea4 1998 Packet.RequestSence.allocation_length = (UINT8)sizeof (ATAPI_REQUEST_SENSE_DATA);\r
ea060cfa 1999\r
1436aea4 2000 Ptr = (UINT16 *)SenseBuffers;\r
ea060cfa 2001 //\r
2002 // initialize pointer\r
2003 //\r
2004 *SenseCounts = 0;\r
2005 //\r
2006 // request sense data from device continiously until no sense data exists in the device.\r
2007 //\r
2008 for (SenseReq = TRUE; SenseReq;) {\r
1436aea4 2009 Sense = (ATAPI_REQUEST_SENSE_DATA *)Ptr;\r
ea060cfa 2010\r
2011 //\r
2012 // send out Request Sense Packet Command and get one Sense data form device\r
2013 //\r
2014 Status = AtapiPacketCommandIn (\r
1436aea4
MK
2015 AtapiBlkIoDev,\r
2016 DevicePosition,\r
2017 &Packet,\r
2018 Ptr,\r
2019 sizeof (ATAPI_REQUEST_SENSE_DATA),\r
2020 ATAPITIMEOUT\r
2021 );\r
ea060cfa 2022 //\r
2023 // failed to get Sense data\r
2024 //\r
2025 if (Status != EFI_SUCCESS) {\r
2026 if (*SenseCounts == 0) {\r
2027 return EFI_DEVICE_ERROR;\r
2028 } else {\r
2029 return EFI_SUCCESS;\r
2030 }\r
2031 }\r
2032\r
2033 (*SenseCounts)++;\r
2034\r
2035 if (*SenseCounts > MAX_SENSE_KEY_COUNT) {\r
2036 return EFI_SUCCESS;\r
2037 }\r
1436aea4 2038\r
ea060cfa 2039 //\r
2040 // We limit MAX sense data count to 20 in order to avoid dead loop. Some\r
2041 // incompatible ATAPI devices don't retrive NO_SENSE when there is no media.\r
2042 // In this case, dead loop occurs if we don't have a gatekeeper. 20 is\r
2043 // supposed to be large enough for any ATAPI device.\r
2044 //\r
2045 if ((Sense->sense_key != ATA_SK_NO_SENSE) && ((*SenseCounts) < 20)) {\r
ea060cfa 2046 Ptr += sizeof (ATAPI_REQUEST_SENSE_DATA) / 2;\r
2047 //\r
2048 // Ptr is word based pointer\r
2049 //\r
2050 } else {\r
2051 //\r
2052 // when no sense key, skip out the loop\r
2053 //\r
2054 SenseReq = FALSE;\r
2055 }\r
2056 }\r
2057\r
2058 return EFI_SUCCESS;\r
2059}\r
2060\r
d1102dba 2061/**\r
ea060cfa 2062 Sends out ATAPI Read Capacity Packet Command to the specified device.\r
2063 This command will return the information regarding the capacity of the\r
2064 media in the device.\r
2065\r
25c80c55
FT
2066 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
2067 @param[in] DevicePosition An integer to signify device position.\r
2068 @param[in, out] MediaInfo The media information of the specified block media.\r
2069 @param[in, out] MediaInfo2 The media information 2 of the specified block media.\r
ea060cfa 2070\r
2071 @retval EFI_SUCCESS Command executed successfully.\r
2072 @retval EFI_DEVICE_ERROR Some device errors happen.\r
2073\r
2074**/\r
2075EFI_STATUS\r
2076ReadCapacity (\r
1436aea4
MK
2077 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
2078 IN UINTN DevicePosition,\r
2079 IN OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,\r
2080 IN OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2\r
ea060cfa 2081 )\r
2082{\r
1436aea4
MK
2083 EFI_STATUS Status;\r
2084 ATAPI_PACKET_COMMAND Packet;\r
ea060cfa 2085\r
2086 //\r
2087 // used for capacity data returned from ATAPI device\r
2088 //\r
1436aea4
MK
2089 ATAPI_READ_CAPACITY_DATA Data;\r
2090 ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;\r
ea060cfa 2091\r
2092 ZeroMem (&Data, sizeof (Data));\r
2093 ZeroMem (&FormatData, sizeof (FormatData));\r
2094\r
2095 if (MediaInfo->DeviceType == IdeCDROM) {\r
ea060cfa 2096 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
2097 Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;\r
1436aea4
MK
2098 Status = AtapiPacketCommandIn (\r
2099 AtapiBlkIoDev,\r
2100 DevicePosition,\r
2101 &Packet,\r
2102 (UINT16 *)(&Data),\r
2103 sizeof (ATAPI_READ_CAPACITY_DATA),\r
2104 ATAPITIMEOUT\r
2105 );\r
ea060cfa 2106 } else {\r
2107 //\r
2108 // DeviceType == IdeLS120\r
2109 //\r
2110 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1436aea4
MK
2111 Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;\r
2112 Packet.ReadFormatCapacity.allocation_length_lo = 12;\r
2113 Status = AtapiPacketCommandIn (\r
2114 AtapiBlkIoDev,\r
2115 DevicePosition,\r
2116 &Packet,\r
2117 (UINT16 *)(&FormatData),\r
2118 sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),\r
2119 ATAPITIMEOUT*10\r
2120 );\r
ea060cfa 2121 }\r
2122\r
2123 if (Status == EFI_SUCCESS) {\r
ea060cfa 2124 if (MediaInfo->DeviceType == IdeCDROM) {\r
1436aea4 2125 MediaInfo->LastBlock = ((UINT32)Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;\r
ea060cfa 2126 MediaInfo->MediaPresent = TRUE;\r
2127 //\r
2128 // Because the user data portion in the sector of the Data CD supported\r
2129 // is always 800h\r
2130 //\r
1436aea4 2131 MediaInfo->BlockSize = 0x800;\r
25c80c55
FT
2132\r
2133 MediaInfo2->LastBlock = MediaInfo->LastBlock;\r
2134 MediaInfo2->MediaPresent = MediaInfo->MediaPresent;\r
2135 MediaInfo2->BlockSize = (UINT32)MediaInfo->BlockSize;\r
ea060cfa 2136 }\r
2137\r
2138 if (MediaInfo->DeviceType == IdeLS120) {\r
ea060cfa 2139 if (FormatData.DesCode == 3) {\r
1436aea4
MK
2140 MediaInfo->MediaPresent = FALSE;\r
2141 MediaInfo->LastBlock = 0;\r
25c80c55
FT
2142 MediaInfo2->MediaPresent = FALSE;\r
2143 MediaInfo2->LastBlock = 0;\r
ea060cfa 2144 } else {\r
1436aea4
MK
2145 MediaInfo->LastBlock = ((UINT32)FormatData.LastLba3 << 24) |\r
2146 (FormatData.LastLba2 << 16) |\r
2147 (FormatData.LastLba1 << 8) |\r
2148 FormatData.LastLba0;\r
ea060cfa 2149 MediaInfo->LastBlock--;\r
2150\r
2151 MediaInfo->MediaPresent = TRUE;\r
2152\r
1436aea4 2153 MediaInfo->BlockSize = 0x200;\r
ea060cfa 2154\r
25c80c55
FT
2155 MediaInfo2->LastBlock = MediaInfo->LastBlock;\r
2156 MediaInfo2->MediaPresent = MediaInfo->MediaPresent;\r
2157 MediaInfo2->BlockSize = (UINT32)MediaInfo->BlockSize;\r
ea060cfa 2158 }\r
2159 }\r
2160\r
2161 return EFI_SUCCESS;\r
ea060cfa 2162 } else {\r
2163 return EFI_DEVICE_ERROR;\r
2164 }\r
2165}\r
2166\r
d1102dba 2167/**\r
ea060cfa 2168 Perform read from disk in block unit.\r
2169\r
2170 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
2171 @param[in] DevicePosition An integer to signify device position.\r
2172 @param[in] Buffer Buffer to contain read data.\r
2173 @param[in] StartLba Starting LBA address.\r
2174 @param[in] NumberOfBlocks Number of blocks to read.\r
2175 @param[in] BlockSize Size of each block.\r
2176\r
2177 @retval EFI_SUCCESS Command executed successfully.\r
2178 @retval EFI_DEVICE_ERROR Some device errors happen.\r
2179\r
2180**/\r
2181EFI_STATUS\r
2182ReadSectors (\r
1436aea4
MK
2183 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
2184 IN UINTN DevicePosition,\r
2185 IN VOID *Buffer,\r
2186 IN EFI_PEI_LBA StartLba,\r
2187 IN UINTN NumberOfBlocks,\r
2188 IN UINTN BlockSize\r
ea060cfa 2189 )\r
2190{\r
ea060cfa 2191 ATAPI_PACKET_COMMAND Packet;\r
2192 ATAPI_READ10_CMD *Read10Packet;\r
2193 EFI_STATUS Status;\r
2194 UINTN BlocksRemaining;\r
2195 UINT32 Lba32;\r
2196 UINT32 ByteCount;\r
2197 UINT16 SectorCount;\r
2198 VOID *PtrBuffer;\r
2199 UINT16 MaxBlock;\r
2200\r
2201 //\r
2202 // fill command packet for Read(10) command\r
2203 //\r
2204 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1436aea4
MK
2205 Read10Packet = &Packet.Read10;\r
2206 Lba32 = (UINT32)StartLba;\r
2207 PtrBuffer = Buffer;\r
ea060cfa 2208\r
2209 //\r
2210 // limit the data bytes that can be transfered by one Read(10) Command\r
2211 //\r
1436aea4 2212 MaxBlock = (UINT16)(0x10000 / BlockSize);\r
ea060cfa 2213 //\r
2214 // (64k bytes)\r
2215 //\r
2216 BlocksRemaining = NumberOfBlocks;\r
2217\r
1436aea4 2218 Status = EFI_SUCCESS;\r
ea060cfa 2219 while (BlocksRemaining > 0) {\r
ea060cfa 2220 if (BlocksRemaining <= MaxBlock) {\r
1436aea4 2221 SectorCount = (UINT16)BlocksRemaining;\r
ea060cfa 2222 } else {\r
2223 SectorCount = MaxBlock;\r
2224 }\r
1436aea4 2225\r
ea060cfa 2226 //\r
2227 // fill the Packet data sturcture\r
2228 //\r
2229 Read10Packet->opcode = ATA_CMD_READ_10;\r
2230\r
2231 //\r
2232 // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
2233 // Lba0 is MSB, Lba3 is LSB\r
2234 //\r
1436aea4
MK
2235 Read10Packet->Lba3 = (UINT8)(Lba32 & 0xff);\r
2236 Read10Packet->Lba2 = (UINT8)(Lba32 >> 8);\r
2237 Read10Packet->Lba1 = (UINT8)(Lba32 >> 16);\r
2238 Read10Packet->Lba0 = (UINT8)(Lba32 >> 24);\r
ea060cfa 2239\r
2240 //\r
2241 // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
2242 // TranLen0 is MSB, TranLen is LSB\r
2243 //\r
1436aea4
MK
2244 Read10Packet->TranLen1 = (UINT8)(SectorCount & 0xff);\r
2245 Read10Packet->TranLen0 = (UINT8)(SectorCount >> 8);\r
ea060cfa 2246\r
1436aea4 2247 ByteCount = (UINT32)(SectorCount * BlockSize);\r
ea060cfa 2248\r
2249 Status = AtapiPacketCommandIn (\r
1436aea4
MK
2250 AtapiBlkIoDev,\r
2251 DevicePosition,\r
2252 &Packet,\r
2253 (UINT16 *)PtrBuffer,\r
2254 ByteCount,\r
2255 ATAPILONGTIMEOUT\r
2256 );\r
ea060cfa 2257 if (Status != EFI_SUCCESS) {\r
2258 return Status;\r
2259 }\r
2260\r
1436aea4
MK
2261 Lba32 += SectorCount;\r
2262 PtrBuffer = (UINT8 *)PtrBuffer + SectorCount * BlockSize;\r
ea060cfa 2263 BlocksRemaining -= SectorCount;\r
2264 }\r
2265\r
2266 return Status;\r
2267}\r
2268\r
d1102dba 2269/**\r
ea060cfa 2270 Check if there is media according to sense data.\r
2271\r
2272 @param[in] SenseData Pointer to sense data.\r
2273 @param[in] SenseCounts Count of sense data.\r
2274\r
2275 @retval TRUE No media\r
2276 @retval FALSE Media exists\r
2277\r
2278**/\r
2279BOOLEAN\r
2280IsNoMedia (\r
2281 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
2282 IN UINTN SenseCounts\r
2283 )\r
2284{\r
2285 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
25c80c55
FT
2286 UINTN Index;\r
2287 BOOLEAN IsNoMedia;\r
ea060cfa 2288\r
2289 IsNoMedia = FALSE;\r
2290\r
1436aea4 2291 SensePtr = SenseData;\r
ea060cfa 2292\r
2293 for (Index = 0; Index < SenseCounts; Index++) {\r
ea060cfa 2294 if ((SensePtr->sense_key == ATA_SK_NOT_READY) && (SensePtr->addnl_sense_code == ATA_ASC_NO_MEDIA)) {\r
2295 IsNoMedia = TRUE;\r
2296 }\r
2297\r
2298 SensePtr++;\r
2299 }\r
2300\r
2301 return IsNoMedia;\r
2302}\r
2303\r
d1102dba 2304/**\r
ea060cfa 2305 Check if device state is unclear according to sense data.\r
2306\r
2307 @param[in] SenseData Pointer to sense data.\r
2308 @param[in] SenseCounts Count of sense data.\r
2309\r
2310 @retval TRUE Device state is unclear\r
d1102dba 2311 @retval FALSE Device state is clear\r
ea060cfa 2312\r
2313**/\r
2314BOOLEAN\r
2315IsDeviceStateUnclear (\r
1436aea4
MK
2316 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
2317 IN UINTN SenseCounts\r
ea060cfa 2318 )\r
2319{\r
2320 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
25c80c55
FT
2321 UINTN Index;\r
2322 BOOLEAN Unclear;\r
ea060cfa 2323\r
1436aea4 2324 Unclear = FALSE;\r
ea060cfa 2325\r
1436aea4 2326 SensePtr = SenseData;\r
ea060cfa 2327\r
2328 for (Index = 0; Index < SenseCounts; Index++) {\r
ea060cfa 2329 if (SensePtr->sense_key == 0x06) {\r
2330 //\r
2331 // Sense key is 0x06 means the device is just be reset or media just\r
2332 // changed. The current state of the device is unclear.\r
2333 //\r
2334 Unclear = TRUE;\r
2335 break;\r
2336 }\r
2337\r
2338 SensePtr++;\r
2339 }\r
2340\r
2341 return Unclear;\r
2342}\r
2343\r
d1102dba 2344/**\r
ea060cfa 2345 Check if there is media error according to sense data.\r
2346\r
2347 @param[in] SenseData Pointer to sense data.\r
2348 @param[in] SenseCounts Count of sense data.\r
2349\r
2350 @retval TRUE Media error\r
2351 @retval FALSE No media error\r
2352\r
2353**/\r
2354BOOLEAN\r
2355IsMediaError (\r
2356 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
2357 IN UINTN SenseCounts\r
2358 )\r
2359{\r
2360 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
25c80c55
FT
2361 UINTN Index;\r
2362 BOOLEAN IsError;\r
ea060cfa 2363\r
1436aea4 2364 IsError = FALSE;\r
ea060cfa 2365\r
1436aea4 2366 SensePtr = SenseData;\r
ea060cfa 2367\r
2368 for (Index = 0; Index < SenseCounts; Index++) {\r
ea060cfa 2369 switch (SensePtr->sense_key) {\r
1436aea4
MK
2370 case ATA_SK_MEDIUM_ERROR:\r
2371 switch (SensePtr->addnl_sense_code) {\r
2372 case ATA_ASC_MEDIA_ERR1:\r
2373 //\r
2374 // fall through\r
2375 //\r
2376 case ATA_ASC_MEDIA_ERR2:\r
2377 //\r
2378 // fall through\r
2379 //\r
2380 case ATA_ASC_MEDIA_ERR3:\r
2381 //\r
2382 // fall through\r
2383 //\r
2384 case ATA_ASC_MEDIA_ERR4:\r
2385 IsError = TRUE;\r
2386 break;\r
ea060cfa 2387\r
1436aea4
MK
2388 default:\r
2389 break;\r
2390 }\r
ea060cfa 2391\r
ea060cfa 2392 break;\r
ea060cfa 2393\r
1436aea4
MK
2394 case ATA_SK_NOT_READY:\r
2395 switch (SensePtr->addnl_sense_code) {\r
2396 case ATA_ASC_MEDIA_UPSIDE_DOWN:\r
2397 IsError = TRUE;\r
2398 break;\r
2399\r
2400 default:\r
2401 break;\r
2402 }\r
ea060cfa 2403\r
ea060cfa 2404 break;\r
2405\r
2406 default:\r
2407 break;\r
ea060cfa 2408 }\r
2409\r
2410 SensePtr++;\r
2411 }\r
2412\r
2413 return IsError;\r
2414}\r
2415\r
d1102dba 2416/**\r
ea060cfa 2417 Check if drive is ready according to sense data.\r
2418\r
2419 @param[in] SenseData Pointer to sense data.\r
2420 @param[in] SenseCounts Count of sense data.\r
2421 @param[out] NeedRetry Indicate if retry is needed.\r
2422\r
2423 @retval TRUE Drive ready\r
2424 @retval FALSE Drive not ready\r
2425\r
2426**/\r
2427BOOLEAN\r
2428IsDriveReady (\r
1436aea4
MK
2429 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
2430 IN UINTN SenseCounts,\r
2431 OUT BOOLEAN *NeedRetry\r
ea060cfa 2432 )\r
2433{\r
2434 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
25c80c55
FT
2435 UINTN Index;\r
2436 BOOLEAN IsReady;\r
ea060cfa 2437\r
1436aea4
MK
2438 IsReady = TRUE;\r
2439 *NeedRetry = FALSE;\r
ea060cfa 2440\r
1436aea4 2441 SensePtr = SenseData;\r
ea060cfa 2442\r
2443 for (Index = 0; Index < SenseCounts; Index++) {\r
ea060cfa 2444 switch (SensePtr->sense_key) {\r
1436aea4
MK
2445 case ATA_SK_NOT_READY:\r
2446 switch (SensePtr->addnl_sense_code) {\r
2447 case ATA_ASC_NOT_READY:\r
2448 switch (SensePtr->addnl_sense_code_qualifier) {\r
2449 case ATA_ASCQ_IN_PROGRESS:\r
2450 IsReady = FALSE;\r
2451 *NeedRetry = TRUE;\r
2452 break;\r
2453\r
2454 default:\r
2455 IsReady = FALSE;\r
2456 *NeedRetry = FALSE;\r
2457 break;\r
2458 }\r
2459\r
2460 break;\r
2461\r
2462 default:\r
2463 break;\r
ea060cfa 2464 }\r
1436aea4 2465\r
ea060cfa 2466 break;\r
2467\r
2468 default:\r
2469 break;\r
ea060cfa 2470 }\r
2471\r
2472 SensePtr++;\r
2473 }\r
2474\r
2475 return IsReady;\r
2476}\r