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