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