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