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