]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/IdeBusPei/AtapiPeim.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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
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
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
25c80c55 71 AtapiBlkIoDev->PpiDescriptor.Flags = EFI_PEI_PPI_DESCRIPTOR_PPI;\r
ea060cfa 72 AtapiBlkIoDev->PpiDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid;\r
73 AtapiBlkIoDev->PpiDescriptor.Ppi = &AtapiBlkIoDev->AtapiBlkIo;\r
74\r
25c80c55
FT
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
ea060cfa 79 DEBUG ((EFI_D_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
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
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
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
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
d1102dba 192 DEBUG ((EFI_D_INFO, "Atatpi GetInfo DevicePosition is %d\n", AtapiBlkIoDev->DeviceInfo[Index].DevicePosition));\r
ea060cfa 193 DEBUG ((EFI_D_INFO, "Atatpi GetInfo DeviceType is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.DeviceType));\r
194 DEBUG ((EFI_D_INFO, "Atatpi GetInfo MediaPresent is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.MediaPresent));\r
195 DEBUG ((EFI_D_INFO, "Atatpi GetInfo BlockSize is 0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.BlockSize));\r
196 DEBUG ((EFI_D_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
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
208 DEBUG ((EFI_D_INFO, "Atatpi GetInfo DevicePosition is %d\n", AtapiBlkIoDev->DeviceInfo[Index].DevicePosition));\r
209 DEBUG ((EFI_D_INFO, "Atatpi GetInfo DeviceType is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.DeviceType));\r
210 DEBUG ((EFI_D_INFO, "Atatpi GetInfo MediaPresent is %d\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.MediaPresent));\r
211 DEBUG ((EFI_D_INFO, "Atatpi GetInfo BlockSize is 0x%x\n", AtapiBlkIoDev->DeviceInfo[Index].MediaInfo.BlockSize));\r
212 DEBUG ((EFI_D_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
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
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
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\r
268 EFI_PEI_BLOCK_IO_MEDIA MediaInfo;\r
25c80c55
FT
269 EFI_STATUS Status;\r
270 UINTN NumberOfBlocks;\r
271 UINTN BlockSize;\r
272 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
ea060cfa 273\r
274 AtapiBlkIoDev = NULL;\r
275\r
276 if (This == NULL) {\r
277 return EFI_INVALID_PARAMETER;\r
278 }\r
279\r
280 AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO_THIS (This);\r
281\r
282 if (Buffer == NULL) {\r
283 return EFI_INVALID_PARAMETER;\r
284 }\r
285\r
286 if (BufferSize == 0) {\r
287 return EFI_SUCCESS;\r
288 }\r
289\r
290 Status = AtapiGetBlockDeviceMediaInfo (\r
291 PeiServices,\r
292 This,\r
293 DeviceIndex,\r
294 &MediaInfo\r
295 );\r
296 if (Status != EFI_SUCCESS) {\r
297 return EFI_DEVICE_ERROR;\r
298 }\r
299\r
300 if (!MediaInfo.MediaPresent) {\r
301 return EFI_NO_MEDIA;\r
302 }\r
303\r
304 BlockSize = MediaInfo.BlockSize;\r
305\r
306 if (BufferSize % BlockSize != 0) {\r
307 return EFI_BAD_BUFFER_SIZE;\r
308 }\r
309\r
310 NumberOfBlocks = BufferSize / BlockSize;\r
311\r
25c80c55 312 if ((StartLBA + NumberOfBlocks - 1) > AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].MediaInfo2.LastBlock) {\r
ea060cfa 313 return EFI_INVALID_PARAMETER;\r
314 }\r
315\r
316 Status = ReadSectors (\r
317 AtapiBlkIoDev,\r
318 AtapiBlkIoDev->DeviceInfo[DeviceIndex - 1].DevicePosition,\r
319 Buffer,\r
320 StartLBA,\r
321 NumberOfBlocks,\r
322 BlockSize\r
323 );\r
324 if (EFI_ERROR (Status)) {\r
325 return EFI_DEVICE_ERROR;\r
326 }\r
327\r
328 return EFI_SUCCESS;\r
329}\r
330\r
25c80c55
FT
331/**\r
332 Gets the count of block I/O devices that one specific block driver detects.\r
333\r
334 This function is used for getting the count of block I/O devices that one\r
335 specific block driver detects. To the PEI ATAPI driver, it returns the number\r
336 of all the detected ATAPI devices it detects during the enumeration process.\r
337 To the PEI legacy floppy driver, it returns the number of all the legacy\r
338 devices it finds during its enumeration process. If no device is detected,\r
339 then the function will return zero.\r
340\r
341 @param[in] PeiServices General-purpose services that are available\r
342 to every PEIM.\r
343 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI\r
344 instance.\r
345 @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
346\r
347 @retval EFI_SUCCESS Operation performed successfully.\r
348\r
349**/\r
350EFI_STATUS\r
351EFIAPI\r
352AtapiGetNumberOfBlockDevices2 (\r
353 IN EFI_PEI_SERVICES **PeiServices,\r
354 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
355 OUT UINTN *NumberBlockDevices\r
356 )\r
357{\r
358 EFI_STATUS Status;\r
359 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
360\r
361 AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO2_THIS (This);\r
362\r
363 Status = AtapiGetNumberOfBlockDevices (\r
364 PeiServices,\r
365 &AtapiBlkIoDev->AtapiBlkIo,\r
366 NumberBlockDevices\r
367 );\r
368\r
369 return Status;\r
370}\r
371\r
372/**\r
373 Gets a block device's media information.\r
374\r
375 This function will provide the caller with the specified block device's media\r
376 information. If the media changes, calling this function will update the media\r
377 information accordingly.\r
378\r
379 @param[in] PeiServices General-purpose services that are available to every\r
380 PEIM\r
381 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
382 @param[in] DeviceIndex Specifies the block device to which the function wants\r
383 to talk. Because the driver that implements Block I/O\r
384 PPIs will manage multiple block devices, the PPIs that\r
385 want to talk to a single device must specify the\r
386 device index that was assigned during the enumeration\r
387 process. This index is a number from one to\r
388 NumberBlockDevices.\r
389 @param[out] MediaInfo The media information of the specified block media.\r
390 The caller is responsible for the ownership of this\r
391 data structure.\r
392\r
393 @retval EFI_SUCCESS Media information about the specified block device\r
394 was obtained successfully.\r
395 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
396 error.\r
397 @retval Others Other failure occurs.\r
398\r
399**/\r
400EFI_STATUS\r
401EFIAPI\r
402AtapiGetBlockDeviceMediaInfo2 (\r
403 IN EFI_PEI_SERVICES **PeiServices,\r
404 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
405 IN UINTN DeviceIndex,\r
406 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo\r
407 )\r
408{\r
409 ATAPI_BLK_IO_DEV *AtapiBlkIoDev;\r
410 EFI_STATUS Status;\r
411 EFI_PEI_BLOCK_IO_MEDIA Media;\r
412\r
413 AtapiBlkIoDev = NULL;\r
414\r
415 if (This == NULL || MediaInfo == NULL) {\r
416 return EFI_INVALID_PARAMETER;\r
417 }\r
418\r
419 AtapiBlkIoDev = PEI_RECOVERY_ATAPI_FROM_BLKIO2_THIS (This);\r
420\r
421 Status = AtapiGetBlockDeviceMediaInfo (\r
422 PeiServices,\r
423 &AtapiBlkIoDev->AtapiBlkIo,\r
424 DeviceIndex,\r
425 &Media\r
426 );\r
427 if (EFI_ERROR (Status)) {\r
428 return Status;\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
ea060cfa 507/**\r
508 Enumerate Atapi devices.\r
509\r
510 This function is used to enumerate Atatpi device in Ide channel.\r
511\r
512 @param[in] AtapiBlkIoDev A pointer to atapi block IO device\r
513\r
514**/\r
515VOID\r
516AtapiEnumerateDevices (\r
517 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev\r
518 )\r
519{\r
25c80c55
FT
520 UINT8 Index1;\r
521 UINT8 Index2;\r
522 UINTN DevicePosition;\r
ea060cfa 523 EFI_PEI_BLOCK_IO_MEDIA MediaInfo;\r
25c80c55
FT
524 EFI_PEI_BLOCK_IO2_MEDIA MediaInfo2;\r
525 EFI_STATUS Status;\r
526 UINTN DeviceCount;\r
527 UINT16 CommandBlockBaseAddr;\r
528 UINT16 ControlBlockBaseAddr;\r
529 UINT32 IdeEnabledNumber;\r
530 IDE_REGS_BASE_ADDR IdeRegsBaseAddr[MAX_IDE_CHANNELS];\r
ea060cfa 531\r
532 DeviceCount = 0;\r
533 DevicePosition = 0;\r
534\r
535 //\r
536 // Scan IDE bus for ATAPI devices\r
537 //\r
538\r
539 //\r
540 // Enable Sata and IDE controller.\r
541 //\r
542 AtapiBlkIoDev->AtaControllerPpi->EnableAtaChannel (\r
543 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(),\r
544 AtapiBlkIoDev->AtaControllerPpi,\r
545 PEI_ICH_IDE_PRIMARY | PEI_ICH_IDE_SECONDARY\r
546 );\r
547\r
548 //\r
d1102dba 549 // Allow SATA Devices to spin-up. This is needed if\r
ea060cfa 550 // SEC and PEI phase is too short, for example Release Build.\r
551 //\r
552 DEBUG ((EFI_D_INFO, "Delay for %d seconds for SATA devices to spin-up\n", PcdGet16 (PcdSataSpinUpDelayInSecForRecoveryPath)));\r
553 MicroSecondDelay (PcdGet16 (PcdSataSpinUpDelayInSecForRecoveryPath) * 1000 * 1000); //\r
554\r
555 //\r
556 // Get four channels (primary or secondary Pata, Sata Channel) Command and Control Regs Base address.\r
557 //\r
558 IdeEnabledNumber = AtapiBlkIoDev->AtaControllerPpi->GetIdeRegsBaseAddr (\r
559 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(),\r
560 AtapiBlkIoDev->AtaControllerPpi,\r
561 IdeRegsBaseAddr\r
562 );\r
563\r
564 //\r
565 // Using Command and Control Regs Base Address to fill other registers.\r
566 //\r
d1102dba 567 for (Index1 = 0; Index1 < IdeEnabledNumber; Index1 ++) {\r
ea060cfa 568 CommandBlockBaseAddr = IdeRegsBaseAddr[Index1].CommandBlockBaseAddr;\r
569 AtapiBlkIoDev->IdeIoPortReg[Index1].Data = CommandBlockBaseAddr;\r
570 AtapiBlkIoDev->IdeIoPortReg[Index1].Reg1.Feature = (UINT16) (CommandBlockBaseAddr + 0x1);\r
571 AtapiBlkIoDev->IdeIoPortReg[Index1].SectorCount = (UINT16) (CommandBlockBaseAddr + 0x2);\r
572 AtapiBlkIoDev->IdeIoPortReg[Index1].SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x3);\r
573 AtapiBlkIoDev->IdeIoPortReg[Index1].CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x4);\r
574 AtapiBlkIoDev->IdeIoPortReg[Index1].CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x5);\r
575 AtapiBlkIoDev->IdeIoPortReg[Index1].Head = (UINT16) (CommandBlockBaseAddr + 0x6);\r
576 AtapiBlkIoDev->IdeIoPortReg[Index1].Reg.Command = (UINT16) (CommandBlockBaseAddr + 0x7);\r
577\r
578 ControlBlockBaseAddr = IdeRegsBaseAddr[Index1].ControlBlockBaseAddr;\r
579 AtapiBlkIoDev->IdeIoPortReg[Index1].Alt.DeviceControl = ControlBlockBaseAddr;\r
580 AtapiBlkIoDev->IdeIoPortReg[Index1].DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x1);\r
d1102dba 581\r
ea060cfa 582 //\r
583 // Scan IDE bus for ATAPI devices IDE or Sata device\r
584 //\r
585 for (Index2 = IdeMaster; Index2 < IdeMaxDevice; Index2++) {\r
586 //\r
587 // Pata & Sata, Primary & Secondary channel, Master & Slave device\r
588 //\r
16f69227 589 DevicePosition = Index1 * 2 + Index2;\r
ea060cfa 590\r
25c80c55 591 if (DiscoverAtapiDevice (AtapiBlkIoDev, DevicePosition, &MediaInfo, &MediaInfo2)) {\r
ea060cfa 592 //\r
593 // ATAPI Device at DevicePosition is found.\r
594 //\r
595 AtapiBlkIoDev->DeviceInfo[DeviceCount].DevicePosition = DevicePosition;\r
596 //\r
597 // Retrieve Media Info\r
598 //\r
25c80c55 599 Status = DetectMedia (AtapiBlkIoDev, DevicePosition, &MediaInfo, &MediaInfo2);\r
ea060cfa 600 CopyMem (&(AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo), &MediaInfo, sizeof (MediaInfo));\r
25c80c55
FT
601 CopyMem (&(AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2), &MediaInfo2, sizeof (MediaInfo2));\r
602\r
ea060cfa 603 DEBUG ((EFI_D_INFO, "Atatpi Device Position is %d\n", DevicePosition));\r
604 DEBUG ((EFI_D_INFO, "Atatpi DeviceType is %d\n", MediaInfo.DeviceType));\r
605 DEBUG ((EFI_D_INFO, "Atatpi MediaPresent is %d\n", MediaInfo.MediaPresent));\r
606 DEBUG ((EFI_D_INFO, "Atatpi BlockSize is 0x%x\n", MediaInfo.BlockSize));\r
607\r
608 if (EFI_ERROR (Status)) {\r
609 AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo.MediaPresent = FALSE;\r
610 AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo.LastBlock = 0;\r
25c80c55
FT
611 AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2.MediaPresent = FALSE;\r
612 AtapiBlkIoDev->DeviceInfo[DeviceCount].MediaInfo2.LastBlock = 0;\r
ea060cfa 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
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
636 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
637 IN UINTN DevicePosition,\r
25c80c55
FT
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
647 //\r
648 // test if it is an ATAPI device (only supported device)\r
649 //\r
650 if (ATAPIIdentify (AtapiBlkIoDev, DevicePosition) == EFI_SUCCESS) {\r
651\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
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 // Send a "ATAPI TEST UNIT READY" command ... slow but accurate\r
786 //\r
787 Status = TestUnitReady (AtapiBlkIoDev, DevicePosition);\r
788 return Status;\r
789 }\r
790\r
791 return EFI_NOT_FOUND;\r
792}\r
793\r
794/**\r
795 Detect if an IDE controller exists in specified position.\r
d1102dba 796\r
ea060cfa 797 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
798 @param[in] DevicePosition An integer to signify device position.\r
799\r
800 @retval TRUE The Atapi device exists.\r
801 @retval FALSE The Atapi device does not present.\r
802\r
803**/\r
804BOOLEAN\r
805DetectIDEController (\r
806 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
807 IN UINTN DevicePosition\r
808 )\r
809{\r
810 UINT8 Channel;\r
811 EFI_STATUS Status;\r
812 UINT8 AtaCommand;\r
813\r
814 Channel = (UINT8) (DevicePosition / 2);\r
815\r
816 ASSERT (Channel < MAX_IDE_CHANNELS);\r
817 //\r
818 // Wait 31 seconds for BSY clear\r
819 //\r
820 Status = WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 31000);\r
821 if (EFI_ERROR (Status)) {\r
822 return FALSE;\r
823 }\r
824 //\r
825 // Send 'check power' command for IDE device\r
826 //\r
827 AtaCommand = 0xE5;\r
828 Status = CheckPowerMode (AtapiBlkIoDev, DevicePosition, AtaCommand);\r
829 if ((Status == EFI_ABORTED) || (Status == EFI_SUCCESS)) {\r
830 return TRUE;\r
831 }\r
832\r
833 return FALSE;\r
834}\r
835\r
836/**\r
837 Wait specified time interval to poll for BSY bit clear in the Status Register.\r
d1102dba 838\r
ea060cfa 839 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
840 @param[in] IdeIoRegisters A pointer to IDE IO registers.\r
841 @param[in] TimeoutInMilliSeconds Time specified in milliseconds.\r
842\r
843 @retval EFI_SUCCESS BSY bit is cleared in the specified time interval.\r
844 @retval EFI_TIMEOUT BSY bit is not cleared in the specified time interval.\r
845\r
846**/\r
847EFI_STATUS\r
848WaitForBSYClear (\r
849 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
850 IN IDE_BASE_REGISTERS *IdeIoRegisters,\r
851 IN UINTN TimeoutInMilliSeconds\r
852 )\r
853{\r
854 UINTN Delay;\r
855 UINT16 StatusRegister;\r
856 UINT8 StatusValue;\r
857\r
858 StatusValue = 0;\r
859\r
860 StatusRegister = IdeIoRegisters->Reg.Status;\r
861\r
862 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
863 do {\r
864 StatusValue = IoRead8 (StatusRegister);\r
865 if ((StatusValue & ATA_STSREG_BSY) == 0x00) {\r
866 break;\r
867 }\r
868 MicroSecondDelay (250);\r
869\r
870 Delay--;\r
871\r
872 } while (Delay != 0);\r
873\r
874 if (Delay == 0) {\r
875 return EFI_TIMEOUT;\r
876 }\r
877\r
878 return EFI_SUCCESS;\r
879}\r
880\r
881/**\r
882 Wait specified time interval to poll for DRDY bit set in the Status register.\r
d1102dba 883\r
ea060cfa 884 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
885 @param[in] IdeIoRegisters A pointer to IDE IO registers.\r
886 @param[in] TimeoutInMilliSeconds Time specified in milliseconds.\r
887\r
888 @retval EFI_SUCCESS DRDY bit is set in the specified time interval.\r
889 @retval EFI_TIMEOUT DRDY bit is not set in the specified time interval.\r
890\r
891**/\r
892EFI_STATUS\r
893DRDYReady (\r
894 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
895 IN IDE_BASE_REGISTERS *IdeIoRegisters,\r
896 IN UINTN TimeoutInMilliSeconds\r
897 )\r
898{\r
899 UINTN Delay;\r
900 UINT16 StatusRegister;\r
901 UINT8 StatusValue;\r
902 UINT8 ErrValue;\r
903\r
904 StatusValue = 0;\r
905\r
906 StatusRegister = IdeIoRegisters->Reg.Status;\r
907\r
908 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
909 do {\r
910 StatusValue = IoRead8 (StatusRegister);\r
911 //\r
912 // BSY == 0 , DRDY == 1\r
913 //\r
914 if ((StatusValue & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
915 break;\r
916 }\r
917\r
918 if ((StatusValue & (ATA_STSREG_ERR | ATA_STSREG_BSY)) == ATA_STSREG_ERR) {\r
919 ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);\r
920 if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
921 return EFI_ABORTED;\r
922 }\r
923 }\r
d1102dba 924\r
ea060cfa 925 MicroSecondDelay (250);\r
926\r
927 Delay--;\r
928\r
929 } while (Delay != 0);\r
930\r
931 if (Delay == 0) {\r
932 return EFI_TIMEOUT;\r
933 }\r
934\r
935 return EFI_SUCCESS;\r
936}\r
937\r
938/**\r
939 Wait specified time interval to poll for DRQ bit clear in the Status Register.\r
d1102dba 940\r
ea060cfa 941 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
942 @param[in] IdeIoRegisters A pointer to IDE IO registers.\r
943 @param[in] TimeoutInMilliSeconds Time specified in milliseconds.\r
944\r
945 @retval EFI_SUCCESS DRQ bit is cleared in the specified time interval.\r
946 @retval EFI_TIMEOUT DRQ bit is not cleared in the specified time interval.\r
947\r
948**/\r
949EFI_STATUS\r
950DRQClear (\r
951 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
952 IN IDE_BASE_REGISTERS *IdeIoRegisters,\r
953 IN UINTN TimeoutInMilliSeconds\r
954 )\r
955{\r
956 UINTN Delay;\r
957 UINT16 StatusRegister;\r
958 UINT8 StatusValue;\r
959 UINT8 ErrValue;\r
960\r
961 StatusValue = 0;\r
962\r
963 StatusRegister = IdeIoRegisters->Reg.Status;\r
964\r
965 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
966 do {\r
967\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
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
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\r
1026 AltStatusValue = IoRead8 (AltStatusRegister);\r
1027\r
1028 //\r
1029 // wait for BSY == 0 and DRQ == 0\r
1030 //\r
1031 if ((AltStatusValue & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
1032 break;\r
1033 }\r
1034\r
1035 if ((AltStatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
1036 ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);\r
1037 if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
1038 return EFI_ABORTED;\r
1039 }\r
1040 }\r
d1102dba 1041\r
ea060cfa 1042 MicroSecondDelay (250);\r
1043\r
1044 Delay--;\r
1045 } while (Delay != 0);\r
1046\r
1047 if (Delay == 0) {\r
1048 return EFI_TIMEOUT;\r
1049 }\r
1050\r
1051 return EFI_SUCCESS;\r
1052}\r
1053\r
1054/**\r
1055 Wait specified time interval to poll for DRQ bit set in the Status Register.\r
1056\r
1057 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1058 @param[in] IdeIoRegisters A pointer to IDE IO registers.\r
1059 @param[in] TimeoutInMilliSeconds Time specified in milliseconds.\r
1060\r
1061 @retval EFI_SUCCESS DRQ bit is set in the specified time interval.\r
1062 @retval EFI_TIMEOUT DRQ bit is not set in the specified time interval.\r
1063 @retval EFI_ABORTED Operation Aborted.\r
1064\r
1065**/\r
1066EFI_STATUS\r
1067DRQReady (\r
1068 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1069 IN IDE_BASE_REGISTERS *IdeIoRegisters,\r
1070 IN UINTN TimeoutInMilliSeconds\r
1071 )\r
1072{\r
1073 UINTN Delay;\r
1074 UINT16 StatusRegister;\r
1075 UINT8 StatusValue;\r
1076 UINT8 ErrValue;\r
1077\r
1078 StatusValue = 0;\r
1079 ErrValue = 0;\r
1080\r
1081 StatusRegister = IdeIoRegisters->Reg.Status;\r
1082\r
1083 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
1084 do {\r
1085 //\r
1086 // read Status Register will clear interrupt\r
1087 //\r
1088 StatusValue = IoRead8 (StatusRegister);\r
1089\r
1090 //\r
1091 // BSY==0,DRQ==1\r
1092 //\r
1093 if ((StatusValue & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
1094 break;\r
1095 }\r
1096\r
1097 if ((StatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
1098\r
1099 ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);\r
1100 if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
1101 return EFI_ABORTED;\r
1102 }\r
1103 }\r
1104 MicroSecondDelay (250);\r
1105\r
1106 Delay--;\r
1107 } while (Delay != 0);\r
1108\r
1109 if (Delay == 0) {\r
1110 return EFI_TIMEOUT;\r
1111 }\r
1112\r
1113 return EFI_SUCCESS;\r
1114}\r
1115\r
1116/**\r
1117 Wait specified time interval to poll for DRQ bit set in the Alternate Status Register.\r
1118\r
1119 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1120 @param[in] IdeIoRegisters A pointer to IDE IO registers.\r
1121 @param[in] TimeoutInMilliSeconds Time specified in milliseconds.\r
1122\r
1123 @retval EFI_SUCCESS DRQ bit is set in the specified time interval.\r
1124 @retval EFI_TIMEOUT DRQ bit is not set in the specified time interval.\r
1125 @retval EFI_ABORTED Operation Aborted.\r
1126\r
1127**/\r
1128EFI_STATUS\r
1129DRQReady2 (\r
1130 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1131 IN IDE_BASE_REGISTERS *IdeIoRegisters,\r
1132 IN UINTN TimeoutInMilliSeconds\r
1133 )\r
1134{\r
1135 UINTN Delay;\r
1136 UINT16 AltStatusRegister;\r
1137 UINT8 AltStatusValue;\r
1138 UINT8 ErrValue;\r
1139\r
1140 AltStatusValue = 0;\r
1141\r
1142 AltStatusRegister = IdeIoRegisters->Alt.AltStatus;\r
1143\r
1144 Delay = ((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 250) + 1;\r
1145 do {\r
1146\r
1147 AltStatusValue = IoRead8 (AltStatusRegister);\r
1148\r
1149 //\r
1150 // BSY==0,DRQ==1\r
1151 //\r
1152 if ((AltStatusValue & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
1153 break;\r
1154 }\r
1155\r
1156 if ((AltStatusValue & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
1157\r
1158 ErrValue = IoRead8 (IdeIoRegisters->Reg1.Error);\r
1159 if ((ErrValue & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
1160 return EFI_ABORTED;\r
1161 }\r
1162 }\r
1163 MicroSecondDelay (250);\r
1164\r
1165 Delay--;\r
1166 } while (Delay != 0);\r
1167\r
1168 if (Delay == 0) {\r
1169 return EFI_TIMEOUT;\r
1170 }\r
1171\r
1172 return EFI_SUCCESS;\r
1173}\r
1174\r
1175/**\r
1176 Check if there is an error in Status Register.\r
1177\r
1178 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1179 @param[in] StatusReg The address to IDE IO registers.\r
1180\r
1181 @retval EFI_SUCCESS Operation success.\r
1182 @retval EFI_DEVICE_ERROR Device error.\r
1183\r
1184**/\r
1185EFI_STATUS\r
1186CheckErrorStatus (\r
1187 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1188 IN UINT16 StatusReg\r
1189 )\r
1190{\r
1191 UINT8 StatusValue;\r
1192\r
1193 StatusValue = IoRead8 (StatusReg);\r
1194\r
1195 if ((StatusValue & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {\r
1196\r
1197 return EFI_SUCCESS;\r
1198 }\r
1199\r
1200 return EFI_DEVICE_ERROR;\r
1201\r
1202}\r
1203\r
1204/**\r
1205 Idendify Atapi devices.\r
1206\r
1207 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1208 @param[in] DevicePosition An integer to signify device position.\r
1209\r
1210 @retval EFI_SUCCESS Identify successfully.\r
1211 @retval EFI_DEVICE_ERROR Device cannot be identified successfully.\r
1212\r
1213**/\r
1214EFI_STATUS\r
1215ATAPIIdentify (\r
1216 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1217 IN UINTN DevicePosition\r
1218 )\r
1219{\r
1220 ATAPI_IDENTIFY_DATA AtapiIdentifyData;\r
25c80c55
FT
1221 UINT8 Channel;\r
1222 UINT8 Device;\r
1223 UINT16 StatusReg;\r
1224 UINT16 HeadReg;\r
1225 UINT16 CommandReg;\r
1226 UINT16 DataReg;\r
1227 UINT16 SectorCountReg;\r
1228 UINT16 SectorNumberReg;\r
1229 UINT16 CylinderLsbReg;\r
1230 UINT16 CylinderMsbReg;\r
1231\r
1232 UINT32 WordCount;\r
1233 UINT32 Increment;\r
1234 UINT32 Index;\r
1235 UINT32 ByteCount;\r
1236 UINT16 *Buffer16;\r
1237\r
1238 EFI_STATUS Status;\r
ea060cfa 1239\r
1240 ByteCount = sizeof (AtapiIdentifyData);\r
1241 Buffer16 = (UINT16 *) &AtapiIdentifyData;\r
1242\r
1243 Channel = (UINT8) (DevicePosition / 2);\r
1244 Device = (UINT8) (DevicePosition % 2);\r
1245\r
1246 ASSERT (Channel < MAX_IDE_CHANNELS);\r
1247\r
1248 StatusReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Status;\r
1249 HeadReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;\r
1250 CommandReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;\r
1251 DataReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Data;\r
1252 SectorCountReg = AtapiBlkIoDev->IdeIoPortReg[Channel].SectorCount;\r
1253 SectorNumberReg = AtapiBlkIoDev->IdeIoPortReg[Channel].SectorNumber;\r
1254 CylinderLsbReg = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderLsb;\r
1255 CylinderMsbReg = AtapiBlkIoDev->IdeIoPortReg[Channel].CylinderMsb;\r
1256\r
1257 //\r
1258 // Send ATAPI Identify Command to get IDENTIFY data.\r
1259 //\r
1260 if (WaitForBSYClear (\r
1261 AtapiBlkIoDev,\r
1262 &(AtapiBlkIoDev->IdeIoPortReg[Channel]),\r
1263 ATATIMEOUT\r
1264 ) != EFI_SUCCESS) {\r
1265 return EFI_DEVICE_ERROR;\r
1266 }\r
1267 //\r
1268 // select device via Head/Device register.\r
1269 // Before write Head/Device register, BSY and DRQ must be 0.\r
1270 //\r
1271 if (DRQClear2 (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), ATATIMEOUT) != EFI_SUCCESS) {\r
1272 return EFI_DEVICE_ERROR;\r
1273 }\r
1274 //\r
1275 // e0:1110,0000-- bit7 and bit5 are reserved bits.\r
1276 // bit6 set means LBA mode\r
1277 //\r
1278 IoWrite8 (HeadReg, (UINT8) ((Device << 4) | 0xe0));\r
1279\r
1280 //\r
1281 // set all the command parameters\r
1282 // Before write to all the following registers, BSY and DRQ must be 0.\r
1283 //\r
1284 if (DRQClear2 (\r
1285 AtapiBlkIoDev,\r
1286 &(AtapiBlkIoDev->IdeIoPortReg[Channel]),\r
1287 ATATIMEOUT\r
1288 ) != EFI_SUCCESS) {\r
1289\r
1290 return EFI_DEVICE_ERROR;\r
1291 }\r
1292\r
1293 IoWrite8 (SectorCountReg, 0);\r
1294 IoWrite8 (SectorNumberReg, 0);\r
1295 IoWrite8 (CylinderLsbReg, 0);\r
1296 IoWrite8 (CylinderMsbReg, 0);\r
1297\r
1298 //\r
1299 // send command via Command Register\r
1300 //\r
1301 IoWrite8 (CommandReg, ATA_CMD_IDENTIFY_DEVICE);\r
1302\r
1303 //\r
1304 // According to PIO data in protocol, host can perform a series of reads to the\r
1305 // data register after each time device set DRQ ready;\r
1306 // The data size of "a series of read" is command specific.\r
1307 // For most ATA command, data size received from device will not exceed 1 sector,\r
1308 // hense the data size for "a series of read" can be the whole data size of one command request.\r
1309 // For ATA command such as Read Sector command, whole data size of one ATA command request is often larger\r
1310 // than 1 sector, according to the Read Sector command, the data size of "a series of read" is exactly\r
1311 // 1 sector.\r
1312 // Here for simplification reason, we specify the data size for "a series of read" to\r
1313 // 1 sector (256 words) if whole data size of one ATA commmand request is larger than 256 words.\r
1314 //\r
1315 Increment = 256;\r
1316 //\r
1317 // 256 words\r
1318 //\r
1319 WordCount = 0;\r
1320 //\r
1321 // WordCount is used to record bytes of currently transfered data\r
1322 //\r
1323 while (WordCount < ByteCount / 2) {\r
1324 //\r
1325 // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
1326 //\r
1327 Status = DRQReady2 (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), ATATIMEOUT);\r
1328 if (Status != EFI_SUCCESS) {\r
1329 return Status;\r
1330 }\r
1331\r
1332 if (CheckErrorStatus (AtapiBlkIoDev, StatusReg) != EFI_SUCCESS) {\r
1333\r
1334 return EFI_DEVICE_ERROR;\r
1335 }\r
1336 //\r
1337 // Get the byte count for one series of read\r
1338 //\r
1339 if ((WordCount + Increment) > ByteCount / 2) {\r
1340 Increment = ByteCount / 2 - WordCount;\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 return CheckErrorStatus (AtapiBlkIoDev, StatusReg);\r
1361 }\r
1362\r
1363 return EFI_SUCCESS;\r
1364\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
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
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 return EFI_DEVICE_ERROR;\r
1476 }\r
1477 //\r
1478 // Select device via Device/Head Register.\r
1479 // DEFAULT_CMD: 0xa0 (1010,0000)\r
1480 //\r
1481 IoWrite8 (HeadReg, (UINT8) ((Device << 4) | ATA_DEFAULT_CMD));\r
1482\r
1483 //\r
1484 // No OVL; No DMA\r
1485 //\r
1486 IoWrite8 (FeatureReg, 0x00);\r
1487\r
1488 //\r
1489 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device\r
1490 // determine how many data should be transfered.\r
1491 //\r
1492 IoWrite8 (CylinderLsbReg, (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff));\r
1493 IoWrite8 (CylinderMsbReg, (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8));\r
1494\r
1495 //\r
1496 // DEFAULT_CTL:0x0a (0000,1010)\r
1497 // Disable interrupt\r
1498 //\r
1499 IoWrite8 (DeviceControlReg, ATA_DEFAULT_CTL);\r
1500\r
1501 //\r
1502 // Send Packet command to inform device\r
1503 // that the following data bytes are command packet.\r
1504 //\r
1505 IoWrite8 (CommandReg, ATA_CMD_PACKET);\r
1506\r
1507 Status = DRQReady (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), TimeoutInMilliSeconds);\r
1508 if (Status != EFI_SUCCESS) {\r
1509 return Status;\r
1510 }\r
1511 //\r
1512 // Send out command packet\r
1513 //\r
1514 CommandIndex = Packet->Data16;\r
1515 for (Count = 0; Count < 6; Count++, CommandIndex++) {\r
1516 IoWrite16 (DataReg, *CommandIndex);\r
1517 MicroSecondDelay (10);\r
1518 }\r
1519\r
1520 StatusValue = IoRead8 (StatusReg);\r
1521 if ((StatusValue & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
1522 //\r
1523 // Trouble! Something's wrong here... Wait some time and return. 3 second is\r
1524 // supposed to be long enough for a device reset latency or error recovery\r
1525 //\r
1526 MicroSecondDelay (3000000);\r
1527 return EFI_DEVICE_ERROR;\r
1528 }\r
1529\r
1530 if (Buffer == NULL || ByteCount == 0) {\r
1531 return EFI_SUCCESS;\r
1532 }\r
1533 //\r
1534 // call PioReadWriteData() function to get\r
1535 // requested transfer data form device.\r
1536 //\r
1537 PtrBuffer = Buffer;\r
1538 RequiredWordCount = ByteCount / 2;\r
1539 //\r
1540 // ActuralWordCount means the word count of data really transfered.\r
1541 //\r
1542 ActualWordCount = 0;\r
1543\r
1544 Status = EFI_SUCCESS;\r
1545 while ((Status == EFI_SUCCESS) && (ActualWordCount < RequiredWordCount)) {\r
1546 //\r
1547 // before each data transfer stream, the host should poll DRQ bit ready,\r
1548 // which informs device is ready to transfer data.\r
1549 //\r
1550 if (DRQReady2 (\r
1551 AtapiBlkIoDev,\r
1552 &(AtapiBlkIoDev->IdeIoPortReg[Channel]),\r
1553 TimeoutInMilliSeconds\r
1554 ) != EFI_SUCCESS) {\r
1555 return CheckErrorStatus (AtapiBlkIoDev, StatusReg);\r
1556 }\r
1557 //\r
1558 // read Status Register will clear interrupt\r
1559 //\r
1560 StatusValue = IoRead8 (StatusReg);\r
1561\r
1562 //\r
1563 // get current data transfer size from Cylinder Registers.\r
1564 //\r
1565 WordCount = IoRead8 (CylinderMsbReg) << 8;\r
1566 WordCount = WordCount | IoRead8 (CylinderLsbReg);\r
1567 WordCount = WordCount & 0xffff;\r
1568 WordCount /= 2;\r
1569\r
1570 //\r
1571 // perform a series data In/Out.\r
1572 //\r
1573 for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {\r
1574\r
1575 *PtrBuffer = IoRead16 (DataReg);\r
1576\r
1577 PtrBuffer++;\r
1578\r
1579 }\r
1580\r
1581 if (((ATAPI_REQUEST_SENSE_CMD *) Packet)->opcode == ATA_CMD_REQUEST_SENSE && ActualWordCount >= 4) {\r
1582 RequiredWordCount = MIN (\r
1583 RequiredWordCount,\r
1584 (UINT32) (4 + (((ATAPI_REQUEST_SENSE_DATA *) Buffer)->addnl_sense_length / 2))\r
1585 );\r
1586 }\r
1587\r
1588 }\r
1589 //\r
1590 // After data transfer is completed, normally, DRQ bit should clear.\r
1591 //\r
1592 Status = DRQClear2 (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), TimeoutInMilliSeconds);\r
1593 if (Status != EFI_SUCCESS) {\r
1594 return EFI_DEVICE_ERROR;\r
1595 }\r
1596 //\r
1597 // read status register to check whether error happens.\r
1598 //\r
1599 Status = CheckErrorStatus (AtapiBlkIoDev, StatusReg);\r
1600 return Status;\r
1601}\r
1602\r
1603/**\r
1604 Sends out ATAPI Inquiry Packet Command to the specified device.\r
1605 This command will return INQUIRY data of the device.\r
1606\r
1607 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1608 @param[in] DevicePosition An integer to signify device position.\r
1609 @param[out] MediaInfo The media information of the specified block media.\r
25c80c55 1610 @param[out] MediaInfo2 The media information 2 of the specified block media.\r
ea060cfa 1611\r
1612 @retval EFI_SUCCESS Command executed successfully.\r
1613 @retval EFI_DEVICE_ERROR Device cannot be executed command successfully.\r
1614 @retval EFI_UNSUPPORTED Unsupported device type.\r
1615\r
1616**/\r
1617EFI_STATUS\r
1618Inquiry (\r
1619 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1620 IN UINTN DevicePosition,\r
25c80c55
FT
1621 OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,\r
1622 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2\r
ea060cfa 1623 )\r
1624{\r
25c80c55
FT
1625 ATAPI_PACKET_COMMAND Packet;\r
1626 EFI_STATUS Status;\r
ea060cfa 1627 ATAPI_INQUIRY_DATA Idata;\r
1628\r
1629 //\r
1630 // prepare command packet for the ATAPI Inquiry Packet Command.\r
1631 //\r
1632 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
523f48e7 1633 ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA));\r
ea060cfa 1634\r
1635 Packet.Inquiry.opcode = ATA_CMD_INQUIRY;\r
1636 Packet.Inquiry.page_code = 0;\r
1637 Packet.Inquiry.allocation_length = (UINT8) sizeof (ATAPI_INQUIRY_DATA);\r
1638\r
1639 //\r
1640 // Send command packet and get requested Inquiry data.\r
1641 //\r
1642 Status = AtapiPacketCommandIn (\r
1643 AtapiBlkIoDev,\r
1644 DevicePosition,\r
1645 &Packet,\r
1646 (UINT16 *) (&Idata),\r
1647 sizeof (ATAPI_INQUIRY_DATA),\r
1648 ATAPITIMEOUT\r
1649 //50\r
1650 );\r
1651\r
1652 if (Status != EFI_SUCCESS) {\r
1653 return EFI_DEVICE_ERROR;\r
1654 }\r
1655 //\r
1656 // Identify device type via INQUIRY data.\r
1657 //\r
1658 switch (Idata.peripheral_type & 0x1f) {\r
1659 case 0x00:\r
1660 //\r
1661 // Magnetic Disk\r
1662 //\r
1663 MediaInfo->DeviceType = IdeLS120;\r
1664 MediaInfo->MediaPresent = FALSE;\r
1665 MediaInfo->LastBlock = 0;\r
1666 MediaInfo->BlockSize = 0x200;\r
25c80c55
FT
1667 MediaInfo2->InterfaceType = MSG_ATAPI_DP;\r
1668 MediaInfo2->RemovableMedia = TRUE;\r
1669 MediaInfo2->MediaPresent = FALSE;\r
1670 MediaInfo2->ReadOnly = FALSE;\r
1671 MediaInfo2->BlockSize = 0x200;\r
1672 MediaInfo2->LastBlock = 0;\r
ea060cfa 1673 break;\r
1674\r
1675 case 0x05:\r
1676 //\r
1677 // CD-ROM\r
1678 //\r
1679 MediaInfo->DeviceType = IdeCDROM;\r
1680 MediaInfo->MediaPresent = FALSE;\r
1681 MediaInfo->LastBlock = 0;\r
1682 MediaInfo->BlockSize = 0x800;\r
25c80c55
FT
1683 MediaInfo2->InterfaceType = MSG_ATAPI_DP;\r
1684 MediaInfo2->RemovableMedia = TRUE;\r
1685 MediaInfo2->MediaPresent = FALSE;\r
1686 MediaInfo2->ReadOnly = TRUE;\r
1687 MediaInfo2->BlockSize = 0x200;\r
1688 MediaInfo2->LastBlock = 0;\r
ea060cfa 1689 break;\r
1690\r
1691 default:\r
1692 return EFI_UNSUPPORTED;\r
1693 }\r
1694\r
1695 return EFI_SUCCESS;\r
1696}\r
1697\r
d1102dba
LG
1698/**\r
1699 Used before read/write blocks from/to ATAPI device media.\r
ea060cfa 1700 Since ATAPI device media is removable, it is necessary to detect\r
1701 whether media is present and get current present media's information.\r
1702\r
1703 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1704 @param[in] DevicePosition An integer to signify device position.\r
25c80c55
FT
1705 @param[in, out] MediaInfo The media information of the specified block media.\r
1706 @param[in, out] MediaInfo2 The media information 2 of the specified block media.\r
ea060cfa 1707\r
1708 @retval EFI_SUCCESS Command executed successfully.\r
1709 @retval EFI_DEVICE_ERROR Some device errors happen.\r
1710 @retval EFI_OUT_OF_RESOURCES Can not allocate required resources.\r
1711\r
1712**/\r
1713EFI_STATUS\r
1714DetectMedia (\r
1715 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1716 IN UINTN DevicePosition,\r
25c80c55
FT
1717 IN OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,\r
1718 IN OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2\r
ea060cfa 1719 )\r
1720{\r
1721\r
25c80c55
FT
1722 UINTN Index;\r
1723 UINTN RetryNum;\r
1724 UINTN MaxRetryNum;\r
1725 ATAPI_REQUEST_SENSE_DATA *SenseBuffers;\r
1726 BOOLEAN NeedReadCapacity;\r
1727 BOOLEAN NeedRetry;\r
1728 EFI_STATUS Status;\r
1729 UINT8 SenseCounts;\r
ea060cfa 1730\r
1731 SenseBuffers = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*SenseBuffers)));\r
1732 if (SenseBuffers == NULL) {\r
1733 return EFI_OUT_OF_RESOURCES;\r
1734 }\r
d1102dba 1735\r
ea060cfa 1736 //\r
1737 // Test Unit Ready command is used to detect whether device is accessible,\r
1738 // the device will produce corresponding Sense data.\r
1739 //\r
1740 for (Index = 0; Index < 2; Index++) {\r
1741\r
1742 Status = TestUnitReady (AtapiBlkIoDev, DevicePosition);\r
1743 if (Status != EFI_SUCCESS) {\r
1744 Status = ResetDevice (AtapiBlkIoDev, DevicePosition, FALSE);\r
1745\r
1746 if (Status != EFI_SUCCESS) {\r
1747 ResetDevice (AtapiBlkIoDev, DevicePosition, TRUE);\r
1748 }\r
1749\r
1750 } else {\r
1751 break;\r
1752 }\r
1753 }\r
1754\r
1755 SenseCounts = MAX_SENSE_KEY_COUNT;\r
1756 Status = EFI_SUCCESS;\r
1757 NeedReadCapacity = TRUE;\r
1758\r
1759 for (Index = 0; Index < 5; Index++) {\r
1760 SenseCounts = MAX_SENSE_KEY_COUNT;\r
1761 Status = RequestSense (\r
1762 AtapiBlkIoDev,\r
1763 DevicePosition,\r
1764 SenseBuffers,\r
1765 &SenseCounts\r
1766 );\r
1767 DEBUG ((EFI_D_INFO, "Atapi Request Sense Count is %d\n", SenseCounts));\r
1768 if (IsDeviceStateUnclear (SenseBuffers, SenseCounts) || IsNoMedia (SenseBuffers, SenseCounts)) {\r
1769 //\r
1770 // We are not sure whether the media is present or not, try again\r
1771 //\r
1772 TestUnitReady (AtapiBlkIoDev, DevicePosition);\r
1773 } else {\r
1774 break;\r
1775 }\r
1776 }\r
1777\r
1778 if (Status == EFI_SUCCESS) {\r
1779\r
1780 if (IsNoMedia (SenseBuffers, SenseCounts)) {\r
1781\r
1782 NeedReadCapacity = FALSE;\r
1783 MediaInfo->MediaPresent = FALSE;\r
1784 MediaInfo->LastBlock = 0;\r
25c80c55
FT
1785 MediaInfo2->MediaPresent = FALSE;\r
1786 MediaInfo2->LastBlock = 0;\r
ea060cfa 1787 }\r
1788\r
1789 if (IsMediaError (SenseBuffers, SenseCounts)) {\r
1790 return EFI_DEVICE_ERROR;\r
1791 }\r
1792 }\r
1793\r
1794 if (NeedReadCapacity) {\r
1795 //\r
1796 // at most retry 5 times\r
1797 //\r
1798 MaxRetryNum = 5;\r
1799 RetryNum = 1;\r
1800 //\r
1801 // initial retry once\r
1802 //\r
1803 for (Index = 0; (Index < RetryNum) && (Index < MaxRetryNum); Index++) {\r
1804\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
1810\r
1811 Status = RequestSense (AtapiBlkIoDev, DevicePosition, SenseBuffers, &SenseCounts);\r
1812 //\r
1813 // If Request Sense data failed, reset the device and retry.\r
1814 //\r
1815 if (Status != EFI_SUCCESS) {\r
1816\r
1817 Status = ResetDevice (AtapiBlkIoDev, DevicePosition, FALSE);\r
1818 //\r
1819 // if ATAPI soft reset fail,\r
1820 // use stronger reset mechanism -- ATA soft reset.\r
1821 //\r
1822 if (Status != EFI_SUCCESS) {\r
1823 ResetDevice (AtapiBlkIoDev, DevicePosition, TRUE);\r
1824 }\r
1825\r
1826 RetryNum++;\r
1827 //\r
1828 // retry once more\r
1829 //\r
1830 continue;\r
1831 }\r
1832 //\r
1833 // No Media\r
1834 //\r
1835 if (IsNoMedia (SenseBuffers, SenseCounts)) {\r
1836\r
1837 MediaInfo->MediaPresent = FALSE;\r
1838 MediaInfo->LastBlock = 0;\r
25c80c55
FT
1839 MediaInfo2->MediaPresent = FALSE;\r
1840 MediaInfo2->LastBlock = 0;\r
ea060cfa 1841 break;\r
1842 }\r
1843\r
1844 if (IsMediaError (SenseBuffers, SenseCounts)) {\r
1845 return EFI_DEVICE_ERROR;\r
1846 }\r
1847\r
1848 if (!IsDriveReady (SenseBuffers, SenseCounts, &NeedRetry)) {\r
1849 //\r
1850 // Drive not ready: if NeedRetry, then retry once more;\r
1851 // else return error\r
1852 //\r
1853 if (NeedRetry) {\r
1854 RetryNum++;\r
1855 continue;\r
1856 } else {\r
1857 return EFI_DEVICE_ERROR;\r
1858 }\r
1859 }\r
1860 //\r
1861 // if read capacity fail not for above reasons, retry once more\r
1862 //\r
1863 RetryNum++;\r
1864\r
1865 }\r
1866\r
1867 }\r
1868\r
1869 }\r
1870\r
1871 return EFI_SUCCESS;\r
1872}\r
1873\r
d1102dba 1874/**\r
ea060cfa 1875 Reset specified Atapi device.\r
1876\r
1877 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1878 @param[in] DevicePosition An integer to signify device position.\r
1879 @param[in] Extensive If TRUE, use ATA soft reset, otherwise use Atapi soft reset.\r
1880\r
1881 @retval EFI_SUCCESS Command executed successfully.\r
1882 @retval EFI_DEVICE_ERROR Some device errors happen.\r
1883\r
1884**/\r
1885EFI_STATUS\r
1886ResetDevice (\r
1887 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1888 IN UINTN DevicePosition,\r
1889 IN BOOLEAN Extensive\r
1890 )\r
1891{\r
1892 UINT8 DevControl;\r
1893 UINT8 Command;\r
1894 UINT8 DeviceSelect;\r
1895 UINT16 DeviceControlReg;\r
1896 UINT16 CommandReg;\r
1897 UINT16 HeadReg;\r
1898 UINT8 Channel;\r
1899 UINT8 Device;\r
1900\r
1901 Channel = (UINT8) (DevicePosition / 2);\r
1902 Device = (UINT8) (DevicePosition % 2);\r
1903\r
1904 ASSERT (Channel < MAX_IDE_CHANNELS);\r
1905\r
1906 DeviceControlReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Alt.DeviceControl;\r
1907 CommandReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Reg.Command;\r
1908 HeadReg = AtapiBlkIoDev->IdeIoPortReg[Channel].Head;\r
1909\r
1910 if (Extensive) {\r
1911\r
1912 DevControl = 0;\r
1913 DevControl |= ATA_CTLREG_SRST;\r
1914 //\r
1915 // set SRST bit to initiate soft reset\r
1916 //\r
1917 DevControl |= BIT1;\r
1918 //\r
1919 // disable Interrupt\r
1920 //\r
1921 IoWrite8 (DeviceControlReg, DevControl);\r
1922\r
1923 //\r
1924 // Wait 10us\r
1925 //\r
1926 MicroSecondDelay (10);\r
1927\r
1928 //\r
1929 // Clear SRST bit\r
1930 //\r
1931 DevControl &= 0xfb;\r
1932 //\r
1933 // 0xfb:1111,1011\r
1934 //\r
1935 IoWrite8 (DeviceControlReg, DevControl);\r
1936\r
1937 //\r
1938 // slave device needs at most 31s to clear BSY\r
1939 //\r
1940 if (WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 31000) == EFI_TIMEOUT) {\r
1941 return EFI_DEVICE_ERROR;\r
1942 }\r
1943\r
1944 } else {\r
1945 //\r
1946 // for ATAPI device, no need to wait DRDY ready after device selecting.\r
1947 // bit7 and bit5 are both set to 1 for backward compatibility\r
1948 //\r
1949 DeviceSelect = (UINT8) (((BIT7 | BIT5) | (Device << 4)));\r
1950 IoWrite8 (HeadReg, DeviceSelect);\r
1951\r
1952 Command = ATA_CMD_SOFT_RESET;\r
1953 IoWrite8 (CommandReg, Command);\r
1954\r
1955 //\r
1956 // BSY cleared is the only status return to the host by the device when reset is completed\r
1957 // slave device needs at most 31s to clear BSY\r
1958 //\r
1959 if (WaitForBSYClear (AtapiBlkIoDev, &(AtapiBlkIoDev->IdeIoPortReg[Channel]), 31000) != EFI_SUCCESS) {\r
1960 return EFI_DEVICE_ERROR;\r
1961 }\r
1962 //\r
1963 // stall 5 seconds to make the device status stable\r
1964 //\r
1965 MicroSecondDelay (STALL_1_SECONDS * 5);\r
1966 }\r
1967\r
1968 return EFI_SUCCESS;\r
1969\r
1970}\r
1971\r
d1102dba 1972/**\r
ea060cfa 1973 Sends out ATAPI Request Sense Packet Command to the specified device.\r
1974\r
1975 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
1976 @param[in] DevicePosition An integer to signify device position.\r
1977 @param[in] SenseBuffers Pointer to sense buffer.\r
1978 @param[in, out] SenseCounts Length of sense buffer.\r
1979\r
1980 @retval EFI_SUCCESS Command executed successfully.\r
1981 @retval EFI_DEVICE_ERROR Some device errors happen.\r
1982\r
1983**/\r
1984EFI_STATUS\r
1985RequestSense (\r
1986 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
1987 IN UINTN DevicePosition,\r
1988 IN ATAPI_REQUEST_SENSE_DATA *SenseBuffers,\r
1989 IN OUT UINT8 *SenseCounts\r
1990 )\r
1991{\r
1992 EFI_STATUS Status;\r
1993 ATAPI_REQUEST_SENSE_DATA *Sense;\r
1994 UINT16 *Ptr;\r
1995 BOOLEAN SenseReq;\r
1996 ATAPI_PACKET_COMMAND Packet;\r
1997\r
1998 ZeroMem (SenseBuffers, sizeof (ATAPI_REQUEST_SENSE_DATA) * (*SenseCounts));\r
1999 //\r
2000 // fill command packet for Request Sense Packet Command\r
2001 //\r
2002 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
2003 Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE;\r
2004 Packet.RequestSence.allocation_length = (UINT8) sizeof (ATAPI_REQUEST_SENSE_DATA);\r
2005\r
2006 Ptr = (UINT16 *) SenseBuffers;\r
2007 //\r
2008 // initialize pointer\r
2009 //\r
2010 *SenseCounts = 0;\r
2011 //\r
2012 // request sense data from device continiously until no sense data exists in the device.\r
2013 //\r
2014 for (SenseReq = TRUE; SenseReq;) {\r
2015\r
2016 Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;\r
2017\r
2018 //\r
2019 // send out Request Sense Packet Command and get one Sense data form device\r
2020 //\r
2021 Status = AtapiPacketCommandIn (\r
2022 AtapiBlkIoDev,\r
2023 DevicePosition,\r
2024 &Packet,\r
2025 Ptr,\r
2026 sizeof (ATAPI_REQUEST_SENSE_DATA),\r
2027 ATAPITIMEOUT\r
2028 );\r
2029 //\r
2030 // failed to get Sense data\r
2031 //\r
2032 if (Status != EFI_SUCCESS) {\r
2033 if (*SenseCounts == 0) {\r
2034 return EFI_DEVICE_ERROR;\r
2035 } else {\r
2036 return EFI_SUCCESS;\r
2037 }\r
2038 }\r
2039\r
2040 (*SenseCounts)++;\r
2041\r
2042 if (*SenseCounts > MAX_SENSE_KEY_COUNT) {\r
2043 return EFI_SUCCESS;\r
2044 }\r
2045 //\r
2046 // We limit MAX sense data count to 20 in order to avoid dead loop. Some\r
2047 // incompatible ATAPI devices don't retrive NO_SENSE when there is no media.\r
2048 // In this case, dead loop occurs if we don't have a gatekeeper. 20 is\r
2049 // supposed to be large enough for any ATAPI device.\r
2050 //\r
2051 if ((Sense->sense_key != ATA_SK_NO_SENSE) && ((*SenseCounts) < 20)) {\r
2052\r
2053 Ptr += sizeof (ATAPI_REQUEST_SENSE_DATA) / 2;\r
2054 //\r
2055 // Ptr is word based pointer\r
2056 //\r
2057 } else {\r
2058 //\r
2059 // when no sense key, skip out the loop\r
2060 //\r
2061 SenseReq = FALSE;\r
2062 }\r
2063 }\r
2064\r
2065 return EFI_SUCCESS;\r
2066}\r
2067\r
d1102dba 2068/**\r
ea060cfa 2069 Sends out ATAPI Read Capacity Packet Command to the specified device.\r
2070 This command will return the information regarding the capacity of the\r
2071 media in the device.\r
2072\r
25c80c55
FT
2073 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
2074 @param[in] DevicePosition An integer to signify device position.\r
2075 @param[in, out] MediaInfo The media information of the specified block media.\r
2076 @param[in, out] MediaInfo2 The media information 2 of the specified block media.\r
ea060cfa 2077\r
2078 @retval EFI_SUCCESS Command executed successfully.\r
2079 @retval EFI_DEVICE_ERROR Some device errors happen.\r
2080\r
2081**/\r
2082EFI_STATUS\r
2083ReadCapacity (\r
2084 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
2085 IN UINTN DevicePosition,\r
25c80c55
FT
2086 IN OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo,\r
2087 IN OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo2\r
ea060cfa 2088 )\r
2089{\r
2090 EFI_STATUS Status;\r
2091 ATAPI_PACKET_COMMAND Packet;\r
2092\r
2093 //\r
2094 // used for capacity data returned from ATAPI device\r
2095 //\r
2096 ATAPI_READ_CAPACITY_DATA Data;\r
2097 ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;\r
2098\r
2099 ZeroMem (&Data, sizeof (Data));\r
2100 ZeroMem (&FormatData, sizeof (FormatData));\r
2101\r
2102 if (MediaInfo->DeviceType == IdeCDROM) {\r
2103\r
2104 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
2105 Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;\r
2106 Status = AtapiPacketCommandIn (\r
2107 AtapiBlkIoDev,\r
2108 DevicePosition,\r
2109 &Packet,\r
2110 (UINT16 *) (&Data),\r
2111 sizeof (ATAPI_READ_CAPACITY_DATA),\r
2112 ATAPITIMEOUT\r
2113 );\r
2114\r
2115 } else {\r
2116 //\r
2117 // DeviceType == IdeLS120\r
2118 //\r
2119 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
2120 Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;\r
2121 Packet.ReadFormatCapacity.allocation_length_lo = 12;\r
2122 Status = AtapiPacketCommandIn (\r
2123 AtapiBlkIoDev,\r
2124 DevicePosition,\r
2125 &Packet,\r
2126 (UINT16 *) (&FormatData),\r
2127 sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),\r
2128 ATAPITIMEOUT*10\r
2129 );\r
2130 }\r
2131\r
2132 if (Status == EFI_SUCCESS) {\r
2133\r
2134 if (MediaInfo->DeviceType == IdeCDROM) {\r
2135\r
3778a4df 2136 MediaInfo->LastBlock = ((UINT32) Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;\r
ea060cfa 2137 MediaInfo->MediaPresent = TRUE;\r
2138 //\r
2139 // Because the user data portion in the sector of the Data CD supported\r
2140 // is always 800h\r
2141 //\r
25c80c55
FT
2142 MediaInfo->BlockSize = 0x800;\r
2143\r
2144 MediaInfo2->LastBlock = MediaInfo->LastBlock;\r
2145 MediaInfo2->MediaPresent = MediaInfo->MediaPresent;\r
2146 MediaInfo2->BlockSize = (UINT32)MediaInfo->BlockSize;\r
ea060cfa 2147 }\r
2148\r
2149 if (MediaInfo->DeviceType == IdeLS120) {\r
2150\r
2151 if (FormatData.DesCode == 3) {\r
2152 MediaInfo->MediaPresent = FALSE;\r
2153 MediaInfo->LastBlock = 0;\r
25c80c55
FT
2154 MediaInfo2->MediaPresent = FALSE;\r
2155 MediaInfo2->LastBlock = 0;\r
ea060cfa 2156 } else {\r
3778a4df 2157 MediaInfo->LastBlock = ((UINT32) FormatData.LastLba3 << 24) |\r
ea060cfa 2158 (FormatData.LastLba2 << 16) |\r
2159 (FormatData.LastLba1 << 8) |\r
2160 FormatData.LastLba0;\r
2161 MediaInfo->LastBlock--;\r
2162\r
2163 MediaInfo->MediaPresent = TRUE;\r
2164\r
2165 MediaInfo->BlockSize = 0x200;\r
2166\r
25c80c55
FT
2167 MediaInfo2->LastBlock = MediaInfo->LastBlock;\r
2168 MediaInfo2->MediaPresent = MediaInfo->MediaPresent;\r
2169 MediaInfo2->BlockSize = (UINT32)MediaInfo->BlockSize;\r
2170\r
ea060cfa 2171 }\r
2172 }\r
2173\r
2174 return EFI_SUCCESS;\r
2175\r
2176 } else {\r
2177 return EFI_DEVICE_ERROR;\r
2178 }\r
2179}\r
2180\r
d1102dba 2181/**\r
ea060cfa 2182 Perform read from disk in block unit.\r
2183\r
2184 @param[in] AtapiBlkIoDev A pointer to atapi block IO device.\r
2185 @param[in] DevicePosition An integer to signify device position.\r
2186 @param[in] Buffer Buffer to contain read data.\r
2187 @param[in] StartLba Starting LBA address.\r
2188 @param[in] NumberOfBlocks Number of blocks to read.\r
2189 @param[in] BlockSize Size of each block.\r
2190\r
2191 @retval EFI_SUCCESS Command executed successfully.\r
2192 @retval EFI_DEVICE_ERROR Some device errors happen.\r
2193\r
2194**/\r
2195EFI_STATUS\r
2196ReadSectors (\r
2197 IN ATAPI_BLK_IO_DEV *AtapiBlkIoDev,\r
2198 IN UINTN DevicePosition,\r
2199 IN VOID *Buffer,\r
2200 IN EFI_PEI_LBA StartLba,\r
2201 IN UINTN NumberOfBlocks,\r
2202 IN UINTN BlockSize\r
2203 )\r
2204{\r
2205\r
2206 ATAPI_PACKET_COMMAND Packet;\r
2207 ATAPI_READ10_CMD *Read10Packet;\r
2208 EFI_STATUS Status;\r
2209 UINTN BlocksRemaining;\r
2210 UINT32 Lba32;\r
2211 UINT32 ByteCount;\r
2212 UINT16 SectorCount;\r
2213 VOID *PtrBuffer;\r
2214 UINT16 MaxBlock;\r
2215\r
2216 //\r
2217 // fill command packet for Read(10) command\r
2218 //\r
2219 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
2220 Read10Packet = &Packet.Read10;\r
2221 Lba32 = (UINT32) StartLba;\r
2222 PtrBuffer = Buffer;\r
2223\r
2224 //\r
2225 // limit the data bytes that can be transfered by one Read(10) Command\r
2226 //\r
2227 MaxBlock = (UINT16) (0x10000 / BlockSize);\r
2228 //\r
2229 // (64k bytes)\r
2230 //\r
2231 BlocksRemaining = NumberOfBlocks;\r
2232\r
2233 Status = EFI_SUCCESS;\r
2234 while (BlocksRemaining > 0) {\r
2235\r
2236 if (BlocksRemaining <= MaxBlock) {\r
2237 SectorCount = (UINT16) BlocksRemaining;\r
2238 } else {\r
2239 SectorCount = MaxBlock;\r
2240 }\r
2241 //\r
2242 // fill the Packet data sturcture\r
2243 //\r
2244 Read10Packet->opcode = ATA_CMD_READ_10;\r
2245\r
2246 //\r
2247 // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
2248 // Lba0 is MSB, Lba3 is LSB\r
2249 //\r
2250 Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);\r
2251 Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);\r
2252 Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);\r
2253 Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);\r
2254\r
2255 //\r
2256 // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
2257 // TranLen0 is MSB, TranLen is LSB\r
2258 //\r
2259 Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);\r
2260 Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);\r
2261\r
2262 ByteCount = (UINT32) (SectorCount * BlockSize);\r
2263\r
2264 Status = AtapiPacketCommandIn (\r
2265 AtapiBlkIoDev,\r
2266 DevicePosition,\r
2267 &Packet,\r
2268 (UINT16 *) PtrBuffer,\r
2269 ByteCount,\r
2270 ATAPILONGTIMEOUT\r
2271 );\r
2272 if (Status != EFI_SUCCESS) {\r
2273 return Status;\r
2274 }\r
2275\r
2276 Lba32 += SectorCount;\r
2277 PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;\r
2278 BlocksRemaining -= SectorCount;\r
2279 }\r
2280\r
2281 return Status;\r
2282}\r
2283\r
d1102dba 2284/**\r
ea060cfa 2285 Check if there is media according to sense data.\r
2286\r
2287 @param[in] SenseData Pointer to sense data.\r
2288 @param[in] SenseCounts Count of sense data.\r
2289\r
2290 @retval TRUE No media\r
2291 @retval FALSE Media exists\r
2292\r
2293**/\r
2294BOOLEAN\r
2295IsNoMedia (\r
2296 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
2297 IN UINTN SenseCounts\r
2298 )\r
2299{\r
2300 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
25c80c55
FT
2301 UINTN Index;\r
2302 BOOLEAN IsNoMedia;\r
ea060cfa 2303\r
2304 IsNoMedia = FALSE;\r
2305\r
2306 SensePtr = SenseData;\r
2307\r
2308 for (Index = 0; Index < SenseCounts; Index++) {\r
2309\r
2310 if ((SensePtr->sense_key == ATA_SK_NOT_READY) && (SensePtr->addnl_sense_code == ATA_ASC_NO_MEDIA)) {\r
2311 IsNoMedia = TRUE;\r
2312 }\r
2313\r
2314 SensePtr++;\r
2315 }\r
2316\r
2317 return IsNoMedia;\r
2318}\r
2319\r
d1102dba 2320/**\r
ea060cfa 2321 Check if device state is unclear according to sense data.\r
2322\r
2323 @param[in] SenseData Pointer to sense data.\r
2324 @param[in] SenseCounts Count of sense data.\r
2325\r
2326 @retval TRUE Device state is unclear\r
d1102dba 2327 @retval FALSE Device state is clear\r
ea060cfa 2328\r
2329**/\r
2330BOOLEAN\r
2331IsDeviceStateUnclear (\r
2332 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
2333 IN UINTN SenseCounts\r
2334 )\r
2335{\r
2336 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
25c80c55
FT
2337 UINTN Index;\r
2338 BOOLEAN Unclear;\r
ea060cfa 2339\r
2340 Unclear = FALSE;\r
2341\r
2342 SensePtr = SenseData;\r
2343\r
2344 for (Index = 0; Index < SenseCounts; Index++) {\r
2345\r
2346 if (SensePtr->sense_key == 0x06) {\r
2347 //\r
2348 // Sense key is 0x06 means the device is just be reset or media just\r
2349 // changed. The current state of the device is unclear.\r
2350 //\r
2351 Unclear = TRUE;\r
2352 break;\r
2353 }\r
2354\r
2355 SensePtr++;\r
2356 }\r
2357\r
2358 return Unclear;\r
2359}\r
2360\r
d1102dba 2361/**\r
ea060cfa 2362 Check if there is media error according to sense data.\r
2363\r
2364 @param[in] SenseData Pointer to sense data.\r
2365 @param[in] SenseCounts Count of sense data.\r
2366\r
2367 @retval TRUE Media error\r
2368 @retval FALSE No media error\r
2369\r
2370**/\r
2371BOOLEAN\r
2372IsMediaError (\r
2373 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
2374 IN UINTN SenseCounts\r
2375 )\r
2376{\r
2377 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
25c80c55
FT
2378 UINTN Index;\r
2379 BOOLEAN IsError;\r
ea060cfa 2380\r
2381 IsError = FALSE;\r
2382\r
2383 SensePtr = SenseData;\r
2384\r
2385 for (Index = 0; Index < SenseCounts; Index++) {\r
2386\r
2387 switch (SensePtr->sense_key) {\r
2388\r
2389 case ATA_SK_MEDIUM_ERROR:\r
2390 switch (SensePtr->addnl_sense_code) {\r
2391 case ATA_ASC_MEDIA_ERR1:\r
2392 //\r
2393 // fall through\r
2394 //\r
2395 case ATA_ASC_MEDIA_ERR2:\r
2396 //\r
2397 // fall through\r
2398 //\r
2399 case ATA_ASC_MEDIA_ERR3:\r
2400 //\r
2401 // fall through\r
2402 //\r
2403 case ATA_ASC_MEDIA_ERR4:\r
2404 IsError = TRUE;\r
2405 break;\r
2406\r
2407 default:\r
2408 break;\r
2409 }\r
2410\r
2411 break;\r
2412\r
2413 case ATA_SK_NOT_READY:\r
2414 switch (SensePtr->addnl_sense_code) {\r
2415 case ATA_ASC_MEDIA_UPSIDE_DOWN:\r
2416 IsError = TRUE;\r
2417 break;\r
2418\r
2419 default:\r
2420 break;\r
2421 }\r
2422 break;\r
2423\r
2424 default:\r
2425 break;\r
2426 }\r
2427\r
2428 SensePtr++;\r
2429 }\r
2430\r
2431 return IsError;\r
2432}\r
2433\r
d1102dba 2434/**\r
ea060cfa 2435 Check if drive is ready according to sense data.\r
2436\r
2437 @param[in] SenseData Pointer to sense data.\r
2438 @param[in] SenseCounts Count of sense data.\r
2439 @param[out] NeedRetry Indicate if retry is needed.\r
2440\r
2441 @retval TRUE Drive ready\r
2442 @retval FALSE Drive not ready\r
2443\r
2444**/\r
2445BOOLEAN\r
2446IsDriveReady (\r
2447 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
2448 IN UINTN SenseCounts,\r
2449 OUT BOOLEAN *NeedRetry\r
2450 )\r
2451{\r
2452 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
25c80c55
FT
2453 UINTN Index;\r
2454 BOOLEAN IsReady;\r
ea060cfa 2455\r
2456 IsReady = TRUE;\r
2457 *NeedRetry = FALSE;\r
2458\r
2459 SensePtr = SenseData;\r
2460\r
2461 for (Index = 0; Index < SenseCounts; Index++) {\r
2462\r
2463 switch (SensePtr->sense_key) {\r
2464\r
2465 case ATA_SK_NOT_READY:\r
2466 switch (SensePtr->addnl_sense_code) {\r
2467 case ATA_ASC_NOT_READY:\r
2468 switch (SensePtr->addnl_sense_code_qualifier) {\r
2469 case ATA_ASCQ_IN_PROGRESS:\r
2470 IsReady = FALSE;\r
2471 *NeedRetry = TRUE;\r
2472 break;\r
2473\r
2474 default:\r
2475 IsReady = FALSE;\r
2476 *NeedRetry = FALSE;\r
2477 break;\r
2478 }\r
2479 break;\r
2480\r
2481 default:\r
2482 break;\r
2483 }\r
2484 break;\r
2485\r
2486 default:\r
2487 break;\r
2488 }\r
2489\r
2490 SensePtr++;\r
2491 }\r
2492\r
2493 return IsReady;\r
2494}\r