]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Drivers/SataSiI3132Dxe/SiI3132AtaPassThru.c
EmbeddedPkg: Fix various typos
[mirror_edk2.git] / EmbeddedPkg / Drivers / SataSiI3132Dxe / SiI3132AtaPassThru.c
1 /** @file
2 *
3 * Copyright (c) 2011-2015, ARM Limited. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-2-Clause-Patent
6 *
7 **/
8
9 #include "SataSiI3132.h"
10
11 #include <IndustryStandard/Atapi.h>
12 #include <Library/DevicePathLib.h>
13
14 SATA_SI3132_DEVICE*
15 GetSataDevice (
16 IN SATA_SI3132_INSTANCE* SataInstance,
17 IN UINT16 Port,
18 IN UINT16 PortMultiplierPort
19 ) {
20 LIST_ENTRY *List;
21 SATA_SI3132_PORT *SataPort;
22 SATA_SI3132_DEVICE *SataDevice;
23
24 if (Port >= SATA_SII3132_MAXPORT) {
25 return NULL;
26 }
27
28 SataPort = &(SataInstance->Ports[Port]);
29 List = SataPort->Devices.ForwardLink;
30
31 while (List != &SataPort->Devices) {
32 SataDevice = (SATA_SI3132_DEVICE*)List;
33 if (SataDevice->Index == PortMultiplierPort) {
34 return SataDevice;
35 }
36 List = List->ForwardLink;
37 }
38 return NULL;
39 }
40
41 EFI_STATUS
42 SiI3132AtaPassThruCommand (
43 IN SATA_SI3132_INSTANCE *SataSiI3132Instance,
44 IN SATA_SI3132_PORT *SataPort,
45 IN UINT16 PortMultiplierPort,
46 IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,
47 IN EFI_EVENT Event OPTIONAL
48 )
49 {
50 SATA_SI3132_DEVICE *SataDevice;
51 EFI_PHYSICAL_ADDRESS PhysInDataBuffer;
52 UINTN InDataBufferLength = 0;
53 EFI_PHYSICAL_ADDRESS PhysOutDataBuffer;
54 UINTN OutDataBufferLength;
55 CONST UINTN EmptySlot = 0;
56 UINTN Control = PRB_CTRL_ATA;
57 UINTN Protocol = 0;
58 UINT32 Value32, Error, Timeout = 0;
59 CONST UINT32 IrqMask = (SII3132_PORT_INT_CMDCOMPL | SII3132_PORT_INT_CMDERR) << 16;
60 EFI_STATUS Status;
61 VOID* PciAllocMapping = NULL;
62 EFI_PCI_IO_PROTOCOL *PciIo;
63
64 PciIo = SataSiI3132Instance->PciIo;
65 ZeroMem (SataPort->HostPRB, sizeof (SATA_SI3132_PRB));
66
67 // Construct Si3132 PRB
68 switch (Packet->Protocol) {
69 case EFI_ATA_PASS_THRU_PROTOCOL_ATA_HARDWARE_RESET:
70 ASSERT (0); //TODO: Implement me!
71 break;
72 case EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET:
73 SATA_TRACE ("SiI3132AtaPassThru() EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET");
74 Control = PRB_CTRL_SRST;
75
76 if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) {
77 SataPort->HostPRB->Fis.Control = 0x0F;
78 }
79 break;
80 case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:
81 ASSERT (0); //TODO: Implement me!
82 break;
83
84 // There is no difference for SiI3132 between PIO and DMA invokation
85 case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN:
86 case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:
87 // Fixup the size for block transfer. Following UEFI Specification, 'InTransferLength' should
88 // be in number of bytes. But for most data transfer commands, the value is in number of blocks
89 if (Packet->Acb->AtaCommand == ATA_CMD_IDENTIFY_DRIVE) {
90 InDataBufferLength = Packet->InTransferLength;
91 } else {
92 SataDevice = GetSataDevice (SataSiI3132Instance, SataPort->Index, PortMultiplierPort);
93 if (!SataDevice || (SataDevice->BlockSize == 0)) {
94 return EFI_INVALID_PARAMETER;
95 }
96
97 InDataBufferLength = Packet->InTransferLength * SataDevice->BlockSize;
98 }
99
100 Status = PciIo->Map (
101 PciIo, EfiPciIoOperationBusMasterWrite,
102 Packet->InDataBuffer, &InDataBufferLength, &PhysInDataBuffer, &PciAllocMapping
103 );
104 if (EFI_ERROR (Status)) {
105 return Status;
106 }
107
108 // Construct SGEs (32-bit system)
109 SataPort->HostPRB->Sge[0].DataAddressLow = (UINT32)PhysInDataBuffer;
110 SataPort->HostPRB->Sge[0].DataAddressHigh = (UINT32)(PhysInDataBuffer >> 32);
111 SataPort->HostPRB->Sge[0].Attributes = SGE_TRM; // Only one SGE
112 SataPort->HostPRB->Sge[0].DataCount = InDataBufferLength;
113
114 // Copy the Ata Command Block
115 CopyMem (&SataPort->HostPRB->Fis, Packet->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
116
117 // Fixup the FIS
118 SataPort->HostPRB->Fis.FisType = 0x27; // Register - Host to Device FIS
119 SataPort->HostPRB->Fis.Control = 1 << 7; // Is a command
120 if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) {
121 SataPort->HostPRB->Fis.Control |= PortMultiplierPort & 0xFF;
122 }
123 break;
124 case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT:
125 case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:
126 SataDevice = GetSataDevice (SataSiI3132Instance, SataPort->Index, PortMultiplierPort);
127 if (!SataDevice || (SataDevice->BlockSize == 0)) {
128 return EFI_INVALID_PARAMETER;
129 }
130
131 // Fixup the size for block transfer. Following UEFI Specification, 'InTransferLength' should
132 // be in number of bytes. But for most data transfer commands, the value is in number of blocks
133 OutDataBufferLength = Packet->OutTransferLength * SataDevice->BlockSize;
134
135 Status = PciIo->Map (
136 PciIo, EfiPciIoOperationBusMasterRead,
137 Packet->OutDataBuffer, &OutDataBufferLength, &PhysOutDataBuffer, &PciAllocMapping
138 );
139 if (EFI_ERROR (Status)) {
140 return Status;
141 }
142
143 // Construct SGEs (32-bit system)
144 SataPort->HostPRB->Sge[0].DataAddressLow = (UINT32)PhysOutDataBuffer;
145 SataPort->HostPRB->Sge[0].DataAddressHigh = (UINT32)(PhysOutDataBuffer >> 32);
146 SataPort->HostPRB->Sge[0].Attributes = SGE_TRM; // Only one SGE
147 SataPort->HostPRB->Sge[0].DataCount = OutDataBufferLength;
148
149 // Copy the Ata Command Block
150 CopyMem (&SataPort->HostPRB->Fis, Packet->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
151
152 // Fixup the FIS
153 SataPort->HostPRB->Fis.FisType = 0x27; // Register - Host to Device FIS
154 SataPort->HostPRB->Fis.Control = 1 << 7; // Is a command
155 if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) {
156 SataPort->HostPRB->Fis.Control |= PortMultiplierPort & 0xFF;
157 }
158 break;
159 case EFI_ATA_PASS_THRU_PROTOCOL_DMA:
160 ASSERT (0); //TODO: Implement me!
161 break;
162 case EFI_ATA_PASS_THRU_PROTOCOL_DMA_QUEUED:
163 ASSERT (0); //TODO: Implement me!
164 break;
165 case EFI_ATA_PASS_THRU_PROTOCOL_DEVICE_DIAGNOSTIC:
166 ASSERT (0); //TODO: Implement me!
167 break;
168 case EFI_ATA_PASS_THRU_PROTOCOL_DEVICE_RESET:
169 ASSERT (0); //TODO: Implement me!
170 break;
171 case EFI_ATA_PASS_THRU_PROTOCOL_FPDMA:
172 ASSERT (0); //TODO: Implement me!
173 break;
174 case EFI_ATA_PASS_THRU_PROTOCOL_RETURN_RESPONSE:
175 ASSERT (0); //TODO: Implement me!
176 break;
177 default:
178 ASSERT (0);
179 break;
180 }
181
182 SataPort->HostPRB->Control = Control;
183 SataPort->HostPRB->ProtocolOverride = Protocol;
184
185 // Clear IRQ
186 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, IrqMask);
187
188 if (!FeaturePcdGet (PcdSataSiI3132FeatureDirectCommandIssuing)) {
189 // Indirect Command Issuance
190
191 //TODO: Find which slot is free (maybe use the Cmd FIFO)
192 //SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_CMDEXECFIFO_REG, &EmptySlot);
193
194 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CMDACTIV_REG + (EmptySlot * 8),
195 (UINT32)(SataPort->PhysAddrHostPRB & 0xFFFFFFFF));
196 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CMDACTIV_REG + (EmptySlot * 8) + 4,
197 (UINT32)((SataPort->PhysAddrHostPRB >> 32) & 0xFFFFFFFF));
198 } else {
199 // Direct Command Issuance
200 Status = PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, 1, // Bar 1
201 SataPort->RegBase + (EmptySlot * 0x80),
202 sizeof (SATA_SI3132_PRB) / 4,
203 SataPort->HostPRB);
204 ASSERT_EFI_ERROR (Status);
205
206 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CMDEXECFIFO_REG, EmptySlot);
207 }
208
209 #if 0
210 // Could need to be implemented if we run multiple command in parallel to know which slot has been completed
211 SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_SLOTSTATUS_REG, &Value32);
212 Timeout = Packet->Timeout;
213 while (!Timeout && !Value32) {
214 gBS->Stall (1);
215 SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_SLOTSTATUS_REG, &Value32);
216 Timeout--;
217 }
218 #else
219 SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Value32);
220 if (!Packet->Timeout) {
221 while (!(Value32 & IrqMask)) {
222 gBS->Stall (1);
223 SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Value32);
224 }
225 } else {
226 Timeout = Packet->Timeout;
227 while (Timeout && !(Value32 & IrqMask)) {
228 gBS->Stall (1);
229 SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Value32);
230 Timeout--;
231 }
232 }
233 #endif
234 // Fill Packet Ata Status Block
235 Status = PciIo->Mem.Read (PciIo, EfiPciIoWidthUint32, 1, // Bar 1
236 SataPort->RegBase + 0x08,
237 sizeof (EFI_ATA_STATUS_BLOCK) / 4,
238 Packet->Asb);
239 ASSERT_EFI_ERROR (Status);
240
241
242 if ((Packet->Timeout != 0) && (Timeout == 0)) {
243 DEBUG ((EFI_D_ERROR, "SiI3132AtaPassThru() Err:Timeout\n"));
244 //ASSERT (0);
245 return EFI_TIMEOUT;
246 } else if (Value32 & (SII3132_PORT_INT_CMDERR << 16)) {
247 SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_CMDERROR_REG, &Error);
248 DEBUG ((EFI_D_ERROR, "SiI3132AtaPassThru() CmdErr:0x%X (SiI3132 Err:0x%X)\n", Value32, Error));
249 ASSERT (0);
250 return EFI_DEVICE_ERROR;
251 } else if (Value32 & (SII3132_PORT_INT_CMDCOMPL << 16)) {
252 // Clear Command Complete
253 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, SII3132_PORT_INT_CMDCOMPL << 16);
254
255 if (PciAllocMapping) {
256 Status = PciIo->Unmap (PciIo, PciAllocMapping);
257 ASSERT (!EFI_ERROR (Status));
258 }
259
260 // If the command was ATA_CMD_IDENTIFY_DRIVE then we need to update the BlockSize
261 if (Packet->Acb->AtaCommand == ATA_CMD_IDENTIFY_DRIVE) {
262 ATA_IDENTIFY_DATA *IdentifyData = (ATA_IDENTIFY_DATA*)Packet->InDataBuffer;
263
264 // Get the corresponding Block Device
265 SataDevice = GetSataDevice (SataSiI3132Instance, SataPort->Index, PortMultiplierPort);
266
267 // Check logical block size
268 if ((IdentifyData->phy_logic_sector_support & BIT12) != 0) {
269 ASSERT (SataDevice != NULL);
270 SataDevice->BlockSize = (UINT32) (((IdentifyData->logic_sector_size_hi << 16) |
271 IdentifyData->logic_sector_size_lo) * sizeof (UINT16));
272 } else {
273 SataDevice->BlockSize = 0x200;
274 }
275 }
276 return EFI_SUCCESS;
277 } else {
278 ASSERT (0);
279 return EFI_DEVICE_ERROR;
280 }
281 }
282
283 /**
284 Sends an ATA command to an ATA device that is attached to the ATA controller. This function
285 supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required,
286 and the non-blocking I/O functionality is optional.
287
288 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
289 @param[in] Port The port number of the ATA device to send the command.
290 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.
291 If there is no port multiplier, then specify 0.
292 @param[in,out] Packet A pointer to the ATA command to send to the ATA device specified by Port
293 and PortMultiplierPort.
294 @param[in] Event If non-blocking I/O is not supported then Event is ignored, and blocking
295 I/O is performed. If Event is NULL, then blocking I/O is performed. If
296 Event is not NULL and non blocking I/O is supported, then non-blocking
297 I/O is performed, and Event will be signaled when the ATA command completes.
298
299 @retval EFI_SUCCESS The ATA command was sent by the host. For bi-directional commands,
300 InTransferLength bytes were transferred from InDataBuffer. For write and
301 bi-directional commands, OutTransferLength bytes were transferred by OutDataBuffer.
302 @retval EFI_BAD_BUFFER_SIZE The ATA command was not executed. The number of bytes that could be transferred
303 is returned in InTransferLength. For write and bi-directional commands,
304 OutTransferLength bytes were transferred by OutDataBuffer.
305 @retval EFI_NOT_READY The ATA command could not be sent because there are too many ATA commands
306 already queued. The caller may retry again later.
307 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the ATA command.
308 @retval EFI_INVALID_PARAMETER Port, PortMultiplierPort, or the contents of Acb are invalid. The ATA
309 command was not sent, so no additional status information is available.
310
311 **/
312 EFI_STATUS
313 SiI3132AtaPassThru (
314 IN EFI_ATA_PASS_THRU_PROTOCOL *This,
315 IN UINT16 Port,
316 IN UINT16 PortMultiplierPort,
317 IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,
318 IN EFI_EVENT Event OPTIONAL
319 )
320 {
321 SATA_SI3132_INSTANCE *SataSiI3132Instance;
322 SATA_SI3132_DEVICE *SataDevice;
323 SATA_SI3132_PORT *SataPort;
324
325 SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
326 if (!SataSiI3132Instance) {
327 return EFI_INVALID_PARAMETER;
328 }
329
330 SataDevice = GetSataDevice (SataSiI3132Instance, Port, PortMultiplierPort);
331 if (!SataDevice) {
332 return EFI_INVALID_PARAMETER;
333 }
334 SataPort = SataDevice->Port;
335
336 DEBUG ((EFI_D_INFO, "SiI3132AtaPassThru(%d,%d) : AtaCmd:0x%X Prot:%d\n", Port, PortMultiplierPort,
337 Packet->Acb->AtaCommand, Packet->Protocol));
338
339 return SiI3132AtaPassThruCommand (SataSiI3132Instance, SataPort, PortMultiplierPort, Packet, Event);
340 }
341
342 /**
343 Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.
344 These can either be the list of ports where ATA devices are actually present or the
345 list of legal port numbers for the ATA controller. Regardless, the caller of this
346 function must probe the port number returned to see if an ATA device is actually
347 present at that location on the ATA controller.
348
349 The GetNextPort() function retrieves the port number on an ATA controller. If on input
350 Port is 0xFFFF, then the port number of the first port on the ATA controller is returned
351 in Port and EFI_SUCCESS is returned.
352
353 If Port is a port number that was returned on a previous call to GetNextPort(), then the
354 port number of the next port on the ATA controller is returned in Port, and EFI_SUCCESS
355 is returned. If Port is not 0xFFFF and Port was not returned on a previous call to
356 GetNextPort(), then EFI_INVALID_PARAMETER is returned.
357
358 If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND is
359 returned.
360
361 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
362 @param[in,out] Port On input, a pointer to the port number on the ATA controller.
363 On output, a pointer to the next port number on the ATA
364 controller. An input value of 0xFFFF retrieves the first port
365 number on the ATA controller.
366
367 @retval EFI_SUCCESS The next port number on the ATA controller was returned in Port.
368 @retval EFI_NOT_FOUND There are no more ports on this ATA controller.
369 @retval EFI_INVALID_PARAMETER Port is not 0xFFFF and Port was not returned on a previous call
370 to GetNextPort().
371
372 **/
373 EFI_STATUS
374 SiI3132GetNextPort (
375 IN EFI_ATA_PASS_THRU_PROTOCOL *This,
376 IN OUT UINT16 *Port
377 )
378 {
379 SATA_SI3132_INSTANCE *SataSiI3132Instance;
380 UINTN PrevPort;
381 EFI_STATUS Status = EFI_SUCCESS;
382
383 SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
384 if (!SataSiI3132Instance) {
385 return EFI_INVALID_PARAMETER;
386 }
387
388 PrevPort = *Port;
389
390 if (PrevPort == 0xFFFF) {
391 *Port = 0;
392 } else {
393 if (PrevPort < SATA_SII3132_MAXPORT) {
394 *Port = PrevPort + 1;
395 } else {
396 Status = EFI_NOT_FOUND;
397 }
398 }
399 return Status;
400 }
401
402 /**
403 Used to retrieve the list of legal port multiplier port numbers for ATA devices on a port of an ATA
404 controller. These can either be the list of port multiplier ports where ATA devices are actually
405 present on port or the list of legal port multiplier ports on that port. Regardless, the caller of this
406 function must probe the port number and port multiplier port number returned to see if an ATA
407 device is actually present.
408
409 The GetNextDevice() function retrieves the port multiplier port number of an ATA device
410 present on a port of an ATA controller.
411
412 If PortMultiplierPort points to a port multiplier port number value that was returned on a
413 previous call to GetNextDevice(), then the port multiplier port number of the next ATA device
414 on the port of the ATA controller is returned in PortMultiplierPort, and EFI_SUCCESS is
415 returned.
416
417 If PortMultiplierPort points to 0xFFFF, then the port multiplier port number of the first
418 ATA device on port of the ATA controller is returned in PortMultiplierPort and
419 EFI_SUCCESS is returned.
420
421 If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort
422 was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
423 is returned.
424
425 If PortMultiplierPort is the port multiplier port number of the last ATA device on the port of
426 the ATA controller, then EFI_NOT_FOUND is returned.
427
428 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
429 @param[in] Port The port number present on the ATA controller.
430 @param[in,out] PortMultiplierPort On input, a pointer to the port multiplier port number of an
431 ATA device present on the ATA controller.
432 If on input a PortMultiplierPort of 0xFFFF is specified,
433 then the port multiplier port number of the first ATA device
434 is returned. On output, a pointer to the port multiplier port
435 number of the next ATA device present on an ATA controller.
436
437 @retval EFI_SUCCESS The port multiplier port number of the next ATA device on the port
438 of the ATA controller was returned in PortMultiplierPort.
439 @retval EFI_NOT_FOUND There are no more ATA devices on this port of the ATA controller.
440 @retval EFI_INVALID_PARAMETER PortMultiplierPort is not 0xFFFF, and PortMultiplierPort was not
441 returned on a previous call to GetNextDevice().
442
443 **/
444 EFI_STATUS
445 SiI3132GetNextDevice (
446 IN EFI_ATA_PASS_THRU_PROTOCOL *This,
447 IN UINT16 Port,
448 IN OUT UINT16 *PortMultiplierPort
449 )
450 {
451 SATA_SI3132_INSTANCE *SataSiI3132Instance;
452 SATA_SI3132_PORT *SataPort;
453 SATA_SI3132_DEVICE *SataDevice;
454 LIST_ENTRY *List;
455 EFI_STATUS Status = EFI_SUCCESS;
456
457 SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
458 if (!SataSiI3132Instance) {
459 return EFI_INVALID_PARAMETER;
460 }
461
462 if (Port >= SATA_SII3132_MAXPORT) {
463 return EFI_INVALID_PARAMETER;
464 }
465
466 SataPort = &(SataSiI3132Instance->Ports[Port]);
467
468 if (*PortMultiplierPort == 0xFFFF) {
469 List = SataPort->Devices.ForwardLink;
470 if (List != &SataPort->Devices) {
471 // The list is not empty, return the first device
472 *PortMultiplierPort = ((SATA_SI3132_DEVICE*)List)->Index;
473 } else {
474 Status = EFI_NOT_FOUND;
475 }
476 } else {
477 SataDevice = GetSataDevice (SataSiI3132Instance, Port, *PortMultiplierPort);
478 if (SataDevice != NULL) {
479 // We have found the previous port multiplier, return the next one
480 List = SataDevice->Link.ForwardLink;
481 if (List != &SataPort->Devices) {
482 *PortMultiplierPort = ((SATA_SI3132_DEVICE*)List)->Index;
483 } else {
484 Status = EFI_NOT_FOUND;
485 }
486 } else {
487 Status = EFI_NOT_FOUND;
488 }
489 }
490 return Status;
491 }
492
493 /**
494 Used to allocate and build a device path node for an ATA device on an ATA controller.
495
496 The BuildDevicePath() function allocates and builds a single device node for the ATA
497 device specified by Port and PortMultiplierPort. If the ATA device specified by Port and
498 PortMultiplierPort is not present on the ATA controller, then EFI_NOT_FOUND is returned.
499 If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. If there are not enough
500 resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.
501
502 Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of
503 DevicePath are initialized to describe the ATA device specified by Port and PortMultiplierPort,
504 and EFI_SUCCESS is returned.
505
506 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
507 @param[in] Port Port specifies the port number of the ATA device for which a
508 device path node is to be allocated and built.
509 @param[in] PortMultiplierPort The port multiplier port number of the ATA device for which a
510 device path node is to be allocated and built. If there is no
511 port multiplier, then specify 0.
512 @param[in,out] DevicePath A pointer to a single device path node that describes the ATA
513 device specified by Port and PortMultiplierPort. This function
514 is responsible for allocating the buffer DevicePath with the
515 boot service AllocatePool(). It is the caller's responsibility
516 to free DevicePath when the caller is finished with DevicePath.
517 @retval EFI_SUCCESS The device path node that describes the ATA device specified by
518 Port and PortMultiplierPort was allocated and returned in DevicePath.
519 @retval EFI_NOT_FOUND The ATA device specified by Port and PortMultiplierPort does not
520 exist on the ATA controller.
521 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
522 @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
523
524 **/
525 EFI_STATUS
526 SiI3132BuildDevicePath (
527 IN EFI_ATA_PASS_THRU_PROTOCOL *This,
528 IN UINT16 Port,
529 IN UINT16 PortMultiplierPort,
530 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
531 )
532 {
533 SATA_SI3132_INSTANCE *SataSiI3132Instance;
534 SATA_SI3132_DEVICE *SataDevice;
535 EFI_DEVICE_PATH_PROTOCOL *SiI3132DevicePath;
536
537 SATA_TRACE ("SiI3132BuildDevicePath()");
538
539 SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
540 if (!SataSiI3132Instance) {
541 return EFI_INVALID_PARAMETER;
542 }
543
544 SataDevice = GetSataDevice (SataSiI3132Instance, Port, PortMultiplierPort);
545 if (SataDevice == NULL) {
546 return EFI_NOT_FOUND;
547 }
548
549 SiI3132DevicePath = CreateDeviceNode (MESSAGING_DEVICE_PATH, MSG_SATA_DP, sizeof (SATA_DEVICE_PATH));
550 if (SiI3132DevicePath == NULL) {
551 return EFI_OUT_OF_RESOURCES;
552 }
553
554 ((SATA_DEVICE_PATH*)SiI3132DevicePath)->HBAPortNumber = Port;
555 if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) {
556 ((SATA_DEVICE_PATH*)SiI3132DevicePath)->PortMultiplierPortNumber = PortMultiplierPort;
557 } else {
558 //Temp:((SATA_DEVICE_PATH*)SiI3132DevicePath)->PortMultiplierPortNumber = SATA_HBA_DIRECT_CONNECT_FLAG;
559 ((SATA_DEVICE_PATH*)SiI3132DevicePath)->PortMultiplierPortNumber = 0;
560 }
561 ((SATA_DEVICE_PATH*)SiI3132DevicePath)->Lun = Port; //TODO: Search information how to define properly LUN (Logical Unit Number)
562
563 *DevicePath = SiI3132DevicePath;
564 return EFI_SUCCESS;
565 }
566
567 /**
568 Used to translate a device path node to a port number and port multiplier port number.
569
570 The GetDevice() function determines the port and port multiplier port number associated with
571 the ATA device described by DevicePath. If DevicePath is a device path node type that the
572 ATA Pass Thru driver supports, then the ATA Pass Thru driver will attempt to translate the contents
573 DevicePath into a port number and port multiplier port number.
574
575 If this translation is successful, then that port number and port multiplier port number are returned
576 in Port and PortMultiplierPort, and EFI_SUCCESS is returned.
577
578 If DevicePath, Port, or PortMultiplierPort are NULL, then EFI_INVALID_PARAMETER is returned.
579
580 If DevicePath is not a device path node type that the ATA Pass Thru driver supports, then
581 EFI_UNSUPPORTED is returned.
582
583 If DevicePath is a device path node type that the ATA Pass Thru driver supports, but there is not
584 a valid translation from DevicePath to a port number and port multiplier port number, then
585 EFI_NOT_FOUND is returned.
586
587 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
588 @param[in] DevicePath A pointer to the device path node that describes an ATA device on the
589 ATA controller.
590 @param[out] Port On return, points to the port number of an ATA device on the ATA controller.
591 @param[out] PortMultiplierPort On return, points to the port multiplier port number of an ATA device
592 on the ATA controller.
593
594 @retval EFI_SUCCESS DevicePath was successfully translated to a port number and port multiplier
595 port number, and they were returned in Port and PortMultiplierPort.
596 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
597 @retval EFI_INVALID_PARAMETER Port is NULL.
598 @retval EFI_INVALID_PARAMETER PortMultiplierPort is NULL.
599 @retval EFI_UNSUPPORTED This driver does not support the device path node type in DevicePath.
600 @retval EFI_NOT_FOUND A valid translation from DevicePath to a port number and port multiplier
601 port number does not exist.
602 **/
603 EFI_STATUS
604 SiI3132GetDevice (
605 IN EFI_ATA_PASS_THRU_PROTOCOL *This,
606 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
607 OUT UINT16 *Port,
608 OUT UINT16 *PortMultiplierPort
609 )
610 {
611 SATA_SI3132_INSTANCE *SataSiI3132Instance;
612
613 SATA_TRACE ("SiI3132GetDevice()");
614
615 if (!DevicePath || !Port || !PortMultiplierPort) {
616 return EFI_INVALID_PARAMETER;
617 }
618
619 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) || (DevicePath->SubType != MSG_SATA_DP)) {
620 return EFI_UNSUPPORTED;
621 }
622
623 SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
624 if (!SataSiI3132Instance) {
625 return EFI_INVALID_PARAMETER;
626 }
627
628 if (((SATA_DEVICE_PATH*)DevicePath)->Lun >= SATA_SII3132_MAXPORT) {
629 return EFI_NOT_FOUND;
630 }
631
632 if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) {
633 ASSERT (0); //TODO: Implement me!
634 return EFI_UNSUPPORTED;
635 } else {
636 *Port = ((SATA_DEVICE_PATH*)DevicePath)->Lun;
637 // Return the first Sata Device as there should be only one directly connected
638 *PortMultiplierPort = ((SATA_SI3132_DEVICE*)SataSiI3132Instance->Ports[*Port].Devices.ForwardLink)->Index;
639 return EFI_SUCCESS;
640 }
641 }
642
643 EFI_STATUS
644 SiI3132HwResetPort (
645 IN SATA_SI3132_PORT *SataPort
646 )
647 {
648 EFI_PCI_IO_PROTOCOL *PciIo;
649 UINT32 Value32;
650 UINTN Timeout;
651
652 SATA_TRACE ("SiI3132HwResetPort()");
653
654 PciIo = SataPort->Instance->PciIo;
655
656 // Clear Port Reset
657 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CONTROLCLEAR_REG, SII3132_PORT_CONTROL_RESET);
658
659 SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_STATUS_REG, &Value32);
660 ASSERT (!(Value32 & SII3132_PORT_CONTROL_RESET));
661
662 // Initialize error counters
663 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ERRCOUNTDECODE, 0);
664 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ERRCOUNTCRC, 0);
665 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ERRCOUNTHANDSHAKE, 0);
666
667 // Enable interrupts for command completion and command errors
668 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ENABLEINT_REG, SII3132_PORT_INT_CMDCOMPL | SII3132_PORT_INT_CMDERR);
669
670 // Clear IRQ
671 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ENABLEINT_REG, SII3132_PORT_INT_CMDCOMPL | SII3132_PORT_INT_CMDERR | SII3132_PORT_INT_PORTRDY | (1 << 3));
672
673 // Wait until Port Ready
674 SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Value32);
675 Timeout = 1000;
676 while ((Timeout > 0) && ((Value32 & SII3132_PORT_INT_PORTRDY) == 0)) {
677 gBS->Stall (1);
678 Timeout--;
679 SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Value32);
680 }
681 // Clear IRQ
682 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, SII3132_PORT_INT_PORTRDY);
683
684 if (Timeout == 0) {
685 SATA_TRACE ("SiI3132HwResetPort(): Timeout");
686 return EFI_TIMEOUT;
687 } else if ((Value32 & SII3132_PORT_INT_PORTRDY) == 0) {
688 SATA_TRACE ("SiI3132HwResetPort(): Port Not Ready");
689 return EFI_DEVICE_ERROR;
690 } else {
691 return EFI_SUCCESS;
692 }
693 }
694
695 /**
696 Resets a specific port on the ATA controller. This operation also resets all the ATA devices
697 connected to the port.
698
699 The ResetChannel() function resets an a specific port on an ATA controller. This operation
700 resets all the ATA devices connected to that port. If this ATA controller does not support
701 a reset port operation, then EFI_UNSUPPORTED is returned.
702
703 If a device error occurs while executing that port reset operation, then EFI_DEVICE_ERROR is
704 returned.
705
706 If a timeout occurs during the execution of the port reset operation, then EFI_TIMEOUT is returned.
707
708 If the port reset operation is completed, then EFI_SUCCESS is returned.
709
710 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
711 @param[in] Port The port number on the ATA controller.
712
713 @retval EFI_SUCCESS The ATA controller port was reset.
714 @retval EFI_UNSUPPORTED The ATA controller does not support a port reset operation.
715 @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the ATA port.
716 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the ATA port.
717
718 **/
719 EFI_STATUS
720 SiI3132ResetPort (
721 IN EFI_ATA_PASS_THRU_PROTOCOL *This,
722 IN UINT16 Port
723 )
724 {
725 SATA_SI3132_INSTANCE *SataSiI3132Instance;
726 SATA_SI3132_PORT *SataPort;
727
728 SATA_TRACE ("SiI3132ResetPort()");
729
730 SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
731 if (!SataSiI3132Instance) {
732 return EFI_INVALID_PARAMETER;
733 }
734
735 if (Port >= SATA_SII3132_MAXPORT) {
736 return EFI_UNSUPPORTED;
737 }
738
739 SataPort = &(SataSiI3132Instance->Ports[Port]);
740 return SiI3132HwResetPort (SataPort);
741 }
742
743 /**
744 Resets an ATA device that is connected to an ATA controller.
745
746 The ResetDevice() function resets the ATA device specified by Port and PortMultiplierPort.
747 If this ATA controller does not support a device reset operation, then EFI_UNSUPPORTED is
748 returned.
749
750 If Port or PortMultiplierPort are not in a valid range for this ATA controller, then
751 EFI_INVALID_PARAMETER is returned.
752
753 If a device error occurs while executing that device reset operation, then EFI_DEVICE_ERROR
754 is returned.
755
756 If a timeout occurs during the execution of the device reset operation, then EFI_TIMEOUT is
757 returned.
758
759 If the device reset operation is completed, then EFI_SUCCESS is returned.
760
761 @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.
762 @param[in] Port Port represents the port number of the ATA device to be reset.
763 @param[in] PortMultiplierPort The port multiplier port number of the ATA device to reset.
764 If there is no port multiplier, then specify 0.
765 @retval EFI_SUCCESS The ATA device specified by Port and PortMultiplierPort was reset.
766 @retval EFI_UNSUPPORTED The ATA controller does not support a device reset operation.
767 @retval EFI_INVALID_PARAMETER Port or PortMultiplierPort are invalid.
768 @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the ATA device
769 specified by Port and PortMultiplierPort.
770 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the ATA device
771 specified by Port and PortMultiplierPort.
772
773 **/
774 EFI_STATUS
775 SiI3132ResetDevice (
776 IN EFI_ATA_PASS_THRU_PROTOCOL *This,
777 IN UINT16 Port,
778 IN UINT16 PortMultiplierPort
779 )
780 {
781 EFI_PCI_IO_PROTOCOL *PciIo;
782 SATA_SI3132_INSTANCE *SataSiI3132Instance;
783 SATA_SI3132_PORT *SataPort;
784 SATA_SI3132_DEVICE *SataDevice;
785 UINTN Timeout;
786 UINT32 Value32;
787
788 SATA_TRACE ("SiI3132ResetDevice()");
789
790 SataSiI3132Instance = INSTANCE_FROM_ATAPASSTHRU_THIS (This);
791 if (!SataSiI3132Instance) {
792 return EFI_INVALID_PARAMETER;
793 }
794
795 PciIo = SataSiI3132Instance->PciIo;
796
797 SataDevice = GetSataDevice (SataSiI3132Instance, Port, PortMultiplierPort);
798 if (!SataDevice) {
799 return EFI_INVALID_PARAMETER;
800 }
801 SataPort = SataDevice->Port;
802
803 SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CONTROLSET_REG, SII3132_PORT_DEVICE_RESET);
804
805 Timeout = 100;
806 SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_STATUS_REG, &Value32);
807 while ((Timeout > 0) && ((Value32 & SII3132_PORT_DEVICE_RESET) != 0)) {
808 gBS->Stall (1);
809 SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_STATUS_REG, &Value32);
810 Timeout--;
811 }
812
813 if (Timeout == 0) {
814 SATA_TRACE ("SiI3132ResetDevice(): Timeout");
815 return EFI_TIMEOUT;
816 } else {
817 return EFI_SUCCESS;
818 }
819 }