]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c
1. The old refresh string code also update the time/date opcode. But for the reason...
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaBusDxe / AtaBus.c
CommitLineData
ad86a50a 1/** @file\r
2 This file implements protocol interfaces for ATA bus driver.\r
3 \r
4 This file implements protocol interfaces: Driver Binding protocol,\r
5 Block IO protocol and DiskInfo protocol.\r
6 \r
e519983a 7 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
cd5ebaa0 8 This program and the accompanying materials\r
ad86a50a 9 are licensed and made available under the terms and conditions of the BSD License\r
10 which accompanies this distribution. The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16\r
17**/\r
18\r
19#include "AtaBus.h"\r
20\r
21//\r
22// ATA Bus Driver Binding Protocol Instance\r
23//\r
24EFI_DRIVER_BINDING_PROTOCOL gAtaBusDriverBinding = {\r
25 AtaBusDriverBindingSupported,\r
26 AtaBusDriverBindingStart,\r
27 AtaBusDriverBindingStop,\r
28 0x10,\r
29 NULL,\r
30 NULL\r
31};\r
32\r
33//\r
34// Template for ATA Child Device.\r
35//\r
36ATA_DEVICE gAtaDeviceTemplate = {\r
05a44e91 37 ATA_DEVICE_SIGNATURE, // Signature\r
38 NULL, // Handle\r
ad86a50a 39 { // BlockIo\r
40 EFI_BLOCK_IO_PROTOCOL_REVISION,\r
41 NULL,\r
42 AtaBlockIoReset,\r
43 AtaBlockIoReadBlocks,\r
44 AtaBlockIoWriteBlocks,\r
45 AtaBlockIoFlushBlocks\r
46 },\r
47 { // BlockMedia\r
48 0, // MediaId\r
49 FALSE, // RemovableMedia\r
50 TRUE, // MediaPresent\r
51 FALSE, // LogicPartition\r
52 FALSE, // ReadOnly\r
53 FALSE, // WritingCache\r
54 0x200, // BlockSize \r
907c1a00 55 0, // IoAlign\r
3bfa77f0 56 0, // LastBlock\r
57 0, // LowestAlignedLba\r
58 1 // LogicalBlocksPerPhysicalBlock\r
ad86a50a 59 },\r
60 { // DiskInfo\r
61 EFI_DISK_INFO_IDE_INTERFACE_GUID,\r
62 AtaDiskInfoInquiry,\r
63 AtaDiskInfoIdentify,\r
64 AtaDiskInfoSenseData,\r
65 AtaDiskInfoWhichIde\r
66 },\r
05a44e91 67 NULL, // DevicePath\r
68 NULL, // AtaBusDriverData\r
69 0, // Port\r
70 0, // PortMultiplierPort\r
ad86a50a 71 { 0, }, // Packet\r
72 {{ 0}, }, // Acb\r
73 NULL, // Asb\r
74 FALSE, // UdmaValid\r
75 FALSE, // Lba48Bit\r
76 NULL, // IdentifyData\r
77 NULL, // ControllerNameTable\r
78 {L'\0', } // ModelName\r
79};\r
80\r
81/**\r
82 Allocates an aligned buffer for ATA device.\r
83\r
84 This function allocates an aligned buffer for the ATA device to perform\r
85 ATA pass through operations. The alignment requirement is from ATA pass\r
86 through interface.\r
87\r
88 @param AtaDevice The ATA child device involved for the operation.\r
89 @param BufferSize The request buffer size.\r
90\r
91 @return A pointer to the aligned buffer or NULL if the allocation fails.\r
92\r
93**/\r
94VOID *\r
95AllocateAlignedBuffer (\r
96 IN ATA_DEVICE *AtaDevice,\r
97 IN UINTN BufferSize\r
98 )\r
99{\r
100 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), AtaDevice->AtaBusDriverData->AtaPassThru->Mode->IoAlign);\r
101}\r
102\r
103/**\r
104 Frees an aligned buffer for ATA device.\r
105\r
106 This function frees an aligned buffer for the ATA device to perform\r
107 ATA pass through operations.\r
108\r
05a44e91 109 @param Buffer The aligned buffer to be freed.\r
ad86a50a 110 @param BufferSize The request buffer size.\r
111\r
112**/\r
113VOID\r
114FreeAlignedBuffer (\r
115 IN VOID *Buffer,\r
116 IN UINTN BufferSize\r
117 )\r
118{\r
119 if (Buffer != NULL) {\r
120 FreePages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));\r
121 }\r
122}\r
123\r
124\r
125/**\r
126 Release all the resources allocated for the ATA device.\r
127\r
128 This function releases all the resources allocated for the ATA device.\r
129\r
130 @param AtaDevice The ATA child device involved for the operation.\r
131\r
132**/\r
133VOID\r
134ReleaseAtaResources (\r
135 IN ATA_DEVICE *AtaDevice\r
136 )\r
137{\r
138 FreeUnicodeStringTable (AtaDevice->ControllerNameTable);\r
139 FreeAlignedBuffer (AtaDevice->Asb, sizeof (*AtaDevice->Asb));\r
140 FreeAlignedBuffer (AtaDevice->IdentifyData, sizeof (*AtaDevice->IdentifyData));\r
141 if (AtaDevice->DevicePath != NULL) {\r
142 FreePool (AtaDevice->DevicePath);\r
143 }\r
144 FreePool (AtaDevice);\r
145}\r
146\r
147\r
148/**\r
149 Registers an ATA device.\r
150\r
151 This function allocates an ATA device structure for the ATA device specified by\r
152 Port and PortMultiplierPort if the ATA device is identified as a valid one. \r
153 Then it will create child handle and install Block IO and Disk Info protocol on\r
154 it.\r
155\r
05a44e91 156 @param AtaBusDriverData The parent ATA bus driver data structure.\r
ad86a50a 157 @param Port The port number of the ATA device.\r
158 @param PortMultiplierPort The port multiplier port number of the ATA device.\r
159\r
160 @retval EFI_SUCCESS The ATA device is successfully registered.\r
161 @retval EFI_OUT_OF_RESOURCES There is not enough memory to allocate the ATA device\r
162 and related data structures.\r
163 @return Others Some error occurs when registering the ATA device.\r
164**/\r
165EFI_STATUS\r
166RegisterAtaDevice (\r
167 IN OUT ATA_BUS_DRIVER_DATA *AtaBusDriverData,\r
168 IN UINT16 Port,\r
169 IN UINT16 PortMultiplierPort\r
170 )\r
171{\r
172 EFI_STATUS Status;\r
173 ATA_DEVICE *AtaDevice;\r
174 EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;\r
175 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;\r
e519983a 176 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
177 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
178 EFI_HANDLE DeviceHandle;\r
ad86a50a 179\r
e519983a 180 AtaDevice = NULL;\r
ad86a50a 181 NewDevicePathNode = NULL;\r
e519983a 182 DevicePath = NULL;\r
183 RemainingDevicePath = NULL;\r
184\r
185 //\r
186 // Build device path \r
187 //\r
188 AtaPassThru = AtaBusDriverData->AtaPassThru;\r
189 Status = AtaPassThru->BuildDevicePath (AtaPassThru, Port, PortMultiplierPort, &NewDevicePathNode);\r
190 if (EFI_ERROR (Status)) {\r
191 goto Done;\r
192 }\r
193\r
194 DevicePath = AppendDevicePathNode (AtaBusDriverData->ParentDevicePath, NewDevicePathNode);\r
195 if (DevicePath == NULL) {\r
196 goto Done;\r
197 }\r
198\r
199 DeviceHandle = NULL;\r
200 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
201 if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
202 Status = EFI_ALREADY_STARTED;\r
203 goto Done;\r
204 }\r
ad86a50a 205\r
206 //\r
207 // Allocate ATA device from the template.\r
208 //\r
209 AtaDevice = AllocateCopyPool (sizeof (gAtaDeviceTemplate), &gAtaDeviceTemplate);\r
210 if (AtaDevice == NULL) {\r
e519983a 211 Status = EFI_OUT_OF_RESOURCES;\r
212 goto Done;\r
ad86a50a 213 }\r
214\r
215 //\r
216 // Initializes ATA device structures and allocates the required buffer.\r
217 //\r
218 AtaDevice->BlockIo.Media = &AtaDevice->BlockMedia;\r
219 AtaDevice->AtaBusDriverData = AtaBusDriverData;\r
e519983a 220 AtaDevice->DevicePath = DevicePath;\r
ad86a50a 221 AtaDevice->Port = Port;\r
222 AtaDevice->PortMultiplierPort = PortMultiplierPort;\r
223 AtaDevice->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (*AtaDevice->Asb));\r
224 if (AtaDevice->Asb == NULL) {\r
225 Status = EFI_OUT_OF_RESOURCES;\r
226 goto Done;\r
227 }\r
228 AtaDevice->IdentifyData = AllocateAlignedBuffer (AtaDevice, sizeof (*AtaDevice->IdentifyData));\r
229 if (AtaDevice->IdentifyData == NULL) {\r
230 Status = EFI_OUT_OF_RESOURCES;\r
231 goto Done;\r
232 }\r
233\r
234 //\r
235 // Try to identify the ATA device via the ATA pass through command. \r
236 //\r
237 Status = DiscoverAtaDevice (AtaDevice);\r
238 if (EFI_ERROR (Status)) {\r
239 goto Done;\r
240 }\r
241 \r
242 //\r
243 // Build controller name for Component Name (2) protocol.\r
244 //\r
245 Status = AddUnicodeString2 (\r
246 "eng",\r
247 gAtaBusComponentName.SupportedLanguages,\r
248 &AtaDevice->ControllerNameTable,\r
249 AtaDevice->ModelName,\r
250 TRUE\r
251 );\r
252 if (EFI_ERROR (Status)) {\r
253 goto Done;\r
254 }\r
255\r
256 Status = AddUnicodeString2 (\r
257 "en",\r
258 gAtaBusComponentName2.SupportedLanguages,\r
259 &AtaDevice->ControllerNameTable,\r
260 AtaDevice->ModelName,\r
261 FALSE\r
262 );\r
263 if (EFI_ERROR (Status)) {\r
264 goto Done;\r
265 }\r
266\r
ad86a50a 267 //\r
268 // Update to AHCI interface GUID based on device path node. The default one\r
269 // is IDE interface GUID copied from template.\r
270 //\r
271 if (NewDevicePathNode->SubType == MSG_SATA_DP) {\r
272 CopyGuid (&AtaDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);\r
273 }\r
274\r
ad86a50a 275 Status = gBS->InstallMultipleProtocolInterfaces (\r
276 &AtaDevice->Handle,\r
277 &gEfiDevicePathProtocolGuid,\r
278 AtaDevice->DevicePath,\r
279 &gEfiBlockIoProtocolGuid,\r
280 &AtaDevice->BlockIo,\r
281 &gEfiDiskInfoProtocolGuid,\r
282 &AtaDevice->DiskInfo,\r
283 NULL\r
284 );\r
285 if (EFI_ERROR (Status)) {\r
286 goto Done;\r
287 }\r
288\r
289 gBS->OpenProtocol (\r
290 AtaBusDriverData->Controller,\r
291 &gEfiAtaPassThruProtocolGuid,\r
292 (VOID **) &AtaPassThru,\r
293 AtaBusDriverData->DriverBindingHandle,\r
294 AtaDevice->Handle,\r
295 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
296 );\r
e519983a 297\r
ad86a50a 298Done:\r
299 if (NewDevicePathNode != NULL) {\r
300 FreePool (NewDevicePathNode);\r
301 }\r
302\r
e519983a 303 if (EFI_ERROR (Status) && (AtaDevice != NULL)) {\r
ad86a50a 304 ReleaseAtaResources (AtaDevice); \r
305 DEBUG ((DEBUG_ERROR | DEBUG_INIT, "Failed to initialize Port %x PortMultiplierPort %x, status = %r\n", Port, PortMultiplierPort, Status));\r
306 }\r
307 return Status;\r
308}\r
309\r
310\r
311/**\r
312 Unregisters an ATA device.\r
313\r
314 This function removes the protocols installed on the controller handle and \r
315 frees the resources allocated for the ATA device. \r
316\r
05a44e91 317 @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance.\r
ad86a50a 318 @param Controller The controller handle of the ATA device.\r
319 @param Handle The child handle.\r
320\r
321 @retval EFI_SUCCESS The ATA device is successfully unregistered.\r
322 @return Others Some error occurs when unregistering the ATA device.\r
323\r
324**/\r
325EFI_STATUS\r
326UnregisterAtaDevice (\r
327 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
328 IN EFI_HANDLE Controller,\r
329 IN EFI_HANDLE Handle\r
330 )\r
331{\r
332 EFI_STATUS Status;\r
333 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
334 ATA_DEVICE *AtaDevice;\r
335 EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;\r
336\r
337 Status = gBS->OpenProtocol (\r
338 Handle,\r
339 &gEfiBlockIoProtocolGuid,\r
340 (VOID **) &BlockIo,\r
341 This->DriverBindingHandle,\r
342 Controller,\r
343 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
344 );\r
345 if (EFI_ERROR (Status)) {\r
346 return Status;\r
347 }\r
348\r
349 AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (BlockIo);\r
350\r
351 //\r
352 // Close the child handle\r
353 //\r
354 gBS->CloseProtocol (\r
355 Controller,\r
356 &gEfiAtaPassThruProtocolGuid,\r
357 This->DriverBindingHandle,\r
358 Handle\r
359 );\r
360\r
361 Status = gBS->UninstallMultipleProtocolInterfaces (\r
362 Handle,\r
363 &gEfiDevicePathProtocolGuid,\r
364 AtaDevice->DevicePath,\r
365 &gEfiBlockIoProtocolGuid,\r
366 &AtaDevice->BlockIo,\r
367 &gEfiDiskInfoProtocolGuid,\r
368 &AtaDevice->DiskInfo,\r
369 NULL\r
370 );\r
371\r
372 if (EFI_ERROR (Status)) {\r
373 gBS->OpenProtocol (\r
374 Controller,\r
375 &gEfiAtaPassThruProtocolGuid,\r
376 (VOID **) &AtaPassThru,\r
377 This->DriverBindingHandle,\r
378 Handle,\r
379 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
380 );\r
381 return Status;\r
382 }\r
383\r
384 ReleaseAtaResources (AtaDevice);\r
385\r
386 return Status;\r
387}\r
388\r
389\r
390\r
391/**\r
392 Tests to see if this driver supports a given controller. If a child device is provided, \r
393 it further tests to see if this driver supports creating a handle for the specified child device.\r
394\r
395 This function checks to see if the driver specified by This supports the device specified by \r
396 ControllerHandle. Drivers will typically use the device path attached to \r
397 ControllerHandle and/or the services from the bus I/O abstraction attached to \r
398 ControllerHandle to determine if the driver supports ControllerHandle. This function \r
399 may be called many times during platform initialization. In order to reduce boot times, the tests \r
400 performed by this function must be very small, and take as little time as possible to execute. This \r
401 function must not change the state of any hardware devices, and this function must be aware that the \r
402 device specified by ControllerHandle may already be managed by the same driver or a \r
403 different driver. This function must match its calls to AllocatePages() with FreePages(), \r
404 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). \r
405 Since ControllerHandle may have been previously started by the same driver, if a protocol is \r
406 already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
407 to guarantee the state of ControllerHandle is not modified by this function.\r
408\r
409 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
410 @param[in] ControllerHandle The handle of the controller to test. This handle \r
411 must support a protocol interface that supplies \r
412 an I/O abstraction to the driver.\r
413 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
414 parameter is ignored by device drivers, and is optional for bus \r
415 drivers. For bus drivers, if this parameter is not NULL, then \r
416 the bus driver must determine if the bus controller specified \r
417 by ControllerHandle and the child controller specified \r
418 by RemainingDevicePath are both supported by this \r
419 bus driver.\r
420\r
421 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
422 RemainingDevicePath is supported by the driver specified by This.\r
423 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
424 RemainingDevicePath is already being managed by the driver\r
425 specified by This.\r
426 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
427 RemainingDevicePath is already being managed by a different\r
428 driver or an application that requires exclusive access.\r
429 Currently not implemented.\r
430 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
431 RemainingDevicePath is not supported by the driver specified by This.\r
432**/\r
433EFI_STATUS\r
434EFIAPI\r
435AtaBusDriverBindingSupported (\r
436 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
437 IN EFI_HANDLE Controller,\r
438 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
439 )\r
440{\r
441 EFI_STATUS Status;\r
442 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
443 EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;\r
444 UINT16 Port;\r
445 UINT16 PortMultiplierPort;\r
446 \r
447 //\r
448 // Test EFI_ATA_PASS_THRU_PROTOCOL on controller handle.\r
449 //\r
450 Status = gBS->OpenProtocol (\r
451 Controller,\r
452 &gEfiAtaPassThruProtocolGuid,\r
453 (VOID **) &AtaPassThru,\r
454 This->DriverBindingHandle,\r
455 Controller,\r
456 EFI_OPEN_PROTOCOL_BY_DRIVER\r
457 );\r
458\r
459 if (Status == EFI_ALREADY_STARTED) {\r
460 return EFI_SUCCESS;\r
461 }\r
462\r
463 if (EFI_ERROR (Status)) {\r
464 return Status;\r
465 }\r
466\r
467 //\r
468 // Test RemainingDevicePath is valid or not.\r
469 //\r
470 if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
471 Status = AtaPassThru->GetDevice (AtaPassThru, RemainingDevicePath, &Port, &PortMultiplierPort);\r
472 if (EFI_ERROR (Status)) {\r
473 return Status;\r
474 }\r
475 }\r
476\r
477 //\r
478 // Close the I/O Abstraction(s) used to perform the supported test\r
479 //\r
480 gBS->CloseProtocol (\r
481 Controller,\r
482 &gEfiAtaPassThruProtocolGuid,\r
483 This->DriverBindingHandle,\r
484 Controller\r
485 );\r
486\r
487 //\r
488 // Open the EFI Device Path protocol needed to perform the supported test\r
489 //\r
490 Status = gBS->OpenProtocol (\r
491 Controller,\r
492 &gEfiDevicePathProtocolGuid,\r
493 (VOID **) &ParentDevicePath,\r
494 This->DriverBindingHandle,\r
495 Controller,\r
496 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
497 );\r
498 return Status;\r
499}\r
500\r
501\r
502/**\r
503 Starts a device controller or a bus controller.\r
504\r
505 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
506 As a result, much of the error checking on the parameters to Start() has been moved into this \r
507 common boot service. It is legal to call Start() from other locations, \r
508 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
509 1. ControllerHandle must be a valid EFI_HANDLE.\r
510 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
511 EFI_DEVICE_PATH_PROTOCOL.\r
512 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
513 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. \r
514\r
515 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
516 @param[in] ControllerHandle The handle of the controller to start. This handle \r
517 must support a protocol interface that supplies \r
518 an I/O abstraction to the driver.\r
519 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
520 parameter is ignored by device drivers, and is optional for bus \r
521 drivers. For a bus driver, if this parameter is NULL, then handles \r
522 for all the children of Controller are created by this driver. \r
523 If this parameter is not NULL and the first Device Path Node is \r
524 not the End of Device Path Node, then only the handle for the \r
525 child device specified by the first Device Path Node of \r
526 RemainingDevicePath is created by this driver.\r
527 If the first Device Path Node of RemainingDevicePath is \r
528 the End of Device Path Node, no child handle is created by this\r
529 driver.\r
530\r
531 @retval EFI_SUCCESS The device was started.\r
532 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
533 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
534 @retval Others The driver failded to start the device.\r
535\r
536**/\r
537EFI_STATUS\r
538EFIAPI\r
539AtaBusDriverBindingStart (\r
540 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
541 IN EFI_HANDLE Controller,\r
542 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
543 )\r
544{\r
545 EFI_STATUS Status;\r
546 EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;\r
547 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
548 ATA_BUS_DRIVER_DATA *AtaBusDriverData;\r
549 UINT16 Port;\r
550 UINT16 PortMultiplierPort;\r
551\r
552 AtaBusDriverData = NULL;\r
553\r
554 Status = gBS->OpenProtocol (\r
555 Controller,\r
556 &gEfiDevicePathProtocolGuid,\r
557 (VOID **) &ParentDevicePath,\r
558 This->DriverBindingHandle,\r
559 Controller,\r
560 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
561 );\r
562 if (EFI_ERROR (Status)) {\r
563 return Status;\r
564 }\r
565\r
566 Status = gBS->OpenProtocol (\r
567 Controller,\r
568 &gEfiAtaPassThruProtocolGuid,\r
569 (VOID **) &AtaPassThru,\r
570 This->DriverBindingHandle,\r
571 Controller,\r
572 EFI_OPEN_PROTOCOL_BY_DRIVER\r
573 );\r
574 if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
575 goto ErrorExit;\r
576 }\r
577\r
578 //\r
579 // Check EFI_ALREADY_STARTED to reuse the original ATA_BUS_DRIVER_DATA.\r
580 //\r
581 if (Status != EFI_ALREADY_STARTED) {\r
582 AtaBusDriverData = AllocateZeroPool (sizeof (ATA_BUS_DRIVER_DATA));\r
583 if (AtaBusDriverData == NULL) {\r
584 Status = EFI_OUT_OF_RESOURCES;\r
585 goto ErrorExit;\r
586 }\r
587\r
588 AtaBusDriverData->AtaPassThru = AtaPassThru;\r
589 AtaBusDriverData->Controller = Controller;\r
590 AtaBusDriverData->ParentDevicePath = ParentDevicePath;\r
591 AtaBusDriverData->DriverBindingHandle = This->DriverBindingHandle;\r
592\r
593 Status = gBS->InstallMultipleProtocolInterfaces (\r
594 &Controller,\r
595 &gEfiCallerIdGuid,\r
596 AtaBusDriverData,\r
597 NULL\r
598 );\r
599 if (EFI_ERROR (Status)) {\r
600 goto ErrorExit;\r
601 }\r
602\r
603 } else {\r
604 Status = gBS->OpenProtocol (\r
605 Controller,\r
606 &gEfiCallerIdGuid,\r
607 (VOID **) &AtaBusDriverData,\r
608 This->DriverBindingHandle,\r
609 Controller,\r
610 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
611 );\r
612 if (EFI_ERROR (Status)) {\r
613 AtaBusDriverData = NULL;\r
614 goto ErrorExit;\r
615 }\r
616 }\r
617\r
618 if (RemainingDevicePath == NULL) {\r
619 Port = 0xFFFF;\r
620 while (TRUE) {\r
621 Status = AtaPassThru->GetNextPort (AtaPassThru, &Port);\r
622 if (EFI_ERROR (Status)) {\r
623 //\r
624 // We cannot find more legal port then we are done.\r
625 //\r
626 break;\r
627 }\r
628 \r
629 PortMultiplierPort = 0xFFFF;\r
630 while (TRUE) {\r
631 Status = AtaPassThru->GetNextDevice (AtaPassThru, Port, &PortMultiplierPort);\r
632 if (EFI_ERROR (Status)) {\r
633 //\r
634 // We cannot find more legal port multiplier port number for ATA device\r
635 // on the port, then we are done.\r
636 //\r
637 break;\r
638 }\r
639 RegisterAtaDevice (AtaBusDriverData, Port, PortMultiplierPort);\r
640 }\r
641 }\r
642 Status = EFI_SUCCESS;\r
643 } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
644 Status = AtaPassThru->GetDevice (AtaPassThru, RemainingDevicePath, &Port, &PortMultiplierPort);\r
645 if (!EFI_ERROR (Status)) {\r
646 Status = RegisterAtaDevice (AtaBusDriverData,Port, PortMultiplierPort);\r
647 }\r
648 }\r
649 \r
650 return Status;\r
651\r
652ErrorExit:\r
653\r
654 if (AtaBusDriverData != NULL) {\r
655 gBS->UninstallMultipleProtocolInterfaces (\r
656 Controller,\r
657 &gEfiCallerIdGuid,\r
658 AtaBusDriverData,\r
659 NULL\r
660 );\r
661 FreePool (AtaBusDriverData);\r
662 }\r
663\r
664 gBS->CloseProtocol (\r
665 Controller,\r
666 &gEfiAtaPassThruProtocolGuid,\r
667 This->DriverBindingHandle,\r
668 Controller\r
669 );\r
670\r
671 return Status;\r
672\r
673}\r
674\r
675\r
676/**\r
677 Stops a device controller or a bus controller.\r
678 \r
679 The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
680 As a result, much of the error checking on the parameters to Stop() has been moved \r
681 into this common boot service. It is legal to call Stop() from other locations, \r
682 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
683 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
684 same driver's Start() function.\r
685 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
686 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
687 Start() function, and the Start() function must have called OpenProtocol() on\r
688 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
689 \r
690 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
691 @param[in] ControllerHandle A handle to the device being stopped. The handle must \r
692 support a bus specific I/O protocol for the driver \r
693 to use to stop the device.\r
694 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
695 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL \r
696 if NumberOfChildren is 0.\r
697\r
698 @retval EFI_SUCCESS The device was stopped.\r
699 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
700\r
701**/\r
702EFI_STATUS\r
703EFIAPI\r
704AtaBusDriverBindingStop (\r
705 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
706 IN EFI_HANDLE Controller,\r
707 IN UINTN NumberOfChildren,\r
708 IN EFI_HANDLE *ChildHandleBuffer\r
709 )\r
710{\r
711 EFI_STATUS Status;\r
712 BOOLEAN AllChildrenStopped;\r
713 UINTN Index;\r
714 ATA_BUS_DRIVER_DATA *AtaBusDriverData;\r
715\r
716 if (NumberOfChildren == 0) {\r
717 Status = gBS->OpenProtocol (\r
718 Controller,\r
719 &gEfiCallerIdGuid,\r
720 (VOID **) &AtaBusDriverData,\r
721 This->DriverBindingHandle,\r
722 Controller,\r
723 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
724 );\r
725 if (!EFI_ERROR (Status)) {\r
726 gBS->UninstallMultipleProtocolInterfaces (\r
727 Controller,\r
728 &gEfiCallerIdGuid,\r
729 AtaBusDriverData,\r
730 NULL\r
731 );\r
732 FreePool (AtaBusDriverData);\r
733 }\r
734\r
735 gBS->CloseProtocol (\r
736 Controller,\r
737 &gEfiAtaPassThruProtocolGuid,\r
738 This->DriverBindingHandle,\r
739 Controller\r
740 );\r
741\r
742 return EFI_SUCCESS;\r
743 }\r
744\r
745 AllChildrenStopped = TRUE;\r
746\r
747 for (Index = 0; Index < NumberOfChildren; Index++) {\r
748\r
749 Status = UnregisterAtaDevice (This, Controller, ChildHandleBuffer[Index]);\r
750 if (EFI_ERROR (Status)) {\r
751 AllChildrenStopped = FALSE;\r
752 }\r
753 }\r
754\r
755 if (!AllChildrenStopped) {\r
756 return EFI_DEVICE_ERROR;\r
757 }\r
758\r
759 return EFI_SUCCESS;\r
760}\r
761\r
762\r
763/**\r
764 Reset the Block Device.\r
765\r
766 @param This Indicates a pointer to the calling context.\r
767 @param ExtendedVerification Driver may perform diagnostics on reset.\r
768\r
769 @retval EFI_SUCCESS The device was reset.\r
770 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
771 not be reset.\r
772\r
773**/\r
774EFI_STATUS\r
775EFIAPI\r
776AtaBlockIoReset (\r
777 IN EFI_BLOCK_IO_PROTOCOL *This,\r
778 IN BOOLEAN ExtendedVerification\r
779 )\r
780{\r
781 EFI_STATUS Status;\r
782 ATA_DEVICE *AtaDevice;\r
783 EFI_TPL OldTpl;\r
784\r
785 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
786\r
787 AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (This);\r
788\r
789 Status = ResetAtaDevice (AtaDevice); \r
790\r
c6e797ae 791 if (EFI_ERROR (Status)) {\r
792 Status = EFI_DEVICE_ERROR;\r
793 }\r
794\r
ad86a50a 795 gBS->RestoreTPL (OldTpl);\r
796 return Status;\r
797}\r
798\r
799\r
800/**\r
801 Read/Write BufferSize bytes from Lba from/into Buffer.\r
802\r
803 @param This Indicates a pointer to the calling context.\r
804 @param MediaId The media ID that the read/write request is for.\r
805 @param Lba The starting logical block address to be read/written. The caller is\r
806 responsible for reading/writing to only legitimate locations.\r
807 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
808 @param Buffer A pointer to the destination/source buffer for the data.\r
05a44e91 809 @param IsWrite Indicates whether it is a write operation.\r
ad86a50a 810\r
811 @retval EFI_SUCCESS The data was read/written correctly to the device.\r
812 @retval EFI_WRITE_PROTECTED The device can not be read/written to.\r
813 @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.\r
814 @retval EFI_NO_MEDIA There is no media in the device.\r
815 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
816 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
817 @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid, \r
818 or the buffer is not on proper alignment.\r
819\r
820**/\r
821EFI_STATUS\r
822BlockIoReadWrite (\r
823 IN EFI_BLOCK_IO_PROTOCOL *This,\r
824 IN UINT32 MediaId,\r
825 IN EFI_LBA Lba,\r
826 IN UINTN BufferSize,\r
827 OUT VOID *Buffer,\r
828 IN BOOLEAN IsWrite\r
829 )\r
830{\r
831 ATA_DEVICE *AtaDevice;\r
832 EFI_STATUS Status;\r
833 EFI_TPL OldTpl;\r
834 EFI_BLOCK_IO_MEDIA *Media;\r
835 UINTN BlockSize;\r
836 UINTN NumberOfBlocks;\r
837 UINTN IoAlign;\r
838\r
839 //\r
840 // Check parameters.\r
841 //\r
842 if (Buffer == NULL) {\r
843 return EFI_INVALID_PARAMETER;\r
844 }\r
845\r
846 if (BufferSize == 0) {\r
847 return EFI_SUCCESS;\r
848 }\r
849\r
850 Media = This->Media;\r
851 if (MediaId != Media->MediaId) {\r
852 return EFI_MEDIA_CHANGED;\r
853 }\r
854\r
855 BlockSize = Media->BlockSize;\r
856 if ((BufferSize % BlockSize) != 0) {\r
857 return EFI_BAD_BUFFER_SIZE;\r
858 }\r
859 \r
860 NumberOfBlocks = BufferSize / BlockSize;\r
861 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
862 return EFI_INVALID_PARAMETER;\r
863 }\r
864\r
865 IoAlign = Media->IoAlign;\r
866 if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r
867 return EFI_INVALID_PARAMETER;\r
868 }\r
869\r
870 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
871\r
872 AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (This);\r
873 \r
874 //\r
875 // Invoke low level AtaDevice Access Routine.\r
876 //\r
877 Status = AccessAtaDevice (AtaDevice, Buffer, Lba, NumberOfBlocks, IsWrite);\r
878 \r
879 gBS->RestoreTPL (OldTpl);\r
880\r
881 return Status;\r
882}\r
883\r
884\r
885/**\r
886 Read BufferSize bytes from Lba into Buffer.\r
887\r
888 @param This Indicates a pointer to the calling context.\r
889 @param MediaId Id of the media, changes every time the media is replaced.\r
890 @param Lba The starting Logical Block Address to read from\r
891 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
892 @param Buffer A pointer to the destination buffer for the data. The caller is\r
893 responsible for either having implicit or explicit ownership of the buffer.\r
894\r
895 @retval EFI_SUCCESS The data was read correctly from the device.\r
896 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
897 @retval EFI_NO_MEDIA There is no media in the device.\r
898 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
899 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
900 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
901 or the buffer is not on proper alignment.\r
902\r
903**/\r
904EFI_STATUS\r
905EFIAPI\r
906AtaBlockIoReadBlocks (\r
907 IN EFI_BLOCK_IO_PROTOCOL *This,\r
908 IN UINT32 MediaId,\r
909 IN EFI_LBA Lba,\r
910 IN UINTN BufferSize,\r
911 OUT VOID *Buffer\r
912 )\r
913{\r
914 return BlockIoReadWrite (This, MediaId, Lba, BufferSize, Buffer, FALSE);\r
915}\r
916\r
917\r
918/**\r
919 Write BufferSize bytes from Lba into Buffer.\r
920\r
921 @param This Indicates a pointer to the calling context.\r
922 @param MediaId The media ID that the write request is for.\r
923 @param Lba The starting logical block address to be written. The caller is\r
924 responsible for writing to only legitimate locations.\r
925 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
926 @param Buffer A pointer to the source buffer for the data.\r
927\r
928 @retval EFI_SUCCESS The data was written correctly to the device.\r
929 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
930 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
931 @retval EFI_NO_MEDIA There is no media in the device.\r
932 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
933 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
934 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
935 or the buffer is not on proper alignment.\r
936\r
937**/\r
938EFI_STATUS\r
939EFIAPI\r
940AtaBlockIoWriteBlocks (\r
941 IN EFI_BLOCK_IO_PROTOCOL *This,\r
942 IN UINT32 MediaId,\r
943 IN EFI_LBA Lba,\r
944 IN UINTN BufferSize,\r
945 IN VOID *Buffer\r
946 )\r
947{\r
948 return BlockIoReadWrite (This, MediaId, Lba, BufferSize, Buffer, TRUE);\r
949}\r
950\r
951\r
952/**\r
953 Flush the Block Device.\r
954\r
955 @param This Indicates a pointer to the calling context.\r
956\r
957 @retval EFI_SUCCESS All outstanding data was written to the device\r
958 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
959 @retval EFI_NO_MEDIA There is no media in the device.\r
960\r
961**/\r
962EFI_STATUS\r
963EFIAPI\r
964AtaBlockIoFlushBlocks (\r
965 IN EFI_BLOCK_IO_PROTOCOL *This\r
966 )\r
967{\r
968 //\r
969 // return directly\r
970 //\r
971 return EFI_SUCCESS;\r
972}\r
973\r
974\r
975/**\r
976 Provides inquiry information for the controller type.\r
977 \r
978 This function is used by the IDE bus driver to get inquiry data. Data format\r
979 of Identify data is defined by the Interface GUID.\r
980\r
05a44e91 981 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.\r
982 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.\r
983 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.\r
ad86a50a 984\r
985 @retval EFI_SUCCESS The command was accepted without any errors.\r
986 @retval EFI_NOT_FOUND Device does not support this data class \r
987 @retval EFI_DEVICE_ERROR Error reading InquiryData from device \r
988 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough \r
989\r
990**/\r
991EFI_STATUS\r
992EFIAPI\r
993AtaDiskInfoInquiry (\r
994 IN EFI_DISK_INFO_PROTOCOL *This,\r
995 IN OUT VOID *InquiryData,\r
996 IN OUT UINT32 *InquiryDataSize\r
997 )\r
998{\r
999 return EFI_NOT_FOUND;\r
1000}\r
1001\r
1002\r
1003/**\r
1004 Provides identify information for the controller type.\r
1005\r
1006 This function is used by the IDE bus driver to get identify data. Data format\r
1007 of Identify data is defined by the Interface GUID.\r
1008\r
05a44e91 1009 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL \r
ad86a50a 1010 instance.\r
05a44e91 1011 @param[in, out] IdentifyData Pointer to a buffer for the identify data.\r
1012 @param[in, out] IdentifyDataSize Pointer to the value for the identify data\r
ad86a50a 1013 size.\r
1014\r
1015 @retval EFI_SUCCESS The command was accepted without any errors.\r
1016 @retval EFI_NOT_FOUND Device does not support this data class \r
1017 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device \r
1018 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough \r
1019\r
1020**/\r
1021EFI_STATUS\r
1022EFIAPI\r
1023AtaDiskInfoIdentify (\r
1024 IN EFI_DISK_INFO_PROTOCOL *This,\r
1025 IN OUT VOID *IdentifyData,\r
1026 IN OUT UINT32 *IdentifyDataSize\r
1027 )\r
1028{\r
1029 EFI_STATUS Status;\r
1030 ATA_DEVICE *AtaDevice;\r
1031\r
1032 AtaDevice = ATA_DEVICE_FROM_DISK_INFO (This);\r
1033\r
1034 Status = EFI_BUFFER_TOO_SMALL;\r
1035 if (*IdentifyDataSize >= sizeof (*AtaDevice->IdentifyData)) {\r
1036 Status = EFI_SUCCESS;\r
1037 CopyMem (IdentifyData, AtaDevice->IdentifyData, sizeof (*AtaDevice->IdentifyData));\r
1038 }\r
1039 *IdentifyDataSize = sizeof (*AtaDevice->IdentifyData);\r
1040\r
1041 return Status;\r
1042}\r
1043\r
1044\r
1045/**\r
1046 Provides sense data information for the controller type.\r
1047 \r
1048 This function is used by the IDE bus driver to get sense data. \r
1049 Data format of Sense data is defined by the Interface GUID.\r
1050\r
05a44e91 1051 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.\r
1052 @param[in, out] SenseData Pointer to the SenseData.\r
1053 @param[in, out] SenseDataSize Size of SenseData in bytes.\r
1054 @param[out] SenseDataNumber Pointer to the value for the sense data size.\r
ad86a50a 1055\r
1056 @retval EFI_SUCCESS The command was accepted without any errors.\r
1057 @retval EFI_NOT_FOUND Device does not support this data class.\r
1058 @retval EFI_DEVICE_ERROR Error reading SenseData from device.\r
1059 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.\r
1060\r
1061**/\r
1062EFI_STATUS\r
1063EFIAPI\r
1064AtaDiskInfoSenseData (\r
1065 IN EFI_DISK_INFO_PROTOCOL *This,\r
1066 IN OUT VOID *SenseData,\r
1067 IN OUT UINT32 *SenseDataSize,\r
1068 OUT UINT8 *SenseDataNumber\r
1069 )\r
1070{\r
1071 return EFI_NOT_FOUND;\r
1072}\r
1073\r
1074\r
1075/**\r
1076 This function is used by the IDE bus driver to get controller information.\r
1077\r
1078 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance. \r
1079 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.\r
1080 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.\r
1081\r
1082 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.\r
1083 @retval EFI_UNSUPPORTED This is not an IDE device.\r
1084\r
1085**/\r
1086EFI_STATUS\r
1087EFIAPI\r
1088AtaDiskInfoWhichIde (\r
1089 IN EFI_DISK_INFO_PROTOCOL *This,\r
1090 OUT UINT32 *IdeChannel,\r
1091 OUT UINT32 *IdeDevice\r
1092 )\r
1093{\r
1094 ATA_DEVICE *AtaDevice;\r
1095\r
1096 AtaDevice = ATA_DEVICE_FROM_DISK_INFO (This);\r
1097 *IdeChannel = AtaDevice->Port;\r
1098 *IdeDevice = AtaDevice->PortMultiplierPort;\r
1099\r
1100 return EFI_SUCCESS;\r
1101}\r
1102\r
1103\r
1104/**\r
1105 The user Entry Point for module AtaBus. The user code starts with this function.\r
1106\r
1107 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1108 @param[in] SystemTable A pointer to the EFI System Table.\r
1109\r
1110 @retval EFI_SUCCESS The entry point is executed successfully.\r
1111 @retval other Some error occurs when executing this entry point.\r
1112\r
1113**/\r
1114EFI_STATUS\r
1115EFIAPI\r
1116InitializeAtaBus(\r
1117 IN EFI_HANDLE ImageHandle,\r
1118 IN EFI_SYSTEM_TABLE *SystemTable\r
1119 )\r
1120{\r
1121 EFI_STATUS Status;\r
1122\r
1123 //\r
1124 // Install driver model protocol(s).\r
1125 //\r
1126 Status = EfiLibInstallDriverBindingComponentName2 (\r
1127 ImageHandle,\r
1128 SystemTable,\r
1129 &gAtaBusDriverBinding,\r
1130 ImageHandle,\r
1131 &gAtaBusComponentName,\r
1132 &gAtaBusComponentName2\r
1133 );\r
1134 ASSERT_EFI_ERROR (Status);\r
1135\r
1136 return Status;\r
1137}\r