]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/SataControllerDxe/SataController.c
IntelSiliconPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / SataControllerDxe / SataController.c
CommitLineData
fda951df
FT
1/** @file\r
2 This driver module produces IDE_CONTROLLER_INIT protocol for Sata Controllers.\r
3\r
d1102dba 4 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
24fee052 5 Copyright (c) 2018, ARM Ltd. All rights reserved.<BR>\r
fda951df
FT
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "SataController.h"\r
17\r
18///\r
19/// EFI_DRIVER_BINDING_PROTOCOL instance\r
20///\r
21EFI_DRIVER_BINDING_PROTOCOL gSataControllerDriverBinding = {\r
22 SataControllerSupported,\r
23 SataControllerStart,\r
24 SataControllerStop,\r
25 0xa,\r
26 NULL,\r
27 NULL\r
28};\r
29\r
30/**\r
31 Read AHCI Operation register.\r
32\r
33 @param PciIo The PCI IO protocol instance.\r
34 @param Offset The operation register offset.\r
35\r
36 @return The register content read.\r
37\r
38**/\r
39UINT32\r
40EFIAPI\r
41AhciReadReg (\r
42 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
43 IN UINT32 Offset\r
44 )\r
45{\r
46 UINT32 Data;\r
47\r
48 ASSERT (PciIo != NULL);\r
d1102dba 49\r
fda951df
FT
50 Data = 0;\r
51\r
52 PciIo->Mem.Read (\r
53 PciIo,\r
54 EfiPciIoWidthUint32,\r
55 AHCI_BAR_INDEX,\r
56 (UINT64) Offset,\r
57 1,\r
58 &Data\r
59 );\r
60\r
61 return Data;\r
62}\r
63\r
64/**\r
65 This function is used to calculate the best PIO mode supported by specific IDE device\r
66\r
67 @param IdentifyData The identify data of specific IDE device.\r
68 @param DisPioMode Disqualified PIO modes collection.\r
69 @param SelectedMode Available PIO modes collection.\r
70\r
71 @retval EFI_SUCCESS Best PIO modes are returned.\r
72 @retval EFI_UNSUPPORTED The device doesn't support PIO mode,\r
73 or all supported modes have been disqualified.\r
74**/\r
75EFI_STATUS\r
76CalculateBestPioMode (\r
77 IN EFI_IDENTIFY_DATA *IdentifyData,\r
78 IN UINT16 *DisPioMode OPTIONAL,\r
79 OUT UINT16 *SelectedMode\r
80 )\r
81{\r
82 UINT16 PioMode;\r
83 UINT16 AdvancedPioMode;\r
84 UINT16 Temp;\r
85 UINT16 Index;\r
86 UINT16 MinimumPioCycleTime;\r
87\r
88 Temp = 0xff;\r
89\r
90 PioMode = (UINT8) (((ATA5_IDENTIFY_DATA *) (&(IdentifyData->AtaData)))->pio_cycle_timing >> 8);\r
91\r
92 //\r
93 // See whether Identify Data word 64 - 70 are valid\r
94 //\r
95 if ((IdentifyData->AtaData.field_validity & 0x02) == 0x02) {\r
96\r
97 AdvancedPioMode = IdentifyData->AtaData.advanced_pio_modes;\r
98 DEBUG ((EFI_D_INFO, "CalculateBestPioMode: AdvancedPioMode = %x\n", AdvancedPioMode));\r
99\r
100 for (Index = 0; Index < 8; Index++) {\r
101 if ((AdvancedPioMode & 0x01) != 0) {\r
102 Temp = Index;\r
103 }\r
104\r
105 AdvancedPioMode >>= 1;\r
106 }\r
107\r
108 //\r
109 // If Temp is modified, mean the advanced_pio_modes is not zero;\r
110 // if Temp is not modified, mean there is no advanced PIO mode supported,\r
111 // the best PIO Mode is the value in pio_cycle_timing.\r
112 //\r
113 if (Temp != 0xff) {\r
114 AdvancedPioMode = (UINT16) (Temp + 3);\r
115 } else {\r
116 AdvancedPioMode = PioMode;\r
117 }\r
118\r
119 //\r
120 // Limit the PIO mode to at most PIO4.\r
121 //\r
122 PioMode = (UINT16) MIN (AdvancedPioMode, 4);\r
123\r
124 MinimumPioCycleTime = IdentifyData->AtaData.min_pio_cycle_time_with_flow_control;\r
125\r
126 if (MinimumPioCycleTime <= 120) {\r
127 PioMode = (UINT16) MIN (4, PioMode);\r
128 } else if (MinimumPioCycleTime <= 180) {\r
129 PioMode = (UINT16) MIN (3, PioMode);\r
130 } else if (MinimumPioCycleTime <= 240) {\r
131 PioMode = (UINT16) MIN (2, PioMode);\r
132 } else {\r
133 PioMode = 0;\r
134 }\r
135\r
136 //\r
137 // Degrade the PIO mode if the mode has been disqualified\r
138 //\r
139 if (DisPioMode != NULL) {\r
140 if (*DisPioMode < 2) {\r
141 return EFI_UNSUPPORTED; // no mode below ATA_PIO_MODE_BELOW_2\r
142 }\r
143\r
144 if (PioMode >= *DisPioMode) {\r
145 PioMode = (UINT16) (*DisPioMode - 1);\r
146 }\r
147 }\r
148\r
149 if (PioMode < 2) {\r
150 *SelectedMode = 1; // ATA_PIO_MODE_BELOW_2;\r
151 } else {\r
152 *SelectedMode = PioMode; // ATA_PIO_MODE_2 to ATA_PIO_MODE_4;\r
153 }\r
154\r
155 } else {\r
156 //\r
157 // Identify Data word 64 - 70 are not valid\r
158 // Degrade the PIO mode if the mode has been disqualified\r
159 //\r
160 if (DisPioMode != NULL) {\r
161 if (*DisPioMode < 2) {\r
162 return EFI_UNSUPPORTED; // no mode below ATA_PIO_MODE_BELOW_2\r
163 }\r
164\r
165 if (PioMode == *DisPioMode) {\r
166 PioMode--;\r
167 }\r
168 }\r
169\r
170 if (PioMode < 2) {\r
171 *SelectedMode = 1; // ATA_PIO_MODE_BELOW_2;\r
172 } else {\r
173 *SelectedMode = 2; // ATA_PIO_MODE_2;\r
174 }\r
175\r
176 }\r
177\r
178 return EFI_SUCCESS;\r
179}\r
180\r
181/**\r
182 This function is used to calculate the best UDMA mode supported by specific IDE device\r
183\r
184 @param IdentifyData The identify data of specific IDE device.\r
185 @param DisUDmaMode Disqualified UDMA modes collection.\r
186 @param SelectedMode Available UDMA modes collection.\r
187\r
188 @retval EFI_SUCCESS Best UDMA modes are returned.\r
189 @retval EFI_UNSUPPORTED The device doesn't support UDMA mode,\r
190 or all supported modes have been disqualified.\r
191**/\r
192EFI_STATUS\r
193CalculateBestUdmaMode (\r
194 IN EFI_IDENTIFY_DATA *IdentifyData,\r
195 IN UINT16 *DisUDmaMode OPTIONAL,\r
196 OUT UINT16 *SelectedMode\r
197 )\r
198{\r
199 UINT16 TempMode;\r
200 UINT16 DeviceUDmaMode;\r
201\r
202 DeviceUDmaMode = 0;\r
203\r
204 //\r
205 // Check whether the WORD 88 (supported UltraDMA by drive) is valid\r
206 //\r
207 if ((IdentifyData->AtaData.field_validity & 0x04) == 0x00) {\r
208 return EFI_UNSUPPORTED;\r
209 }\r
210\r
211 DeviceUDmaMode = IdentifyData->AtaData.ultra_dma_mode;\r
212 DEBUG ((EFI_D_INFO, "CalculateBestUdmaMode: DeviceUDmaMode = %x\n", DeviceUDmaMode));\r
213 DeviceUDmaMode &= 0x3f;\r
214 TempMode = 0; // initialize it to UDMA-0\r
215\r
216 while ((DeviceUDmaMode >>= 1) != 0) {\r
217 TempMode++;\r
218 }\r
219\r
220 //\r
221 // Degrade the UDMA mode if the mode has been disqualified\r
222 //\r
223 if (DisUDmaMode != NULL) {\r
224 if (*DisUDmaMode == 0) {\r
225 *SelectedMode = 0;\r
226 return EFI_UNSUPPORTED; // no mode below ATA_UDMA_MODE_0\r
227 }\r
228\r
229 if (TempMode >= *DisUDmaMode) {\r
230 TempMode = (UINT16) (*DisUDmaMode - 1);\r
231 }\r
232 }\r
233\r
234 //\r
235 // Possible returned mode is between ATA_UDMA_MODE_0 and ATA_UDMA_MODE_5\r
236 //\r
237 *SelectedMode = TempMode;\r
238\r
239 return EFI_SUCCESS;\r
240}\r
241\r
242/**\r
243 The Entry Point of module. It follows the standard UEFI driver model.\r
244\r
d1102dba 245 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
fda951df 246 @param[in] SystemTable A pointer to the EFI System Table.\r
d1102dba 247\r
fda951df
FT
248 @retval EFI_SUCCESS The entry point is executed successfully.\r
249 @retval other Some error occurs when executing this entry point.\r
250\r
251**/\r
252EFI_STATUS\r
253EFIAPI\r
254InitializeSataControllerDriver (\r
255 IN EFI_HANDLE ImageHandle,\r
256 IN EFI_SYSTEM_TABLE *SystemTable\r
257 )\r
258{\r
259 EFI_STATUS Status;\r
260\r
261 //\r
262 // Install driver model protocol(s).\r
263 //\r
264 Status = EfiLibInstallDriverBindingComponentName2 (\r
265 ImageHandle,\r
266 SystemTable,\r
267 &gSataControllerDriverBinding,\r
268 ImageHandle,\r
269 &gSataControllerComponentName,\r
270 &gSataControllerComponentName2\r
271 );\r
272 ASSERT_EFI_ERROR (Status);\r
273\r
274 return Status;\r
275}\r
276\r
277/**\r
278 Supported function of Driver Binding protocol for this driver.\r
279 Test to see if this driver supports ControllerHandle.\r
280\r
281 @param This Protocol instance pointer.\r
282 @param Controller Handle of device to test.\r
283 @param RemainingDevicePath A pointer to the device path.\r
284 it should be ignored by device driver.\r
285\r
286 @retval EFI_SUCCESS This driver supports this device.\r
287 @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
288 @retval other This driver does not support this device.\r
289\r
290**/\r
291EFI_STATUS\r
292EFIAPI\r
293SataControllerSupported (\r
294 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
295 IN EFI_HANDLE Controller,\r
296 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
297 )\r
298{\r
299 EFI_STATUS Status;\r
300 EFI_PCI_IO_PROTOCOL *PciIo;\r
301 PCI_TYPE00 PciData;\r
302\r
303 //\r
304 // Attempt to open PCI I/O Protocol\r
305 //\r
306 Status = gBS->OpenProtocol (\r
307 Controller,\r
308 &gEfiPciIoProtocolGuid,\r
309 (VOID **) &PciIo,\r
310 This->DriverBindingHandle,\r
311 Controller,\r
312 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
313 );\r
314 if (EFI_ERROR (Status)) {\r
315 return Status;\r
316 }\r
317\r
318 //\r
319 // Now further check the PCI header: Base Class (offset 0x0B) and\r
320 // Sub Class (offset 0x0A). This controller should be an SATA controller\r
321 //\r
322 Status = PciIo->Pci.Read (\r
323 PciIo,\r
324 EfiPciIoWidthUint8,\r
325 PCI_CLASSCODE_OFFSET,\r
326 sizeof (PciData.Hdr.ClassCode),\r
327 PciData.Hdr.ClassCode\r
328 );\r
329 if (EFI_ERROR (Status)) {\r
330 return EFI_UNSUPPORTED;\r
331 }\r
332\r
333 if (IS_PCI_IDE (&PciData) || IS_PCI_SATADPA (&PciData)) {\r
334 return EFI_SUCCESS;\r
335 }\r
336\r
337 return EFI_UNSUPPORTED;\r
338}\r
339\r
340/**\r
d1102dba 341 This routine is called right after the .Supported() called and\r
fda951df
FT
342 Start this driver on ControllerHandle.\r
343\r
344 @param This Protocol instance pointer.\r
345 @param Controller Handle of device to bind driver to.\r
346 @param RemainingDevicePath A pointer to the device path.\r
347 it should be ignored by device driver.\r
348\r
349 @retval EFI_SUCCESS This driver is added to this device.\r
350 @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
351 @retval other Some error occurs when binding this driver to this device.\r
352\r
353**/\r
354EFI_STATUS\r
355EFIAPI\r
356SataControllerStart (\r
357 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
358 IN EFI_HANDLE Controller,\r
359 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
360 )\r
361{\r
362 EFI_STATUS Status;\r
363 EFI_PCI_IO_PROTOCOL *PciIo;\r
364 PCI_TYPE00 PciData;\r
365 EFI_SATA_CONTROLLER_PRIVATE_DATA *Private;\r
366 UINT32 Data32;\r
367 UINTN TotalCount;\r
24fee052 368 UINT64 Supports;\r
aa4240ed 369 UINT8 MaxPortNumber;\r
fda951df
FT
370\r
371 DEBUG ((EFI_D_INFO, "SataControllerStart start\n"));\r
372\r
373 Private = NULL;\r
374\r
375 //\r
376 // Now test and open PCI I/O Protocol\r
377 //\r
378 Status = gBS->OpenProtocol (\r
379 Controller,\r
380 &gEfiPciIoProtocolGuid,\r
381 (VOID **) &PciIo,\r
382 This->DriverBindingHandle,\r
383 Controller,\r
384 EFI_OPEN_PROTOCOL_BY_DRIVER\r
385 );\r
386 if (EFI_ERROR (Status)) {\r
387 DEBUG ((EFI_D_ERROR, "SataControllerStart error. return status = %r\n", Status));\r
388 return Status;\r
389 }\r
390\r
391 //\r
392 // Allocate Sata Private Data structure\r
393 //\r
394 Private = AllocateZeroPool (sizeof (EFI_SATA_CONTROLLER_PRIVATE_DATA));\r
395 if (Private == NULL) {\r
396 Status = EFI_OUT_OF_RESOURCES;\r
397 goto Done;\r
398 }\r
399\r
400 //\r
401 // Initialize Sata Private Data\r
402 //\r
403 Private->Signature = SATA_CONTROLLER_SIGNATURE;\r
404 Private->PciIo = PciIo;\r
405 Private->IdeInit.GetChannelInfo = IdeInitGetChannelInfo;\r
406 Private->IdeInit.NotifyPhase = IdeInitNotifyPhase;\r
407 Private->IdeInit.SubmitData = IdeInitSubmitData;\r
408 Private->IdeInit.DisqualifyMode = IdeInitDisqualifyMode;\r
409 Private->IdeInit.CalculateMode = IdeInitCalculateMode;\r
410 Private->IdeInit.SetTiming = IdeInitSetTiming;\r
411 Private->IdeInit.EnumAll = SATA_ENUMER_ALL;\r
24fee052
SM
412 Private->PciAttributesChanged = FALSE;\r
413\r
414 //\r
415 // Save original PCI attributes\r
416 //\r
417 Status = PciIo->Attributes (\r
418 PciIo,\r
419 EfiPciIoAttributeOperationGet,\r
420 0,\r
421 &Private->OriginalPciAttributes\r
422 );\r
423 if (EFI_ERROR (Status)) {\r
424 goto Done;\r
425 }\r
426\r
427 DEBUG ((\r
428 EFI_D_INFO,\r
429 "Original PCI Attributes = 0x%llx\n",\r
430 Private->OriginalPciAttributes\r
431 ));\r
432\r
433 Status = PciIo->Attributes (\r
434 PciIo,\r
435 EfiPciIoAttributeOperationSupported,\r
436 0,\r
437 &Supports\r
438 );\r
439 if (EFI_ERROR (Status)) {\r
440 goto Done;\r
441 }\r
442\r
443 DEBUG ((EFI_D_INFO, "Supported PCI Attributes = 0x%llx\n", Supports));\r
444\r
445 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
446 Status = PciIo->Attributes (\r
447 PciIo,\r
448 EfiPciIoAttributeOperationEnable,\r
449 Supports,\r
450 NULL\r
451 );\r
452 if (EFI_ERROR (Status)) {\r
453 goto Done;\r
454 }\r
455\r
456 DEBUG ((EFI_D_INFO, "Enabled PCI Attributes = 0x%llx\n", Supports));\r
457 Private->PciAttributesChanged = TRUE;\r
fda951df
FT
458\r
459 Status = PciIo->Pci.Read (\r
460 PciIo,\r
461 EfiPciIoWidthUint8,\r
462 PCI_CLASSCODE_OFFSET,\r
463 sizeof (PciData.Hdr.ClassCode),\r
464 PciData.Hdr.ClassCode\r
465 );\r
24fee052
SM
466 if (EFI_ERROR (Status)) {\r
467 ASSERT (FALSE);\r
468 goto Done;\r
469 }\r
fda951df
FT
470\r
471 if (IS_PCI_IDE (&PciData)) {\r
472 Private->IdeInit.ChannelCount = IDE_MAX_CHANNEL;\r
473 Private->DeviceCount = IDE_MAX_DEVICES;\r
474 } else if (IS_PCI_SATADPA (&PciData)) {\r
475 //\r
aa4240ed
SZ
476 // Read Ports Implemented(PI) to calculate max port number (0 based).\r
477 //\r
478 Data32 = AhciReadReg (PciIo, R_AHCI_PI);\r
479 DEBUG ((DEBUG_INFO, "Ports Implemented(PI) = 0x%x\n", Data32));\r
480 if (Data32 == 0) {\r
481 Status = EFI_UNSUPPORTED;\r
482 goto Done;\r
483 }\r
484 MaxPortNumber = 31;\r
485 while (MaxPortNumber > 0) {\r
cd69c873 486 if ((Data32 & ((UINT32)1 << MaxPortNumber)) != 0) {\r
aa4240ed
SZ
487 break;\r
488 }\r
489 MaxPortNumber--;\r
490 }\r
491 //\r
492 // Make the ChannelCount equal to the max port number (0 based) plus 1.\r
493 //\r
494 Private->IdeInit.ChannelCount = MaxPortNumber + 1;\r
495\r
496 //\r
497 // Read HBA Capabilities(CAP) to get Supports Port Multiplier(SPM).\r
fda951df
FT
498 //\r
499 Data32 = AhciReadReg (PciIo, R_AHCI_CAP);\r
aa4240ed 500 DEBUG ((DEBUG_INFO, "HBA Capabilities(CAP) = 0x%x\n", Data32));\r
fda951df
FT
501 Private->DeviceCount = AHCI_MAX_DEVICES;\r
502 if ((Data32 & B_AHCI_CAP_SPM) == B_AHCI_CAP_SPM) {\r
503 Private->DeviceCount = AHCI_MULTI_MAX_DEVICES;\r
504 }\r
505 }\r
506\r
507 TotalCount = (UINTN) (Private->IdeInit.ChannelCount) * (UINTN) (Private->DeviceCount);\r
508 Private->DisqualifiedModes = AllocateZeroPool ((sizeof (EFI_ATA_COLLECTIVE_MODE)) * TotalCount);\r
509 if (Private->DisqualifiedModes == NULL) {\r
510 Status = EFI_OUT_OF_RESOURCES;\r
511 goto Done;\r
512 }\r
513\r
514 Private->IdentifyData = AllocateZeroPool ((sizeof (EFI_IDENTIFY_DATA)) * TotalCount);\r
515 if (Private->IdentifyData == NULL) {\r
516 Status = EFI_OUT_OF_RESOURCES;\r
517 goto Done;\r
518 }\r
519\r
520 Private->IdentifyValid = AllocateZeroPool ((sizeof (BOOLEAN)) * TotalCount);\r
521 if (Private->IdentifyValid == NULL) {\r
522 Status = EFI_OUT_OF_RESOURCES;\r
523 goto Done;\r
524 }\r
525\r
526 //\r
527 // Install IDE Controller Init Protocol to this instance\r
528 //\r
529 Status = gBS->InstallMultipleProtocolInterfaces (\r
530 &Controller,\r
531 &gEfiIdeControllerInitProtocolGuid,\r
532 &(Private->IdeInit),\r
533 NULL\r
534 );\r
535\r
536Done:\r
537 if (EFI_ERROR (Status)) {\r
538\r
539 gBS->CloseProtocol (\r
540 Controller,\r
541 &gEfiPciIoProtocolGuid,\r
542 This->DriverBindingHandle,\r
543 Controller\r
544 );\r
545 if (Private != NULL) {\r
546 if (Private->DisqualifiedModes != NULL) {\r
547 FreePool (Private->DisqualifiedModes);\r
548 }\r
549 if (Private->IdentifyData != NULL) {\r
550 FreePool (Private->IdentifyData);\r
551 }\r
552 if (Private->IdentifyValid != NULL) {\r
553 FreePool (Private->IdentifyValid);\r
554 }\r
24fee052
SM
555 if (Private->PciAttributesChanged) {\r
556 //\r
557 // Restore original PCI attributes\r
558 //\r
559 PciIo->Attributes (\r
560 PciIo,\r
561 EfiPciIoAttributeOperationSet,\r
562 Private->OriginalPciAttributes,\r
563 NULL\r
564 );\r
565 }\r
fda951df
FT
566 FreePool (Private);\r
567 }\r
568 }\r
569\r
570 DEBUG ((EFI_D_INFO, "SataControllerStart end with %r\n", Status));\r
571\r
572 return Status;\r
573}\r
574\r
575/**\r
576 Stop this driver on ControllerHandle.\r
577\r
578 @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
579 @param Controller A handle to the device being stopped.\r
580 @param NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
d1102dba 581 @param ChildHandleBuffer An array of child handles to be freed.\r
fda951df
FT
582\r
583 @retval EFI_SUCCESS This driver is removed from this device.\r
584 @retval other Some error occurs when removing this driver from this device.\r
585\r
586**/\r
587EFI_STATUS\r
588EFIAPI\r
589SataControllerStop (\r
590 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
591 IN EFI_HANDLE Controller,\r
592 IN UINTN NumberOfChildren,\r
593 IN EFI_HANDLE *ChildHandleBuffer\r
594 )\r
595{\r
596 EFI_STATUS Status;\r
597 EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
598 EFI_SATA_CONTROLLER_PRIVATE_DATA *Private;\r
599\r
600 //\r
601 // Open the produced protocol\r
602 //\r
603 Status = gBS->OpenProtocol (\r
604 Controller,\r
605 &gEfiIdeControllerInitProtocolGuid,\r
606 (VOID **) &IdeInit,\r
607 This->DriverBindingHandle,\r
608 Controller,\r
609 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
610 );\r
611 if (EFI_ERROR (Status)) {\r
612 return EFI_UNSUPPORTED;\r
613 }\r
614\r
615 Private = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (IdeInit);\r
616 ASSERT (Private != NULL);\r
617\r
618 //\r
619 // Uninstall the IDE Controller Init Protocol from this instance\r
620 //\r
621 Status = gBS->UninstallMultipleProtocolInterfaces (\r
622 Controller,\r
623 &gEfiIdeControllerInitProtocolGuid,\r
624 &(Private->IdeInit),\r
625 NULL\r
626 );\r
627 if (EFI_ERROR (Status)) {\r
628 return Status;\r
629 }\r
630\r
631 if (Private != NULL) {\r
632 if (Private->DisqualifiedModes != NULL) {\r
633 FreePool (Private->DisqualifiedModes);\r
634 }\r
635 if (Private->IdentifyData != NULL) {\r
636 FreePool (Private->IdentifyData);\r
637 }\r
638 if (Private->IdentifyValid != NULL) {\r
639 FreePool (Private->IdentifyValid);\r
640 }\r
24fee052
SM
641 if (Private->PciAttributesChanged) {\r
642 //\r
643 // Restore original PCI attributes\r
644 //\r
645 Private->PciIo->Attributes (\r
646 Private->PciIo,\r
647 EfiPciIoAttributeOperationSet,\r
648 Private->OriginalPciAttributes,\r
649 NULL\r
650 );\r
651 }\r
fda951df
FT
652 FreePool (Private);\r
653 }\r
654\r
655 //\r
656 // Close protocols opened by Sata Controller driver\r
657 //\r
658 return gBS->CloseProtocol (\r
659 Controller,\r
660 &gEfiPciIoProtocolGuid,\r
661 This->DriverBindingHandle,\r
662 Controller\r
663 );\r
664}\r
665\r
666/**\r
667 Calculate the flat array subscript of a (Channel, Device) pair.\r
668\r
669 @param[in] Private The private data structure corresponding to the\r
670 SATA controller that attaches the device for\r
671 which the flat array subscript is being\r
672 calculated.\r
673\r
674 @param[in] Channel The channel (ie. port) number on the SATA\r
675 controller that the device is attached to.\r
676\r
677 @param[in] Device The device number on the channel.\r
678\r
679 @return The flat array subscript suitable for indexing DisqualifiedModes,\r
680 IdentifyData, and IdentifyValid.\r
681**/\r
682STATIC\r
683UINTN\r
684FlatDeviceIndex (\r
685 IN CONST EFI_SATA_CONTROLLER_PRIVATE_DATA *Private,\r
686 IN UINTN Channel,\r
687 IN UINTN Device\r
688 )\r
689{\r
690 ASSERT (Private != NULL);\r
691 ASSERT (Channel < Private->IdeInit.ChannelCount);\r
692 ASSERT (Device < Private->DeviceCount);\r
693\r
694 return Channel * Private->DeviceCount + Device;\r
695}\r
696\r
697//\r
698// Interface functions of IDE_CONTROLLER_INIT protocol\r
699//\r
700/**\r
701 Returns the information about the specified IDE channel.\r
d1102dba 702\r
fda951df 703 This function can be used to obtain information about a particular IDE channel.\r
d1102dba
LG
704 The driver entity uses this information during the enumeration process.\r
705\r
706 If Enabled is set to FALSE, the driver entity will not scan the channel. Note\r
fda951df 707 that it will not prevent an operating system driver from scanning the channel.\r
d1102dba
LG
708\r
709 For most of today's controllers, MaxDevices will either be 1 or 2. For SATA\r
710 controllers, this value will always be 1. SATA configurations can contain SATA\r
fda951df 711 port multipliers. SATA port multipliers behave like SATA bridges and can support\r
d1102dba
LG
712 up to 16 devices on the other side. If a SATA port out of the IDE controller\r
713 is connected to a port multiplier, MaxDevices will be set to the number of SATA\r
714 devices that the port multiplier supports. Because today's port multipliers\r
715 support up to fifteen SATA devices, this number can be as large as fifteen. The IDE\r
716 bus driver is required to scan for the presence of port multipliers behind an SATA\r
717 controller and enumerate up to MaxDevices number of devices behind the port\r
718 multiplier.\r
719\r
720 In this context, the devices behind a port multiplier constitute a channel.\r
721\r
fda951df
FT
722 @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.\r
723 @param[in] Channel Zero-based channel number.\r
d1102dba 724 @param[out] Enabled TRUE if this channel is enabled. Disabled channels\r
fda951df
FT
725 are not scanned to see if any devices are present.\r
726 @param[out] MaxDevices The maximum number of IDE devices that the bus driver\r
d1102dba
LG
727 can expect on this channel. For the ATA/ATAPI\r
728 specification, version 6, this number will either be\r
729 one or two. For Serial ATA (SATA) configurations with a\r
fda951df
FT
730 port multiplier, this number can be as large as fifteen.\r
731\r
732 @retval EFI_SUCCESS Information was returned without any errors.\r
733 @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).\r
734\r
735**/\r
736EFI_STATUS\r
737EFIAPI\r
738IdeInitGetChannelInfo (\r
739 IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,\r
740 IN UINT8 Channel,\r
741 OUT BOOLEAN *Enabled,\r
742 OUT UINT8 *MaxDevices\r
743 )\r
744{\r
745 EFI_SATA_CONTROLLER_PRIVATE_DATA *Private;\r
746 Private = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (This);\r
747 ASSERT (Private != NULL);\r
748\r
749 if (Channel < This->ChannelCount) {\r
750 *Enabled = TRUE;\r
751 *MaxDevices = Private->DeviceCount;\r
752 return EFI_SUCCESS;\r
753 }\r
754\r
755 *Enabled = FALSE;\r
756 return EFI_INVALID_PARAMETER;\r
757}\r
758\r
759/**\r
760 The notifications from the driver entity that it is about to enter a certain\r
761 phase of the IDE channel enumeration process.\r
d1102dba
LG
762\r
763 This function can be used to notify the IDE controller driver to perform\r
764 specific actions, including any chipset-specific initialization, so that the\r
765 chipset is ready to enter the next phase. Seven notification points are defined\r
766 at this time.\r
767\r
768 More synchronization points may be added as required in the future.\r
fda951df
FT
769\r
770 @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL\r
771 instance.\r
772 @param[in] Phase The phase during enumeration.\r
773 @param[in] Channel Zero-based channel number.\r
774\r
775 @retval EFI_SUCCESS The notification was accepted without any errors.\r
776 @retval EFI_UNSUPPORTED Phase is not supported.\r
777 @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).\r
d1102dba
LG
778 @retval EFI_NOT_READY This phase cannot be entered at this time; for\r
779 example, an attempt was made to enter a Phase\r
780 without having entered one or more previous\r
fda951df
FT
781 Phase.\r
782\r
783**/\r
784EFI_STATUS\r
785EFIAPI\r
786IdeInitNotifyPhase (\r
787 IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,\r
788 IN EFI_IDE_CONTROLLER_ENUM_PHASE Phase,\r
789 IN UINT8 Channel\r
790 )\r
791{\r
792 return EFI_SUCCESS;\r
793}\r
794\r
795/**\r
796 Submits the device information to the IDE controller driver.\r
797\r
d1102dba
LG
798 This function is used by the driver entity to pass detailed information about\r
799 a particular device to the IDE controller driver. The driver entity obtains\r
fda951df 800 this information by issuing an ATA or ATAPI IDENTIFY_DEVICE command. IdentifyData\r
d1102dba
LG
801 is the pointer to the response data buffer. The IdentifyData buffer is owned\r
802 by the driver entity, and the IDE controller driver must make a local copy\r
803 of the entire buffer or parts of the buffer as needed. The original IdentifyData\r
fda951df 804 buffer pointer may not be valid when\r
d1102dba 805\r
fda951df
FT
806 - EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() or\r
807 - EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() is called at a later point.\r
d1102dba
LG
808\r
809 The IDE controller driver may consult various fields of EFI_IDENTIFY_DATA to\r
810 compute the optimum mode for the device. These fields are not limited to the\r
811 timing information. For example, an implementation of the IDE controller driver\r
812 may examine the vendor and type/mode field to match known bad drives.\r
813\r
814 The driver entity may submit drive information in any order, as long as it\r
815 submits information for all the devices belonging to the enumeration group\r
fda951df
FT
816 before EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() is called for any device\r
817 in that enumeration group. If a device is absent, EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData()\r
d1102dba
LG
818 should be called with IdentifyData set to NULL. The IDE controller driver may\r
819 not have any other mechanism to know whether a device is present or not. Therefore,\r
820 setting IdentifyData to NULL does not constitute an error condition.\r
821 EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() can be called only once for a\r
822 given (Channel, Device) pair.\r
823\r
fda951df
FT
824 @param[in] This A pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.\r
825 @param[in] Channel Zero-based channel number.\r
826 @param[in] Device Zero-based device number on the Channel.\r
827 @param[in] IdentifyData The device's response to the ATA IDENTIFY_DEVICE command.\r
828\r
829 @retval EFI_SUCCESS The information was accepted without any errors.\r
830 @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).\r
831 @retval EFI_INVALID_PARAMETER Device is invalid.\r
832\r
833**/\r
834EFI_STATUS\r
835EFIAPI\r
836IdeInitSubmitData (\r
837 IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,\r
838 IN UINT8 Channel,\r
839 IN UINT8 Device,\r
840 IN EFI_IDENTIFY_DATA *IdentifyData\r
841 )\r
842{\r
843 EFI_SATA_CONTROLLER_PRIVATE_DATA *Private;\r
844 UINTN DeviceIndex;\r
845\r
846 Private = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (This);\r
847 ASSERT (Private != NULL);\r
848\r
849 if ((Channel >= This->ChannelCount) || (Device >= Private->DeviceCount)) {\r
850 return EFI_INVALID_PARAMETER;\r
851 }\r
852\r
853 DeviceIndex = FlatDeviceIndex (Private, Channel, Device);\r
854\r
855 //\r
856 // Make a local copy of device's IdentifyData and mark the valid flag\r
857 //\r
858 if (IdentifyData != NULL) {\r
859 CopyMem (\r
860 &(Private->IdentifyData[DeviceIndex]),\r
861 IdentifyData,\r
862 sizeof (EFI_IDENTIFY_DATA)\r
863 );\r
864\r
865 Private->IdentifyValid[DeviceIndex] = TRUE;\r
866 } else {\r
867 Private->IdentifyValid[DeviceIndex] = FALSE;\r
868 }\r
869\r
870 return EFI_SUCCESS;\r
871}\r
872\r
873/**\r
874 Disqualifies specific modes for an IDE device.\r
875\r
d1102dba 876 This function allows the driver entity or other drivers (such as platform\r
fda951df 877 drivers) to reject certain timing modes and request the IDE controller driver\r
d1102dba
LG
878 to recalculate modes. This function allows the driver entity and the IDE\r
879 controller driver to negotiate the timings on a per-device basis. This function\r
880 is useful in the case of drives that lie about their capabilities. An example\r
881 is when the IDE device fails to accept the timing modes that are calculated\r
fda951df
FT
882 by the IDE controller driver based on the response to the Identify Drive command.\r
883\r
d1102dba
LG
884 If the driver entity does not want to limit the ATA timing modes and leave that\r
885 decision to the IDE controller driver, it can either not call this function for\r
886 the given device or call this function and set the Valid flag to FALSE for all\r
fda951df 887 modes that are listed in EFI_ATA_COLLECTIVE_MODE.\r
d1102dba
LG
888\r
889 The driver entity may disqualify modes for a device in any order and any number\r
fda951df 890 of times.\r
d1102dba
LG
891\r
892 This function can be called multiple times to invalidate multiple modes of the\r
893 same type (e.g., Programmed Input/Output [PIO] modes 3 and 4). See the ATA/ATAPI\r
894 specification for more information on PIO modes.\r
895\r
fda951df
FT
896 For Serial ATA (SATA) controllers, this member function can be used to disqualify\r
897 a higher transfer rate mode on a given channel. For example, a platform driver\r
d1102dba 898 may inform the IDE controller driver to not use second-generation (Gen2) speeds\r
fda951df 899 for a certain SATA drive.\r
d1102dba 900\r
fda951df
FT
901 @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.\r
902 @param[in] Channel The zero-based channel number.\r
903 @param[in] Device The zero-based device number on the Channel.\r
904 @param[in] BadModes The modes that the device does not support and that\r
905 should be disqualified.\r
906\r
907 @retval EFI_SUCCESS The modes were accepted without any errors.\r
908 @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).\r
909 @retval EFI_INVALID_PARAMETER Device is invalid.\r
910 @retval EFI_INVALID_PARAMETER IdentifyData is NULL.\r
d1102dba 911\r
fda951df
FT
912**/\r
913EFI_STATUS\r
914EFIAPI\r
915IdeInitDisqualifyMode (\r
916 IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,\r
917 IN UINT8 Channel,\r
918 IN UINT8 Device,\r
919 IN EFI_ATA_COLLECTIVE_MODE *BadModes\r
920 )\r
921{\r
922 EFI_SATA_CONTROLLER_PRIVATE_DATA *Private;\r
923 UINTN DeviceIndex;\r
924\r
925 Private = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (This);\r
926 ASSERT (Private != NULL);\r
927\r
928 if ((Channel >= This->ChannelCount) || (BadModes == NULL) || (Device >= Private->DeviceCount)) {\r
929 return EFI_INVALID_PARAMETER;\r
930 }\r
931\r
932 DeviceIndex = FlatDeviceIndex (Private, Channel, Device);\r
933\r
934 //\r
935 // Record the disqualified modes per channel per device. From ATA/ATAPI spec,\r
936 // if a mode is not supported, the modes higher than it is also not supported.\r
937 //\r
938 CopyMem (\r
939 &(Private->DisqualifiedModes[DeviceIndex]),\r
940 BadModes,\r
941 sizeof (EFI_ATA_COLLECTIVE_MODE)\r
942 );\r
943\r
944 return EFI_SUCCESS;\r
945}\r
946\r
947/**\r
948 Returns the information about the optimum modes for the specified IDE device.\r
949\r
950 This function is used by the driver entity to obtain the optimum ATA modes for\r
d1102dba 951 a specific device. The IDE controller driver takes into account the following\r
fda951df
FT
952 while calculating the mode:\r
953 - The IdentifyData inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData()\r
954 - The BadModes inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode()\r
955\r
d1102dba
LG
956 The driver entity is required to call EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData()\r
957 for all the devices that belong to an enumeration group before calling\r
958 EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() for any device in the same group.\r
959\r
960 The IDE controller driver will use controller- and possibly platform-specific\r
961 algorithms to arrive at SupportedModes. The IDE controller may base its\r
962 decision on user preferences and other considerations as well. This function\r
963 may be called multiple times because the driver entity may renegotiate the mode\r
fda951df 964 with the IDE controller driver using EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode().\r
d1102dba
LG
965\r
966 The driver entity may collect timing information for various devices in any\r
fda951df 967 order. The driver entity is responsible for making sure that all the dependencies\r
d1102dba
LG
968 are satisfied. For example, the SupportedModes information for device A that\r
969 was previously returned may become stale after a call to\r
fda951df 970 EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() for device B.\r
d1102dba
LG
971\r
972 The buffer SupportedModes is allocated by the callee because the caller does\r
973 not necessarily know the size of the buffer. The type EFI_ATA_COLLECTIVE_MODE\r
974 is defined in a way that allows for future extensibility and can be of variable\r
975 length. This memory pool should be deallocated by the caller when it is no\r
976 longer necessary.\r
977\r
978 The IDE controller driver for a Serial ATA (SATA) controller can use this\r
979 member function to force a lower speed (first-generation [Gen1] speeds on a\r
980 second-generation [Gen2]-capable hardware). The IDE controller driver can\r
981 also allow the driver entity to stay with the speed that has been negotiated\r
fda951df 982 by the physical layer.\r
d1102dba 983\r
fda951df
FT
984 @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.\r
985 @param[in] Channel A zero-based channel number.\r
986 @param[in] Device A zero-based device number on the Channel.\r
987 @param[out] SupportedModes The optimum modes for the device.\r
988\r
989 @retval EFI_SUCCESS SupportedModes was returned.\r
990 @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).\r
d1102dba 991 @retval EFI_INVALID_PARAMETER Device is invalid.\r
fda951df 992 @retval EFI_INVALID_PARAMETER SupportedModes is NULL.\r
d1102dba
LG
993 @retval EFI_NOT_READY Modes cannot be calculated due to a lack of\r
994 data. This error may happen if\r
995 EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData()\r
996 and EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyData()\r
997 were not called for at least one drive in the\r
fda951df
FT
998 same enumeration group.\r
999\r
1000**/\r
1001EFI_STATUS\r
1002EFIAPI\r
1003IdeInitCalculateMode (\r
1004 IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,\r
1005 IN UINT8 Channel,\r
1006 IN UINT8 Device,\r
1007 OUT EFI_ATA_COLLECTIVE_MODE **SupportedModes\r
1008 )\r
1009{\r
1010 EFI_SATA_CONTROLLER_PRIVATE_DATA *Private;\r
1011 EFI_IDENTIFY_DATA *IdentifyData;\r
1012 BOOLEAN IdentifyValid;\r
1013 EFI_ATA_COLLECTIVE_MODE *DisqualifiedModes;\r
1014 UINT16 SelectedMode;\r
1015 EFI_STATUS Status;\r
1016 UINTN DeviceIndex;\r
1017\r
1018 Private = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (This);\r
1019 ASSERT (Private != NULL);\r
1020\r
1021 if ((Channel >= This->ChannelCount) || (SupportedModes == NULL) || (Device >= Private->DeviceCount)) {\r
1022 return EFI_INVALID_PARAMETER;\r
1023 }\r
1024\r
1025 *SupportedModes = AllocateZeroPool (sizeof (EFI_ATA_COLLECTIVE_MODE));\r
1026 if (*SupportedModes == NULL) {\r
1027 ASSERT (*SupportedModes != NULL);\r
1028 return EFI_OUT_OF_RESOURCES;\r
1029 }\r
1030\r
1031 DeviceIndex = FlatDeviceIndex (Private, Channel, Device);\r
1032\r
1033 IdentifyData = &(Private->IdentifyData[DeviceIndex]);\r
1034 IdentifyValid = Private->IdentifyValid[DeviceIndex];\r
1035 DisqualifiedModes = &(Private->DisqualifiedModes[DeviceIndex]);\r
1036\r
1037 //\r
1038 // Make sure we've got the valid identify data of the device from SubmitData()\r
1039 //\r
1040 if (!IdentifyValid) {\r
1041 FreePool (*SupportedModes);\r
1042 return EFI_NOT_READY;\r
1043 }\r
1044\r
1045 Status = CalculateBestPioMode (\r
1046 IdentifyData,\r
1047 (DisqualifiedModes->PioMode.Valid ? ((UINT16 *) &(DisqualifiedModes->PioMode.Mode)) : NULL),\r
1048 &SelectedMode\r
1049 );\r
1050 if (!EFI_ERROR (Status)) {\r
1051 (*SupportedModes)->PioMode.Valid = TRUE;\r
1052 (*SupportedModes)->PioMode.Mode = SelectedMode;\r
1053\r
1054 } else {\r
1055 (*SupportedModes)->PioMode.Valid = FALSE;\r
1056 }\r
1057 DEBUG ((EFI_D_INFO, "IdeInitCalculateMode: PioMode = %x\n", (*SupportedModes)->PioMode.Mode));\r
1058\r
1059 Status = CalculateBestUdmaMode (\r
1060 IdentifyData,\r
1061 (DisqualifiedModes->UdmaMode.Valid ? ((UINT16 *) &(DisqualifiedModes->UdmaMode.Mode)) : NULL),\r
1062 &SelectedMode\r
1063 );\r
1064\r
1065 if (!EFI_ERROR (Status)) {\r
1066 (*SupportedModes)->UdmaMode.Valid = TRUE;\r
1067 (*SupportedModes)->UdmaMode.Mode = SelectedMode;\r
1068\r
1069 } else {\r
1070 (*SupportedModes)->UdmaMode.Valid = FALSE;\r
1071 }\r
1072 DEBUG ((EFI_D_INFO, "IdeInitCalculateMode: UdmaMode = %x\n", (*SupportedModes)->UdmaMode.Mode));\r
1073\r
1074 //\r
1075 // The modes other than PIO and UDMA are not supported\r
1076 //\r
1077 return EFI_SUCCESS;\r
1078}\r
1079\r
1080/**\r
1081 Commands the IDE controller driver to program the IDE controller hardware\r
1082 so that the specified device can operate at the specified mode.\r
1083\r
d1102dba
LG
1084 This function is used by the driver entity to instruct the IDE controller\r
1085 driver to program the IDE controller hardware to the specified modes. This\r
1086 function can be called only once for a particular device. For a Serial ATA\r
fda951df
FT
1087 (SATA) Advanced Host Controller Interface (AHCI) controller, no controller-\r
1088 specific programming may be required.\r
1089\r
1090 @param[in] This Pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance.\r
1091 @param[in] Channel Zero-based channel number.\r
1092 @param[in] Device Zero-based device number on the Channel.\r
1093 @param[in] Modes The modes to set.\r
1094\r
1095 @retval EFI_SUCCESS The command was accepted without any errors.\r
1096 @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount).\r
1097 @retval EFI_INVALID_PARAMETER Device is invalid.\r
1098 @retval EFI_NOT_READY Modes cannot be set at this time due to lack of data.\r
1099 @retval EFI_DEVICE_ERROR Modes cannot be set due to hardware failure.\r
1100 The driver entity should not use this device.\r
1101\r
1102**/\r
1103EFI_STATUS\r
1104EFIAPI\r
1105IdeInitSetTiming (\r
1106 IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This,\r
1107 IN UINT8 Channel,\r
1108 IN UINT8 Device,\r
1109 IN EFI_ATA_COLLECTIVE_MODE *Modes\r
1110 )\r
1111{\r
1112 return EFI_SUCCESS;\r
1113}\r
1114\r