]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - 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
1/** @file\r
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
6for Atapi CD ROM device.\r
7\r
8Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9\r
10SPDX-License-Identifier: BSD-2-Clause-Patent\r
11\r
12**/\r
13\r
14#include "AtapiPeim.h"\r
15\r
16/**\r
17 Initializes the Atapi Block Io PPI.\r
18\r
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
29 IN EFI_PEI_FILE_HANDLE FileHandle,\r
30 IN CONST EFI_PEI_SERVICES **PeiServices\r
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
43 &gPeiAtaControllerPpiGuid,\r
44 0,\r
45 NULL,\r
46 (VOID **)&AtaControllerPpi\r
47 );\r
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
63 AtapiBlkIoDev->AtapiBlkIo.GetNumberOfBlockDevices = AtapiGetNumberOfBlockDevices;\r
64 AtapiBlkIoDev->AtapiBlkIo.GetBlockDeviceMediaInfo = AtapiGetBlockDeviceMediaInfo;\r
65 AtapiBlkIoDev->AtapiBlkIo.ReadBlocks = AtapiReadBlocks;\r
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
70\r
71 AtapiBlkIoDev->PpiDescriptor.Flags = EFI_PEI_PPI_DESCRIPTOR_PPI;\r
72 AtapiBlkIoDev->PpiDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid;\r
73 AtapiBlkIoDev->PpiDescriptor.Ppi = &AtapiBlkIoDev->AtapiBlkIo;\r
74\r
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
78\r
79 DEBUG ((DEBUG_INFO, "Atatpi Device Count is %d\n", AtapiBlkIoDev->DeviceCount));\r
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
93 This function is used for getting the count of block I/O devices that one\r
94 specific block driver detects. To the PEI ATAPI driver, it returns the number\r
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
101 to every PEIM.\r
102 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI\r
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
112 IN EFI_PEI_SERVICES **PeiServices,\r
113 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
114 OUT UINTN *NumberBlockDevices\r
115 )\r
116{\r
117 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
118\r
119 AtapiBlkIoDev = NULL;\r
120\r
121 AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS (This);\r
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
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
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
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
142 device index that was assigned during the enumeration\r
143 process. This index is a number from one to\r
144 NumberBlockDevices.\r
145 @param[out] MediaInfo The media information of the specified block media.\r
146 The caller is responsible for the ownership of this\r
147 data structure.\r
148\r
149 @retval EFI_SUCCESS Media information about the specified block device\r
150 was obtained successfully.\r
151 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
152 error.\r
153 @retval Others Other failure occurs.\r
154\r
155**/\r
156EFI_STATUS\r
157EFIAPI\r
158AtapiGetBlockDeviceMediaInfo (\r
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
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
172 if ((This == NULL) || (MediaInfo == NULL)) {\r
173 return EFI_INVALID_PARAMETER;\r
174 }\r
175\r
176 AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS (This);\r
177\r
178 DeviceCount = AtapiBlkIoDev->DeviceCount;\r
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
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
197\r
198 Status = DetectMedia (\r
199 AtapiBlkIoDev,\r
200 AtapiBlkIoDev->DeviceInfo[Index].DevicePosition,\r
201 &AtapiBlkIoDev->DeviceInfo[Index].MediaInfo,\r
202 &AtapiBlkIoDev->DeviceInfo[Index].MediaInfo2\r
203 );\r
204 if (Status != EFI_SUCCESS) {\r
205 return EFI_DEVICE_ERROR;\r
206 }\r
207\r
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
213\r
214 //\r
215 // Get media info from AtapiBlkIoDev\r
216 //\r
217 CopyMem (MediaInfo, &AtapiBlkIoDev->DeviceInfo[Index].MediaInfo, sizeof (EFI_PEI_BLOCK_IO_MEDIA));\r
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
225 The function reads the requested number of blocks from the device. All the\r
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
229 @param[in] PeiServices General-purpose services that are available to\r
230 every PEIM.\r
231 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
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
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
243 The caller is responsible for the ownership of the\r
244 buffer.\r
245\r
246 @retval EFI_SUCCESS The data was read correctly from the device.\r
247 @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
248 to perform the read operation.\r
249 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
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
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
265 )\r
266{\r
267 EFI_PEI_BLOCK_IO_MEDIA MediaInfo;\r
268 EFI_STATUS Status;\r
269 UINTN NumberOfBlocks;\r
270 UINTN BlockSize;\r
271 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
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
290 PeiServices,\r
291 This,\r
292 DeviceIndex,\r
293 &MediaInfo\r
294 );\r
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
311 if ((StartLBA + NumberOfBlocks - 1) > AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].MediaInfo2.LastBlock) {\r
312 return EFI_INVALID_PARAMETER;\r
313 }\r
314\r
315 Status = ReadSectors (\r
316 AtapiBlkIoDev,\r
317 AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].DevicePosition,\r
318 Buffer,\r
319 StartLBA,\r
320 NumberOfBlocks,\r
321 BlockSize\r
322 );\r
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
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
352 IN EFI_PEI_SERVICES **PeiServices,\r
353 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
354 OUT UINTN *NumberBlockDevices\r
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
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
406 )\r
407{\r
408 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
409 EFI_STATUS Status;\r
410 EFI_PEI_BLOCK_IO_MEDIA Media;\r
411\r
412 AtapiBlkIoDev = NULL;\r
413\r
414 if ((This == NULL) || (MediaInfo == NULL)) {\r
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
429\r
430 //\r
431 // Get media info from AtapiBlkIoDev\r
432 //\r
433 CopyMem (MediaInfo, &AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].MediaInfo2, sizeof (EFI_PEI_BLOCK_IO2_MEDIA));\r
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
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
481 )\r
482{\r
483 EFI_STATUS Status;\r
484 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
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
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
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
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
542 (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),\r
543 AtapiBlkIoDev->AtaControllerPpi,\r
544 PEI_ICH_IDE_PRIMARY | PEI_ICH_IDE_SECONDARY\r
545 );\r
546\r
547 //\r
548 // Allow SATA Devices to spin-up. This is needed if\r
549 // SEC and PEI phase is too short, for example Release Build.\r
550 //\r
551 DEBUG ((DEBUG_INFO, "Delay for %d seconds for SATA devices to spin-up\n", PcdGet16 (PcdSataSpinUpDelayInSecForRecoveryPath)));\r
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
558 (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),\r
559 AtapiBlkIoDev->AtaControllerPpi,\r
560 IdeRegsBaseAddr\r
561 );\r
562\r
563 //\r
564 // Using Command and Control Regs Base Address to fill other registers.\r
565 //\r
566 for (Index1 = 0; Index1 < IdeEnabledNumber; Index1++) {\r
567 CommandBlockBaseAddr = IdeRegsBaseAddr[Index1].CommandBlockBaseAddr;\r
568 AtapiBlkIoDev->IdeIoPortReg[Index1].Data = CommandBlockBaseAddr;\r
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
578 AtapiBlkIoDev->IdeIoPortReg[Index1].Alt.DeviceControl = ControlBlockBaseAddr;\r
579 AtapiBlkIoDev->IdeIoPortReg[Index1].DriveAddress = (UINT16)(ControlBlockBaseAddr + 0x1);\r
580\r
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
588 DevicePosition = Index1 * 2 + Index2;\r
589\r
590 if (DiscoverAtapiDevice (AtapiBlkIoDev, DevicePosition, &MediaInfo, &MediaInfo2)) {\r
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
598 Status = DetectMedia (AtapiBlkIoDev, DevicePosition, &MediaInfo, &MediaInfo2);\r
599 CopyMem (&(AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo), &MediaInfo, sizeof (MediaInfo));\r
600 CopyMem (&(AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2), &MediaInfo2, sizeof (MediaInfo2));\r
601\r
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
606\r
607 if (EFI_ERROR (Status)) {\r
608 AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo.MediaPresent = FALSE;\r
609 AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo.LastBlock = 0;\r
610 AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2.MediaPresent = FALSE;\r
611 AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2.LastBlock = 0;\r
612 }\r
613\r
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
624\r
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
628 @param[out] MediaInfo2 The media information 2 of the specified block media.\r
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
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
640 )\r
641{\r
642 EFI_STATUS Status;\r
643\r
644 if (!DetectIDEController (AtapiBlkIoDev, DevicePosition)) {\r
645 return FALSE;\r
646 }\r
647\r
648 //\r
649 // test if it is an ATAPI device (only supported device)\r
650 //\r
651 if (ATAPIIdentify (AtapiBlkIoDev, DevicePosition) == EFI_SUCCESS) {\r
652 Status = Inquiry (AtapiBlkIoDev, DevicePosition, MediaInfo, MediaInfo2);\r
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
663\r
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
676 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
677 IN UINTN DevicePosition,\r
678 IN UINT8 AtaCommand\r
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
693 Channel = (UINT8)(DevicePosition / 2);\r
694 Device = (UINT8)(DevicePosition % 2);\r
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
707 IoWrite8 (HeadRegister, (UINT8)((Device << 4) | 0xe0));\r
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
718 IoWrite8 (HeadRegister, (UINT8)((Device << 4) | 0xe0));\r
719\r
720 Status = DRDYReady (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 100);\r
721\r
722 //\r
723 // select device\r
724 //\r
725 IoWrite8 (HeadRegister, (UINT8)((Device << 4) | 0xe0));\r
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
769 IoWrite8 (HeadRegister, (UINT8)((Device << 4) | 0xe0));\r
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
784\r
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
797\r
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
807 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
808 IN UINTN DevicePosition\r
809 )\r
810{\r
811 UINT8 Channel;\r
812 EFI_STATUS Status;\r
813 UINT8 AtaCommand;\r
814\r
815 Channel = (UINT8)(DevicePosition / 2);\r
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
825\r
826 //\r
827 // Send 'check power' command for IDE device\r
828 //\r
829 AtaCommand = 0xE5;\r
830 Status = CheckPowerMode (AtapiBlkIoDev, DevicePosition, AtaCommand);\r
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
840\r
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
860 StatusValue = 0;\r
861\r
862 StatusRegister = IdeIoRegisters->Reg.Status;\r
863\r
864 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
865 do {\r
866 StatusValue = IoRead8 (StatusRegister);\r
867 if ((StatusValue & ATA_STSREG_BSY) == 0x00) {\r
868 break;\r
869 }\r
870\r
871 MicroSecondDelay (250);\r
872\r
873 Delay--;\r
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
885\r
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
906 StatusValue = 0;\r
907\r
908 StatusRegister = IdeIoRegisters->Reg.Status;\r
909\r
910 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
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
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
925 }\r
926\r
927 MicroSecondDelay (250);\r
928\r
929 Delay--;\r
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
941\r
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
962 StatusValue = 0;\r
963\r
964 StatusRegister = IdeIoRegisters->Reg.Status;\r
965\r
966 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
967 do {\r
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
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
982 }\r
983\r
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
998\r
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
1019 AltStatusValue = 0;\r
1020\r
1021 AltStatusRegister = IdeIoRegisters->Alt.AltStatus;\r
1022\r
1023 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
1024 do {\r
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
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
1039 }\r
1040\r
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
1077 StatusValue = 0;\r
1078 ErrValue = 0;\r
1079\r
1080 StatusRegister = IdeIoRegisters->Reg.Status;\r
1081\r
1082 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
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
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
1102\r
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
1139 AltStatusValue = 0;\r
1140\r
1141 AltStatusRegister = IdeIoRegisters->Alt.AltStatus;\r
1142\r
1143 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
1144 do {\r
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
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
1160\r
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
1185 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1186 IN UINT16 StatusReg\r
1187 )\r
1188{\r
1189 UINT8 StatusValue;\r
1190\r
1191 StatusValue = IoRead8 (StatusReg);\r
1192\r
1193 if ((StatusValue & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {\r
1194 return EFI_SUCCESS;\r
1195 }\r
1196\r
1197 return EFI_DEVICE_ERROR;\r
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
1212 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1213 IN UINTN DevicePosition\r
1214 )\r
1215{\r
1216 ATAPI_IDENTIFY_DATA AtapiIdentifyData;\r
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
1228 UINT32 WordCount;\r
1229 UINT32 Increment;\r
1230 UINT32 Index;\r
1231 UINT32 ByteCount;\r
1232 UINT16 *Buffer16;\r
1233\r
1234 EFI_STATUS Status;\r
1235\r
1236 ByteCount = sizeof (AtapiIdentifyData);\r
1237 Buffer16 = (UINT16 *)&AtapiIdentifyData;\r
1238\r
1239 Channel = (UINT8)(DevicePosition / 2);\r
1240 Device = (UINT8)(DevicePosition % 2);\r
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
1260 ) != EFI_SUCCESS)\r
1261 {\r
1262 return EFI_DEVICE_ERROR;\r
1263 }\r
1264\r
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
1272\r
1273 //\r
1274 // e0:1110,0000-- bit7 and bit5 are reserved bits.\r
1275 // bit6 set means LBA mode\r
1276 //\r
1277 IoWrite8 (HeadReg, (UINT8)((Device << 4) | 0xe0));\r
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
1287 ) != EFI_SUCCESS)\r
1288 {\r
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
1332 return EFI_DEVICE_ERROR;\r
1333 }\r
1334\r
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
1341\r
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
1350 }\r
1351\r
1352 //\r
1353 // while\r
1354 //\r
1355 if (DRQClear (\r
1356 AtapiBlkIoDev,\r
1357 &(AtapiBlkIoDev->IdeIoPortReg[Channel]),\r
1358 ATATIMEOUT\r
1359 ) != EFI_SUCCESS)\r
1360 {\r
1361 return CheckErrorStatus (AtapiBlkIoDev, StatusReg);\r
1362 }\r
1363\r
1364 return EFI_SUCCESS;\r
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
1380 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1381 IN UINTN DevicePosition\r
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
1402\r
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
1445 UINT32 RequiredWordCount;\r
1446\r
1447 //\r
1448 // actual transfer data in word unit.\r
1449 //\r
1450 UINT32 ActualWordCount;\r
1451\r
1452 Channel = (UINT8)(DevicePosition / 2);\r
1453 Device = (UINT8)(DevicePosition % 2);\r
1454\r
1455 ASSERT (Channel < MAX_IDE_CHANNELS);\r
1456\r
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
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
1474 ) != EFI_SUCCESS)\r
1475 {\r
1476 return EFI_DEVICE_ERROR;\r
1477 }\r
1478\r
1479 //\r
1480 // Select device via Device/Head Register.\r
1481 // DEFAULT_CMD: 0xa0 (1010,0000)\r
1482 //\r
1483 IoWrite8 (HeadReg, (UINT8)((Device << 4) | ATA_DEFAULT_CMD));\r
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
1494 IoWrite8 (CylinderLsbReg, (UINT8)(ATAPI_MAX_BYTE_COUNT & 0x00ff));\r
1495 IoWrite8 (CylinderMsbReg, (UINT8)(ATAPI_MAX_BYTE_COUNT >> 8));\r
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
1513\r
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
1533 if ((Buffer == NULL) || (ByteCount == 0)) {\r
1534 return EFI_SUCCESS;\r
1535 }\r
1536\r
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
1548 Status = EFI_SUCCESS;\r
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
1558 ) != EFI_SUCCESS)\r
1559 {\r
1560 return CheckErrorStatus (AtapiBlkIoDev, StatusReg);\r
1561 }\r
1562\r
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
1571 WordCount = IoRead8 (CylinderMsbReg) << 8;\r
1572 WordCount = WordCount | IoRead8 (CylinderLsbReg);\r
1573 WordCount = WordCount & 0xffff;\r
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
1580 *PtrBuffer = IoRead16 (DataReg);\r
1581\r
1582 PtrBuffer++;\r
1583 }\r
1584\r
1585 if ((((ATAPI_REQUEST_SENSE_CMD *)Packet)->opcode == ATA_CMD_REQUEST_SENSE) && (ActualWordCount >= 4)) {\r
1586 RequiredWordCount = MIN (\r
1587 RequiredWordCount,\r
1588 (UINT32)(4 + (((ATAPI_REQUEST_SENSE_DATA *)Buffer)->addnl_sense_length / 2))\r
1589 );\r
1590 }\r
1591 }\r
1592\r
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
1600\r
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
1615 @param[out] MediaInfo2 The media information 2 of the specified block media.\r
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
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
1628 )\r
1629{\r
1630 ATAPI_PACKET_COMMAND Packet;\r
1631 EFI_STATUS Status;\r
1632 ATAPI_INQUIRY_DATA Idata;\r
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
1638 ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA));\r
1639\r
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
1643\r
1644 //\r
1645 // Send command packet and get requested Inquiry data.\r
1646 //\r
1647 Status = AtapiPacketCommandIn (\r
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
1656\r
1657 if (Status != EFI_SUCCESS) {\r
1658 return EFI_DEVICE_ERROR;\r
1659 }\r
1660\r
1661 //\r
1662 // Identify device type via INQUIRY data.\r
1663 //\r
1664 switch (Idata.peripheral_type & 0x1f) {\r
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
1699 }\r
1700\r
1701 return EFI_SUCCESS;\r
1702}\r
1703\r
1704/**\r
1705 Used before read/write blocks from/to ATAPI device media.\r
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
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
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
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
1725 )\r
1726{\r
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
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
1740\r
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
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
1753 } else {\r
1754 break;\r
1755 }\r
1756 }\r
1757\r
1758 SenseCounts = MAX_SENSE_KEY_COUNT;\r
1759 Status = EFI_SUCCESS;\r
1760 NeedReadCapacity = TRUE;\r
1761\r
1762 for (Index = 0; Index < 5; Index++) {\r
1763 SenseCounts = MAX_SENSE_KEY_COUNT;\r
1764 Status = RequestSense (\r
1765 AtapiBlkIoDev,\r
1766 DevicePosition,\r
1767 SenseBuffers,\r
1768 &SenseCounts\r
1769 );\r
1770 DEBUG ((DEBUG_INFO, "Atapi Request Sense Count is %d\n", SenseCounts));\r
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
1782 if (IsNoMedia (SenseBuffers, SenseCounts)) {\r
1783 NeedReadCapacity = FALSE;\r
1784 MediaInfo->MediaPresent = FALSE;\r
1785 MediaInfo->LastBlock = 0;\r
1786 MediaInfo2->MediaPresent = FALSE;\r
1787 MediaInfo2->LastBlock = 0;\r
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
1805 Status = ReadCapacity (AtapiBlkIoDev, DevicePosition, MediaInfo, MediaInfo2);\r
1806 MicroSecondDelay (200000);\r
1807 SenseCounts = MAX_SENSE_KEY_COUNT;\r
1808\r
1809 if (Status != EFI_SUCCESS) {\r
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
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
1830\r
1831 //\r
1832 // No Media\r
1833 //\r
1834 if (IsNoMedia (SenseBuffers, SenseCounts)) {\r
1835 MediaInfo->MediaPresent = FALSE;\r
1836 MediaInfo->LastBlock = 0;\r
1837 MediaInfo2->MediaPresent = FALSE;\r
1838 MediaInfo2->LastBlock = 0;\r
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
1858\r
1859 //\r
1860 // if read capacity fail not for above reasons, retry once more\r
1861 //\r
1862 RetryNum++;\r
1863 }\r
1864 }\r
1865 }\r
1866\r
1867 return EFI_SUCCESS;\r
1868}\r
1869\r
1870/**\r
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
1897 Channel = (UINT8)(DevicePosition / 2);\r
1898 Device = (UINT8)(DevicePosition % 2);\r
1899\r
1900 ASSERT (Channel < MAX_IDE_CHANNELS);\r
1901\r
1902 DeviceControlReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Alt.DeviceControl;\r
1903 CommandReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;\r
1904 HeadReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;\r
1905\r
1906 if (Extensive) {\r
1907 DevControl = 0;\r
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
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
1943 DeviceSelect = (UINT8)(((BIT7 | BIT5) | (Device << 4)));\r
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
1956\r
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
1964}\r
1965\r
1966/**\r
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
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
1984 )\r
1985{\r
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
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
1998 Packet.RequestSence.allocation_length = (UINT8)sizeof (ATAPI_REQUEST_SENSE_DATA);\r
1999\r
2000 Ptr = (UINT16 *)SenseBuffers;\r
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
2009 Sense = (ATAPI_REQUEST_SENSE_DATA *)Ptr;\r
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
2015 AtapiBlkIoDev,\r
2016 DevicePosition,\r
2017 &Packet,\r
2018 Ptr,\r
2019 sizeof (ATAPI_REQUEST_SENSE_DATA),\r
2020 ATAPITIMEOUT\r
2021 );\r
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
2038\r
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
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
2061/**\r
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
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
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
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
2081 )\r
2082{\r
2083 EFI_STATUS Status;\r
2084 ATAPI_PACKET_COMMAND Packet;\r
2085\r
2086 //\r
2087 // used for capacity data returned from ATAPI device\r
2088 //\r
2089 ATAPI_READ_CAPACITY_DATA Data;\r
2090 ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;\r
2091\r
2092 ZeroMem (&Data, sizeof (Data));\r
2093 ZeroMem (&FormatData, sizeof (FormatData));\r
2094\r
2095 if (MediaInfo->DeviceType == IdeCDROM) {\r
2096 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
2097 Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;\r
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
2106 } else {\r
2107 //\r
2108 // DeviceType == IdeLS120\r
2109 //\r
2110 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
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
2121 }\r
2122\r
2123 if (Status == EFI_SUCCESS) {\r
2124 if (MediaInfo->DeviceType == IdeCDROM) {\r
2125 MediaInfo->LastBlock = ((UINT32)Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;\r
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
2131 MediaInfo->BlockSize = 0x800;\r
2132\r
2133 MediaInfo2->LastBlock = MediaInfo->LastBlock;\r
2134 MediaInfo2->MediaPresent = MediaInfo->MediaPresent;\r
2135 MediaInfo2->BlockSize = (UINT32)MediaInfo->BlockSize;\r
2136 }\r
2137\r
2138 if (MediaInfo->DeviceType == IdeLS120) {\r
2139 if (FormatData.DesCode == 3) {\r
2140 MediaInfo->MediaPresent = FALSE;\r
2141 MediaInfo->LastBlock = 0;\r
2142 MediaInfo2->MediaPresent = FALSE;\r
2143 MediaInfo2->LastBlock = 0;\r
2144 } else {\r
2145 MediaInfo->LastBlock = ((UINT32)FormatData.LastLba3 << 24) |\r
2146 (FormatData.LastLba2 << 16) |\r
2147 (FormatData.LastLba1 << 8) |\r
2148 FormatData.LastLba0;\r
2149 MediaInfo->LastBlock--;\r
2150\r
2151 MediaInfo->MediaPresent = TRUE;\r
2152\r
2153 MediaInfo->BlockSize = 0x200;\r
2154\r
2155 MediaInfo2->LastBlock = MediaInfo->LastBlock;\r
2156 MediaInfo2->MediaPresent = MediaInfo->MediaPresent;\r
2157 MediaInfo2->BlockSize = (UINT32)MediaInfo->BlockSize;\r
2158 }\r
2159 }\r
2160\r
2161 return EFI_SUCCESS;\r
2162 } else {\r
2163 return EFI_DEVICE_ERROR;\r
2164 }\r
2165}\r
2166\r
2167/**\r
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
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
2189 )\r
2190{\r
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
2205 Read10Packet = &Packet.Read10;\r
2206 Lba32 = (UINT32)StartLba;\r
2207 PtrBuffer = Buffer;\r
2208\r
2209 //\r
2210 // limit the data bytes that can be transfered by one Read(10) Command\r
2211 //\r
2212 MaxBlock = (UINT16)(0x10000 / BlockSize);\r
2213 //\r
2214 // (64k bytes)\r
2215 //\r
2216 BlocksRemaining = NumberOfBlocks;\r
2217\r
2218 Status = EFI_SUCCESS;\r
2219 while (BlocksRemaining > 0) {\r
2220 if (BlocksRemaining <= MaxBlock) {\r
2221 SectorCount = (UINT16)BlocksRemaining;\r
2222 } else {\r
2223 SectorCount = MaxBlock;\r
2224 }\r
2225\r
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
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
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
2244 Read10Packet->TranLen1 = (UINT8)(SectorCount & 0xff);\r
2245 Read10Packet->TranLen0 = (UINT8)(SectorCount >> 8);\r
2246\r
2247 ByteCount = (UINT32)(SectorCount * BlockSize);\r
2248\r
2249 Status = AtapiPacketCommandIn (\r
2250 AtapiBlkIoDev,\r
2251 DevicePosition,\r
2252 &Packet,\r
2253 (UINT16 *)PtrBuffer,\r
2254 ByteCount,\r
2255 ATAPILONGTIMEOUT\r
2256 );\r
2257 if (Status != EFI_SUCCESS) {\r
2258 return Status;\r
2259 }\r
2260\r
2261 Lba32 += SectorCount;\r
2262 PtrBuffer = (UINT8 *)PtrBuffer + SectorCount * BlockSize;\r
2263 BlocksRemaining -= SectorCount;\r
2264 }\r
2265\r
2266 return Status;\r
2267}\r
2268\r
2269/**\r
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
2286 UINTN Index;\r
2287 BOOLEAN IsNoMedia;\r
2288\r
2289 IsNoMedia = FALSE;\r
2290\r
2291 SensePtr = SenseData;\r
2292\r
2293 for (Index = 0; Index < SenseCounts; Index++) {\r
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
2304/**\r
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
2311 @retval FALSE Device state is clear\r
2312\r
2313**/\r
2314BOOLEAN\r
2315IsDeviceStateUnclear (\r
2316 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
2317 IN UINTN SenseCounts\r
2318 )\r
2319{\r
2320 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
2321 UINTN Index;\r
2322 BOOLEAN Unclear;\r
2323\r
2324 Unclear = FALSE;\r
2325\r
2326 SensePtr = SenseData;\r
2327\r
2328 for (Index = 0; Index < SenseCounts; Index++) {\r
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
2344/**\r
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
2361 UINTN Index;\r
2362 BOOLEAN IsError;\r
2363\r
2364 IsError = FALSE;\r
2365\r
2366 SensePtr = SenseData;\r
2367\r
2368 for (Index = 0; Index < SenseCounts; Index++) {\r
2369 switch (SensePtr->sense_key) {\r
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
2387\r
2388 default:\r
2389 break;\r
2390 }\r
2391\r
2392 break;\r
2393\r
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
2403\r
2404 break;\r
2405\r
2406 default:\r
2407 break;\r
2408 }\r
2409\r
2410 SensePtr++;\r
2411 }\r
2412\r
2413 return IsError;\r
2414}\r
2415\r
2416/**\r
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
2429 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
2430 IN UINTN SenseCounts,\r
2431 OUT BOOLEAN *NeedRetry\r
2432 )\r
2433{\r
2434 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
2435 UINTN Index;\r
2436 BOOLEAN IsReady;\r
2437\r
2438 IsReady = TRUE;\r
2439 *NeedRetry = FALSE;\r
2440\r
2441 SensePtr = SenseData;\r
2442\r
2443 for (Index = 0; Index < SenseCounts; Index++) {\r
2444 switch (SensePtr->sense_key) {\r
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
2464 }\r
2465\r
2466 break;\r
2467\r
2468 default:\r
2469 break;\r
2470 }\r
2471\r
2472 SensePtr++;\r
2473 }\r
2474\r
2475 return IsReady;\r
2476}\r