]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
MdeModulePkg/UfsPassThruDxe: Refactor UfsExecUicCommand function
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsPassThruDxe / UfsPassThruHci.c
CommitLineData
0591696e
FT
1/** @file\r
2 UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface\r
3 for upper layer application to execute UFS-supported SCSI cmds.\r
4\r
90952ad7 5 Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
0591696e
FT
7\r
8**/\r
9\r
10#include "UfsPassThru.h"\r
11\r
095f0779
FT
12/**\r
13 Read 32bits data from specified UFS MMIO register.\r
14\r
15 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
16 @param[in] Offset The offset within the UFS Host Controller MMIO space to start\r
17 the memory operation.\r
18 @param[out] Value The data buffer to store.\r
19\r
20 @retval EFI_TIMEOUT The operation is time out.\r
21 @retval EFI_SUCCESS The operation succeeds.\r
22 @retval Others The operation fails.\r
23\r
24**/\r
25EFI_STATUS\r
26UfsMmioRead32 (\r
27 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
28 IN UINTN Offset,\r
29 OUT UINT32 *Value\r
30 )\r
31{\r
32 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
33 EFI_STATUS Status;\r
34\r
35 UfsHc = Private->UfsHostController;\r
36\r
37 Status = UfsHc->Read (UfsHc, EfiUfsHcWidthUint32, Offset, 1, Value);\r
38\r
39 return Status;\r
40}\r
41\r
42/**\r
43 Write 32bits data to specified UFS MMIO register.\r
44\r
45 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
46 @param[in] Offset The offset within the UFS Host Controller MMIO space to start\r
47 the memory operation.\r
48 @param[in] Value The data to write.\r
49\r
50 @retval EFI_TIMEOUT The operation is time out.\r
51 @retval EFI_SUCCESS The operation succeeds.\r
52 @retval Others The operation fails.\r
53\r
54**/\r
55EFI_STATUS\r
56UfsMmioWrite32 (\r
57 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
58 IN UINTN Offset,\r
59 IN UINT32 Value\r
60 )\r
61{\r
62 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
63 EFI_STATUS Status;\r
64\r
65 UfsHc = Private->UfsHostController;\r
66\r
67 Status = UfsHc->Write (UfsHc, EfiUfsHcWidthUint32, Offset, 1, &Value);\r
68\r
69 return Status;\r
70}\r
71\r
0591696e
FT
72/**\r
73 Wait for the value of the specified system memory set to the test value.\r
74\r
095f0779
FT
75 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
76 @param[in] Offset The offset within the UFS Host Controller MMIO space to start\r
77 the memory operation.\r
78 @param[in] MaskValue The mask value of memory.\r
79 @param[in] TestValue The test value of memory.\r
80 @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.\r
0591696e
FT
81\r
82 @retval EFI_TIMEOUT The system memory setting is time out.\r
83 @retval EFI_SUCCESS The system memory is correct set.\r
095f0779 84 @retval Others The operation fails.\r
0591696e
FT
85\r
86**/\r
87EFI_STATUS\r
0591696e 88UfsWaitMemSet (\r
095f0779
FT
89 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
90 IN UINTN Offset,\r
91 IN UINT32 MaskValue,\r
92 IN UINT32 TestValue,\r
93 IN UINT64 Timeout\r
0591696e
FT
94 )\r
95{\r
96 UINT32 Value;\r
97 UINT64 Delay;\r
98 BOOLEAN InfiniteWait;\r
095f0779 99 EFI_STATUS Status;\r
0591696e
FT
100\r
101 if (Timeout == 0) {\r
102 InfiniteWait = TRUE;\r
103 } else {\r
104 InfiniteWait = FALSE;\r
105 }\r
106\r
107 Delay = DivU64x32 (Timeout, 10) + 1;\r
108\r
109 do {\r
110 //\r
111 // Access PCI MMIO space to see if the value is the tested one.\r
112 //\r
095f0779
FT
113 Status = UfsMmioRead32 (Private, Offset, &Value);\r
114 if (EFI_ERROR (Status)) {\r
115 return Status;\r
116 }\r
117\r
118 Value &= MaskValue;\r
0591696e
FT
119\r
120 if (Value == TestValue) {\r
121 return EFI_SUCCESS;\r
122 }\r
123\r
124 //\r
125 // Stall for 1 microseconds.\r
126 //\r
127 MicroSecondDelay (1);\r
128\r
129 Delay--;\r
130\r
131 } while (InfiniteWait || (Delay > 0));\r
132\r
133 return EFI_TIMEOUT;\r
134}\r
135\r
136/**\r
137 Dump UIC command execution result for debugging.\r
138\r
139 @param[in] UicOpcode The executed UIC opcode.\r
140 @param[in] Result The result to be parsed.\r
141\r
142**/\r
143VOID\r
144DumpUicCmdExecResult (\r
145 IN UINT8 UicOpcode,\r
146 IN UINT8 Result\r
147 )\r
148{\r
149 if (UicOpcode <= UfsUicDmePeerSet) {\r
150 switch (Result) {\r
151 case 0x00:\r
152 break;\r
153 case 0x01:\r
edd94e74 154 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));\r
0591696e
FT
155 break;\r
156 case 0x02:\r
edd94e74 157 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));\r
0591696e
FT
158 break;\r
159 case 0x03:\r
edd94e74 160 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));\r
0591696e
FT
161 break;\r
162 case 0x04:\r
edd94e74 163 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));\r
0591696e
FT
164 break;\r
165 case 0x05:\r
edd94e74 166 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));\r
0591696e
FT
167 break;\r
168 case 0x06:\r
edd94e74 169 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));\r
0591696e
FT
170 break;\r
171 case 0x07:\r
edd94e74 172 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));\r
0591696e
FT
173 break;\r
174 case 0x08:\r
edd94e74 175 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));\r
d1102dba 176 break;\r
0591696e 177 case 0x09:\r
edd94e74 178 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BUSY\n"));\r
0591696e
FT
179 break;\r
180 case 0x0A:\r
edd94e74 181 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));\r
d1102dba 182 break;\r
0591696e
FT
183 default :\r
184 ASSERT (FALSE);\r
185 break;\r
186 }\r
187 } else {\r
188 switch (Result) {\r
189 case 0x00:\r
190 break;\r
191 case 0x01:\r
edd94e74 192 DEBUG ((DEBUG_VERBOSE, "UIC control command fails - FAILURE\n"));\r
d1102dba 193 break;\r
0591696e
FT
194 default :\r
195 ASSERT (FALSE);\r
196 break;\r
197 }\r
198 }\r
199}\r
200\r
201/**\r
202 Dump QUERY RESPONSE UPIU result for debugging.\r
203\r
204 @param[in] Result The result to be parsed.\r
205\r
206**/\r
207VOID\r
208DumpQueryResponseResult (\r
209 IN UINT8 Result\r
210 )\r
211{\r
212 switch (Result) {\r
213 case 0xF6:\r
edd94e74 214 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Readable\n"));\r
0591696e
FT
215 break;\r
216 case 0xF7:\r
edd94e74 217 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Writeable\n"));\r
0591696e
FT
218 break;\r
219 case 0xF8:\r
edd94e74 220 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Already Written\n"));\r
0591696e
FT
221 break;\r
222 case 0xF9:\r
edd94e74 223 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Length\n"));\r
0591696e
FT
224 break;\r
225 case 0xFA:\r
edd94e74 226 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Value\n"));\r
0591696e
FT
227 break;\r
228 case 0xFB:\r
edd94e74 229 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Selector\n"));\r
0591696e
FT
230 break;\r
231 case 0xFC:\r
edd94e74 232 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Index\n"));\r
0591696e
FT
233 break;\r
234 case 0xFD:\r
edd94e74 235 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Idn\n"));\r
0591696e
FT
236 break;\r
237 case 0xFE:\r
edd94e74 238 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Opcode\n"));\r
d1102dba 239 break;\r
0591696e 240 case 0xFF:\r
edd94e74 241 DEBUG ((DEBUG_VERBOSE, "Query Response with General Failure\n"));\r
0591696e
FT
242 break;\r
243 default :\r
244 ASSERT (FALSE);\r
245 break;\r
246 }\r
247}\r
248\r
249/**\r
250 Swap little endian to big endian.\r
251\r
252 @param[in, out] Buffer The data buffer. In input, it contains little endian data.\r
253 In output, it will become big endian.\r
254 @param[in] BufferSize The length of converted data.\r
255\r
256**/\r
257VOID\r
258SwapLittleEndianToBigEndian (\r
259 IN OUT UINT8 *Buffer,\r
260 IN UINT32 BufferSize\r
261 )\r
262{\r
263 UINT32 Index;\r
264 UINT8 Temp;\r
265 UINT32 SwapCount;\r
266\r
267 SwapCount = BufferSize / 2;\r
268 for (Index = 0; Index < SwapCount; Index++) {\r
269 Temp = Buffer[Index];\r
270 Buffer[Index] = Buffer[BufferSize - 1 - Index];\r
271 Buffer[BufferSize - 1 - Index] = Temp;\r
272 }\r
273}\r
274\r
275/**\r
276 Fill TSF field of QUERY REQUEST UPIU.\r
277\r
278 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.\r
279 @param[in] Opcode The opcode of request.\r
280 @param[in] DescId The descriptor ID of request.\r
281 @param[in] Index The index of request.\r
282 @param[in] Selector The selector of request.\r
283 @param[in] Length The length of transferred data. The maximum is 4.\r
284 @param[in] Value The value of transferred data.\r
285\r
286**/\r
287VOID\r
288UfsFillTsfOfQueryReqUpiu (\r
289 IN OUT UTP_UPIU_TSF *TsfBase,\r
290 IN UINT8 Opcode,\r
291 IN UINT8 DescId OPTIONAL,\r
292 IN UINT8 Index OPTIONAL,\r
293 IN UINT8 Selector OPTIONAL,\r
294 IN UINT16 Length OPTIONAL,\r
295 IN UINT32 Value OPTIONAL\r
296 )\r
297{\r
298 ASSERT (TsfBase != NULL);\r
299 ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);\r
300\r
301 TsfBase->Opcode = Opcode;\r
302 if (Opcode != UtpQueryFuncOpcodeNop) {\r
303 TsfBase->DescId = DescId;\r
304 TsfBase->Index = Index;\r
305 TsfBase->Selector = Selector;\r
306\r
307 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {\r
308 SwapLittleEndianToBigEndian ((UINT8*)&Length, sizeof (Length));\r
309 TsfBase->Length = Length;\r
310 }\r
d1102dba 311\r
0591696e
FT
312 if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
313 SwapLittleEndianToBigEndian ((UINT8*)&Value, sizeof (Value));\r
314 TsfBase->Value = Value;\r
315 }\r
316 }\r
317}\r
318\r
319/**\r
320 Initialize COMMAND UPIU.\r
321\r
322 @param[in, out] Command The base address of COMMAND UPIU.\r
323 @param[in] Lun The Lun on which the SCSI command is executed.\r
324 @param[in] TaskTag The task tag of request.\r
325 @param[in] Cdb The cdb buffer containing SCSI command.\r
326 @param[in] CdbLength The cdb length.\r
327 @param[in] DataDirection The direction of data transfer.\r
328 @param[in] ExpDataTranLen The expected transfer data length.\r
329\r
330 @retval EFI_SUCCESS The initialization succeed.\r
331\r
332**/\r
333EFI_STATUS\r
334UfsInitCommandUpiu (\r
335 IN OUT UTP_COMMAND_UPIU *Command,\r
336 IN UINT8 Lun,\r
337 IN UINT8 TaskTag,\r
338 IN UINT8 *Cdb,\r
339 IN UINT8 CdbLength,\r
340 IN UFS_DATA_DIRECTION DataDirection,\r
341 IN UINT32 ExpDataTranLen\r
342 )\r
343{\r
344 UINT8 Flags;\r
345\r
346 ASSERT ((Command != NULL) && (Cdb != NULL));\r
347\r
348 //\r
349 // Task attribute is hard-coded to Ordered.\r
350 //\r
351 if (DataDirection == UfsDataIn) {\r
352 Flags = BIT0 | BIT6;\r
353 } else if (DataDirection == UfsDataOut) {\r
354 Flags = BIT0 | BIT5;\r
355 } else {\r
356 Flags = BIT0;\r
357 }\r
358\r
359 //\r
360 // Fill UTP COMMAND UPIU associated fields.\r
361 //\r
362 Command->TransCode = 0x01;\r
363 Command->Flags = Flags;\r
364 Command->Lun = Lun;\r
365 Command->TaskTag = TaskTag;\r
366 Command->CmdSet = 0x00;\r
367 SwapLittleEndianToBigEndian ((UINT8*)&ExpDataTranLen, sizeof (ExpDataTranLen));\r
368 Command->ExpDataTranLen = ExpDataTranLen;\r
369\r
370 CopyMem (Command->Cdb, Cdb, CdbLength);\r
371\r
372 return EFI_SUCCESS;\r
373}\r
374\r
375/**\r
376 Initialize UTP PRDT for data transfer.\r
377\r
378 @param[in] Prdt The base address of PRDT.\r
379 @param[in] Buffer The buffer to be read or written.\r
380 @param[in] BufferSize The data size to be read or written.\r
381\r
382 @retval EFI_SUCCESS The initialization succeed.\r
383\r
384**/\r
385EFI_STATUS\r
386UfsInitUtpPrdt (\r
387 IN UTP_TR_PRD *Prdt,\r
388 IN VOID *Buffer,\r
389 IN UINT32 BufferSize\r
390 )\r
391{\r
392 UINT32 PrdtIndex;\r
393 UINT32 RemainingLen;\r
394 UINT8 *Remaining;\r
395 UINTN PrdtNumber;\r
396\r
a37e18f6
AM
397 ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);\r
398 ASSERT ((BufferSize & (BIT1 | BIT0)) == 0);\r
d945390d 399\r
0591696e
FT
400 if (BufferSize == 0) {\r
401 return EFI_SUCCESS;\r
402 }\r
403\r
0591696e
FT
404 RemainingLen = BufferSize;\r
405 Remaining = Buffer;\r
406 PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
407\r
408 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
409 if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {\r
410 Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;\r
411 } else {\r
412 Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;\r
413 }\r
414\r
415 Prdt[PrdtIndex].DbAddr = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);\r
416 Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);\r
417 RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;\r
418 Remaining += UFS_MAX_DATA_LEN_PER_PRD;\r
419 }\r
420\r
421 return EFI_SUCCESS;\r
422}\r
423\r
424/**\r
425 Initialize QUERY REQUEST UPIU.\r
426\r
427 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.\r
428 @param[in] TaskTag The task tag of request.\r
429 @param[in] Opcode The opcode of request.\r
430 @param[in] DescId The descriptor ID of request.\r
431 @param[in] Index The index of request.\r
432 @param[in] Selector The selector of request.\r
433 @param[in] DataSize The data size to be read or written.\r
434 @param[in] Data The buffer to be read or written.\r
435\r
436 @retval EFI_SUCCESS The initialization succeed.\r
437\r
438**/\r
439EFI_STATUS\r
440UfsInitQueryRequestUpiu (\r
441 IN OUT UTP_QUERY_REQ_UPIU *QueryReq,\r
442 IN UINT8 TaskTag,\r
443 IN UINT8 Opcode,\r
444 IN UINT8 DescId,\r
445 IN UINT8 Index,\r
446 IN UINT8 Selector,\r
447 IN UINTN DataSize OPTIONAL,\r
448 IN UINT8 *Data OPTIONAL\r
449 )\r
450{\r
451 ASSERT (QueryReq != NULL);\r
452\r
453 QueryReq->TransCode = 0x16;\r
454 QueryReq->TaskTag = TaskTag;\r
455 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {\r
456 QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;\r
457 } else {\r
458 QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;\r
459 }\r
460\r
461 if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
462 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32*)Data);\r
463 } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {\r
464 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);\r
465 } else {\r
466 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);\r
467 }\r
468\r
469 if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
470 CopyMem (QueryReq + 1, Data, DataSize);\r
c16eee92
HW
471\r
472 SwapLittleEndianToBigEndian ((UINT8*)&DataSize, sizeof (UINT16));\r
473 QueryReq->DataSegLen = (UINT16)DataSize;\r
0591696e
FT
474 }\r
475\r
476 return EFI_SUCCESS;\r
477}\r
478\r
479/**\r
480 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
481\r
482 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
483 @param[in] Lun The Lun on which the SCSI command is executed.\r
484 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.\r
485 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
486 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
487 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
488\r
489 @retval EFI_SUCCESS The creation succeed.\r
490 @retval EFI_DEVICE_ERROR The creation failed.\r
491 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
492\r
493**/\r
494EFI_STATUS\r
495UfsCreateScsiCommandDesc (\r
496 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
497 IN UINT8 Lun,\r
498 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
499 IN UTP_TRD *Trd,\r
500 OUT VOID **CmdDescHost,\r
501 OUT VOID **CmdDescMapping\r
502 )\r
503{\r
504 UINTN TotalLen;\r
505 UINTN PrdtNumber;\r
506 UTP_COMMAND_UPIU *CommandUpiu;\r
507 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
508 EFI_STATUS Status;\r
509 UINT32 DataLen;\r
510 UFS_DATA_DIRECTION DataDirection;\r
511\r
512 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
513\r
514 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
515 DataLen = Packet->InTransferLength;\r
516 DataDirection = UfsDataIn;\r
517 } else {\r
518 DataLen = Packet->OutTransferLength;\r
519 DataDirection = UfsDataOut;\r
520 }\r
521\r
522 if (DataLen == 0) {\r
523 DataDirection = UfsNoData;\r
524 }\r
525\r
526 PrdtNumber = (UINTN)DivU64x32 ((UINT64)DataLen + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
527\r
528 TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);\r
529\r
530 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
531 if (EFI_ERROR (Status)) {\r
532 return Status;\r
533 }\r
534\r
535 CommandUpiu = (UTP_COMMAND_UPIU*)*CmdDescHost;\r
536\r
537 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, DataLen);\r
538\r
539 //\r
540 // Fill UTP_TRD associated fields\r
541 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table\r
542 // *MUST* be located at a 64-bit aligned boundary.\r
543 //\r
544 Trd->Int = UFS_INTERRUPT_COMMAND;\r
545 Trd->Dd = DataDirection;\r
546 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
86bd34ca 547 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
548 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
549 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
550 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));\r
551 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));\r
552 Trd->PrdtL = (UINT16)PrdtNumber;\r
553 Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));\r
554 return EFI_SUCCESS;\r
555}\r
556\r
557/**\r
558 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
559\r
560 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
561 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.\r
562 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
563 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
564 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
565\r
566 @retval EFI_SUCCESS The creation succeed.\r
567 @retval EFI_DEVICE_ERROR The creation failed.\r
568 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
569 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.\r
570\r
571**/\r
572EFI_STATUS\r
573UfsCreateDMCommandDesc (\r
574 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
575 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,\r
576 IN UTP_TRD *Trd,\r
577 OUT VOID **CmdDescHost,\r
578 OUT VOID **CmdDescMapping\r
579 )\r
580{\r
581 UINTN TotalLen;\r
582 UTP_QUERY_REQ_UPIU *QueryReqUpiu;\r
583 UINT8 Opcode;\r
584 UINT32 DataSize;\r
585 UINT8 *Data;\r
586 UINT8 DataDirection;\r
587 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
588 EFI_STATUS Status;\r
589\r
590 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
591\r
592 Opcode = Packet->Opcode;\r
593 if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {\r
594 return EFI_INVALID_PARAMETER;\r
595 }\r
596\r
597 DataDirection = Packet->DataDirection;\r
95ad8f7f
HW
598 DataSize = Packet->TransferLength;\r
599 Data = Packet->DataBuffer;\r
0591696e
FT
600\r
601 if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {\r
95ad8f7f
HW
602 if (DataSize == 0 || Data == NULL) {\r
603 return EFI_INVALID_PARAMETER;\r
604 }\r
0591696e
FT
605 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);\r
606 } else {\r
607 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));\r
608 }\r
609\r
610 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
611 if (EFI_ERROR (Status)) {\r
612 return Status;\r
613 }\r
614\r
615 //\r
616 // Initialize UTP QUERY REQUEST UPIU\r
617 //\r
618 QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)*CmdDescHost;\r
619 ASSERT (QueryReqUpiu != NULL);\r
620 UfsInitQueryRequestUpiu (\r
621 QueryReqUpiu,\r
622 Private->TaskTag++,\r
623 Opcode,\r
624 Packet->DescId,\r
625 Packet->Index,\r
626 Packet->Selector,\r
627 DataSize,\r
628 Data\r
629 );\r
630\r
631 //\r
632 // Fill UTP_TRD associated fields\r
633 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.\r
634 //\r
635 Trd->Int = UFS_INTERRUPT_COMMAND;\r
636 Trd->Dd = DataDirection;\r
637 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
86bd34ca 638 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
639 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
640 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
641 if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
642 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));\r
16f69227 643 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));\r
0591696e 644 } else {\r
16f69227 645 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));\r
0591696e
FT
646 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));\r
647 }\r
648\r
649 return EFI_SUCCESS;\r
650}\r
651\r
652/**\r
653 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.\r
654\r
655 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
656 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
657 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
658 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
659\r
660 @retval EFI_SUCCESS The creation succeed.\r
661 @retval EFI_DEVICE_ERROR The creation failed.\r
662 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
663\r
664**/\r
665EFI_STATUS\r
666UfsCreateNopCommandDesc (\r
667 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
668 IN UTP_TRD *Trd,\r
669 OUT VOID **CmdDescHost,\r
670 OUT VOID **CmdDescMapping\r
671 )\r
672{\r
673 UINTN TotalLen;\r
674 UTP_NOP_OUT_UPIU *NopOutUpiu;\r
675 EFI_STATUS Status;\r
676 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
677\r
678 ASSERT ((Private != NULL) && (Trd != NULL));\r
679\r
680 TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));\r
681 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
682 if (EFI_ERROR (Status)) {\r
683 return Status;\r
684 }\r
685\r
686 NopOutUpiu = (UTP_NOP_OUT_UPIU*)*CmdDescHost;\r
687 ASSERT (NopOutUpiu != NULL);\r
688 NopOutUpiu->TaskTag = Private->TaskTag++;\r
689\r
690 //\r
691 // Fill UTP_TRD associated fields\r
692 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.\r
693 //\r
694 Trd->Int = UFS_INTERRUPT_COMMAND;\r
695 Trd->Dd = 0x00;\r
696 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
86bd34ca 697 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
698 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
699 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
700 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));\r
701 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));\r
702\r
703 return EFI_SUCCESS;\r
704}\r
705\r
706/**\r
707 Find out available slot in transfer list of a UFS device.\r
708\r
709 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
710 @param[out] Slot The available slot.\r
711\r
712 @retval EFI_SUCCESS The available slot was found successfully.\r
0350b57c 713 @retval EFI_NOT_READY No slot is available at this moment.\r
0591696e
FT
714\r
715**/\r
716EFI_STATUS\r
717UfsFindAvailableSlotInTrl (\r
718 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
719 OUT UINT8 *Slot\r
720 )\r
721{\r
0350b57c
HW
722 UINT8 Nutrs;\r
723 UINT8 Index;\r
724 UINT32 Data;\r
725 EFI_STATUS Status;\r
726\r
0591696e
FT
727 ASSERT ((Private != NULL) && (Slot != NULL));\r
728\r
0350b57c
HW
729 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);\r
730 if (EFI_ERROR (Status)) {\r
731 return Status;\r
732 }\r
0591696e 733\r
0350b57c
HW
734 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
735\r
736 for (Index = 0; Index < Nutrs; Index++) {\r
737 if ((Data & (BIT0 << Index)) == 0) {\r
738 *Slot = Index;\r
739 return EFI_SUCCESS;\r
740 }\r
741 }\r
742\r
743 return EFI_NOT_READY;\r
0591696e
FT
744}\r
745\r
0591696e
FT
746\r
747/**\r
748 Start specified slot in transfer list of a UFS device.\r
749\r
750 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
751 @param[in] Slot The slot to be started.\r
752\r
753**/\r
095f0779 754EFI_STATUS\r
0591696e
FT
755UfsStartExecCmd (\r
756 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
757 IN UINT8 Slot\r
d1102dba 758 )\r
0591696e 759{\r
0591696e 760 UINT32 Data;\r
095f0779 761 EFI_STATUS Status;\r
0591696e 762\r
095f0779
FT
763 Status = UfsMmioRead32 (Private, UFS_HC_UTRLRSR_OFFSET, &Data);\r
764 if (EFI_ERROR (Status)) {\r
765 return Status;\r
766 }\r
0591696e 767\r
0591696e 768 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {\r
095f0779
FT
769 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);\r
770 if (EFI_ERROR (Status)) {\r
771 return Status;\r
772 }\r
773 }\r
774\r
775 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot);\r
776 if (EFI_ERROR (Status)) {\r
777 return Status;\r
0591696e
FT
778 }\r
779\r
095f0779 780 return EFI_SUCCESS;\r
0591696e
FT
781}\r
782\r
783/**\r
784 Stop specified slot in transfer list of a UFS device.\r
785\r
786 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
787 @param[in] Slot The slot to be stop.\r
788\r
789**/\r
095f0779 790EFI_STATUS\r
0591696e
FT
791UfsStopExecCmd (\r
792 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
793 IN UINT8 Slot\r
d1102dba 794 )\r
0591696e 795{\r
0591696e 796 UINT32 Data;\r
095f0779 797 EFI_STATUS Status;\r
0591696e 798\r
095f0779
FT
799 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);\r
800 if (EFI_ERROR (Status)) {\r
801 return Status;\r
802 }\r
0591696e 803\r
0591696e 804 if ((Data & (BIT0 << Slot)) != 0) {\r
095f0779
FT
805 Status = UfsMmioRead32 (Private, UFS_HC_UTRLCLR_OFFSET, &Data);\r
806 if (EFI_ERROR (Status)) {\r
807 return Status;\r
808 }\r
809\r
810 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLCLR_OFFSET, Data & ~(BIT0 << Slot));\r
811 if (EFI_ERROR (Status)) {\r
812 return Status;\r
813 }\r
0591696e 814 }\r
095f0779
FT
815\r
816 return EFI_SUCCESS;\r
0591696e
FT
817}\r
818\r
819/**\r
95ad8f7f 820 Extracts return data from query response upiu.\r
0591696e 821\r
95ad8f7f
HW
822 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.\r
823 @param[in] QueryResp Pointer to the query response.\r
0591696e 824\r
95ad8f7f 825 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.\r
8894c90d 826 @retval EFI_DEVICE_ERROR Data returned from device is invalid.\r
95ad8f7f 827 @retval EFI_SUCCESS Data extracted.\r
0591696e
FT
828\r
829**/\r
830EFI_STATUS\r
95ad8f7f
HW
831UfsGetReturnDataFromQueryResponse (\r
832 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,\r
833 IN UTP_QUERY_RESP_UPIU *QueryResp\r
0591696e
FT
834 )\r
835{\r
95ad8f7f
HW
836 UINT16 ReturnDataSize;\r
837 UINT32 ReturnData;\r
0591696e 838\r
95ad8f7f
HW
839 if (Packet == NULL || QueryResp == NULL) {\r
840 return EFI_INVALID_PARAMETER;\r
841 }\r
0591696e 842\r
95ad8f7f
HW
843 switch (Packet->Opcode) {\r
844 case UtpQueryFuncOpcodeRdDesc:\r
845 ReturnDataSize = QueryResp->Tsf.Length;\r
846 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));\r
8894c90d
HW
847 //\r
848 // Make sure the hardware device does not return more data than expected.\r
849 //\r
850 if (ReturnDataSize > Packet->TransferLength) {\r
851 return EFI_DEVICE_ERROR;\r
852 }\r
853\r
95ad8f7f
HW
854 CopyMem (Packet->DataBuffer, (QueryResp + 1), ReturnDataSize);\r
855 Packet->TransferLength = ReturnDataSize;\r
856 break;\r
857 case UtpQueryFuncOpcodeWrDesc:\r
858 ReturnDataSize = QueryResp->Tsf.Length;\r
859 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));\r
860 Packet->TransferLength = ReturnDataSize;\r
861 break;\r
862 case UtpQueryFuncOpcodeRdFlag:\r
863 case UtpQueryFuncOpcodeSetFlag:\r
864 case UtpQueryFuncOpcodeClrFlag:\r
865 case UtpQueryFuncOpcodeTogFlag:\r
866 CopyMem (Packet->DataBuffer, &QueryResp->Tsf.Value, sizeof (UINT8));\r
867 break;\r
868 case UtpQueryFuncOpcodeRdAttr:\r
869 case UtpQueryFuncOpcodeWrAttr:\r
870 ReturnData = QueryResp->Tsf.Value;\r
871 SwapLittleEndianToBigEndian ((UINT8*) &ReturnData, sizeof (UINT32));\r
872 CopyMem (Packet->DataBuffer, &ReturnData, sizeof (UINT32));\r
873 break;\r
874 default:\r
875 return EFI_INVALID_PARAMETER;\r
0591696e 876 }\r
95ad8f7f
HW
877\r
878 return EFI_SUCCESS;\r
879}\r
880\r
881/**\r
882 Creates Transfer Request descriptor and sends Query Request to the device.\r
883\r
884 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.\r
885 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.\r
886\r
887 @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
32c9049d
HW
888 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid\r
889 combination to point to a type of UFS device descriptor.\r
95ad8f7f
HW
890 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
891 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
892\r
893**/\r
894EFI_STATUS\r
895UfsSendDmRequestRetry (\r
896 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
897 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet\r
898 )\r
899{\r
900 UINT8 Slot;\r
901 UTP_TRD *Trd;\r
902 VOID *CmdDescHost;\r
903 VOID *CmdDescMapping;\r
904 UINT32 CmdDescSize;\r
905 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
906 UTP_QUERY_RESP_UPIU *QueryResp;\r
907 EFI_STATUS Status;\r
0591696e
FT
908\r
909 //\r
910 // Find out which slot of transfer request list is available.\r
911 //\r
912 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
913 if (EFI_ERROR (Status)) {\r
914 return Status;\r
915 }\r
d1102dba 916\r
0591696e
FT
917 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
918 //\r
919 // Fill transfer request descriptor to this slot.\r
920 //\r
95ad8f7f 921 Status = UfsCreateDMCommandDesc (Private, Packet, Trd, &CmdDescHost, &CmdDescMapping);\r
0591696e 922 if (EFI_ERROR (Status)) {\r
95ad8f7f 923 DEBUG ((DEBUG_ERROR, "Failed to create DM command descriptor\n"));\r
0591696e
FT
924 return Status;\r
925 }\r
926\r
0591696e
FT
927 UfsHc = Private->UfsHostController;\r
928 QueryResp = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
929 ASSERT (QueryResp != NULL);\r
930 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
931\r
932 //\r
933 // Start to execute the transfer request.\r
934 //\r
935 UfsStartExecCmd (Private, Slot);\r
936\r
937 //\r
938 // Wait for the completion of the transfer request.\r
95ad8f7f
HW
939 //\r
940 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0, 0, Packet->Timeout);\r
0591696e
FT
941 if (EFI_ERROR (Status)) {\r
942 goto Exit;\r
943 }\r
944\r
95ad8f7f
HW
945 if (Trd->Ocs != 0 || QueryResp->QueryResp != UfsUtpQueryResponseSuccess) {\r
946 DEBUG ((DEBUG_ERROR, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd->Ocs, QueryResp->QueryResp));\r
0591696e 947 DumpQueryResponseResult (QueryResp->QueryResp);\r
32c9049d
HW
948\r
949 if ((QueryResp->QueryResp == UfsUtpQueryResponseInvalidSelector) ||\r
950 (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIndex) ||\r
951 (QueryResp->QueryResp == UfsUtpQueryResponseInvalidIdn)) {\r
952 Status = EFI_INVALID_PARAMETER;\r
953 } else {\r
954 Status = EFI_DEVICE_ERROR;\r
955 }\r
0591696e
FT
956 goto Exit;\r
957 }\r
958\r
95ad8f7f
HW
959 Status = UfsGetReturnDataFromQueryResponse (Packet, QueryResp);\r
960 if (EFI_ERROR (Status)) {\r
961 DEBUG ((DEBUG_ERROR, "Failed to get return data from query response\n"));\r
962 goto Exit;\r
0591696e
FT
963 }\r
964\r
965Exit:\r
966 UfsHc->Flush (UfsHc);\r
967\r
968 UfsStopExecCmd (Private, Slot);\r
969\r
970 if (CmdDescMapping != NULL) {\r
971 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
972 }\r
973 if (CmdDescHost != NULL) {\r
974 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
975 }\r
976\r
977 return Status;\r
978}\r
979\r
95ad8f7f
HW
980/**\r
981 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.\r
982\r
983 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.\r
984 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.\r
985\r
986 @retval EFI_SUCCESS The device responded correctly to the Query request.\r
32c9049d
HW
987 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid\r
988 combination to point to a type of UFS device descriptor.\r
95ad8f7f
HW
989 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.\r
990 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.\r
991\r
992**/\r
993EFI_STATUS\r
994UfsSendDmRequest (\r
995 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
996 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet\r
997 )\r
998{\r
999 EFI_STATUS Status;\r
1000 UINT8 Retry;\r
1001\r
1002 Status = EFI_SUCCESS;\r
1003\r
1004 for (Retry = 0; Retry < 5; Retry ++) {\r
1005 Status = UfsSendDmRequestRetry (Private, Packet);\r
1006 if (!EFI_ERROR (Status)) {\r
1007 return EFI_SUCCESS;\r
1008 }\r
1009 }\r
1010\r
1011 DEBUG ((DEBUG_ERROR, "Failed to get response from the device after %d retries\n", Retry));\r
1012 return Status;\r
1013}\r
1014\r
1015/**\r
1016 Read or write specified device descriptor of a UFS device.\r
1017\r
1018 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1019 @param[in] Read The boolean variable to show r/w direction.\r
1020 @param[in] DescId The ID of device descriptor.\r
1021 @param[in] Index The Index of device descriptor.\r
1022 @param[in] Selector The Selector of device descriptor.\r
1023 @param[in, out] Descriptor The buffer of device descriptor to be read or written.\r
32c9049d
HW
1024 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,\r
1025 of the data buffer specified by Descriptor. On output, the number\r
1026 of bytes that were actually transferred.\r
95ad8f7f
HW
1027\r
1028 @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
32c9049d
HW
1029 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a\r
1030 type of UFS device descriptor.\r
95ad8f7f
HW
1031 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
1032 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
1033\r
1034**/\r
1035EFI_STATUS\r
1036UfsRwDeviceDesc (\r
1037 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1038 IN BOOLEAN Read,\r
1039 IN UINT8 DescId,\r
1040 IN UINT8 Index,\r
1041 IN UINT8 Selector,\r
1042 IN OUT VOID *Descriptor,\r
32c9049d 1043 IN OUT UINT32 *DescSize\r
95ad8f7f
HW
1044 )\r
1045{\r
1046 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
32c9049d
HW
1047 EFI_STATUS Status;\r
1048\r
1049 if (DescSize == NULL) {\r
1050 return EFI_INVALID_PARAMETER;\r
1051 }\r
95ad8f7f
HW
1052\r
1053 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1054\r
1055 if (Read) {\r
1056 Packet.DataDirection = UfsDataIn;\r
1057 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;\r
1058 } else {\r
1059 Packet.DataDirection = UfsDataOut;\r
1060 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;\r
1061 }\r
1062 Packet.DataBuffer = Descriptor;\r
32c9049d 1063 Packet.TransferLength = *DescSize;\r
95ad8f7f
HW
1064 Packet.DescId = DescId;\r
1065 Packet.Index = Index;\r
1066 Packet.Selector = Selector;\r
1067 Packet.Timeout = UFS_TIMEOUT;\r
1068\r
32c9049d
HW
1069 Status = UfsSendDmRequest (Private, &Packet);\r
1070 if (EFI_ERROR (Status)) {\r
1071 *DescSize = 0;\r
1072 } else {\r
1073 *DescSize = Packet.TransferLength;\r
1074 }\r
1075\r
1076 return Status;\r
95ad8f7f
HW
1077}\r
1078\r
0591696e
FT
1079/**\r
1080 Read or write specified attribute of a UFS device.\r
1081\r
1082 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1083 @param[in] Read The boolean variable to show r/w direction.\r
1084 @param[in] AttrId The ID of Attribute.\r
1085 @param[in] Index The Index of Attribute.\r
1086 @param[in] Selector The Selector of Attribute.\r
1087 @param[in, out] Attributes The value of Attribute to be read or written.\r
1088\r
1089 @retval EFI_SUCCESS The Attribute was read/written successfully.\r
32c9049d
HW
1090 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a\r
1091 type of UFS device descriptor.\r
0591696e
FT
1092 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.\r
1093 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.\r
1094\r
1095**/\r
1096EFI_STATUS\r
1097UfsRwAttributes (\r
1098 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1099 IN BOOLEAN Read,\r
1100 IN UINT8 AttrId,\r
1101 IN UINT8 Index,\r
1102 IN UINT8 Selector,\r
1103 IN OUT UINT32 *Attributes\r
1104 )\r
1105{\r
0591696e 1106 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
0591696e
FT
1107\r
1108 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1109\r
1110 if (Read) {\r
1111 Packet.DataDirection = UfsDataIn;\r
1112 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;\r
1113 } else {\r
1114 Packet.DataDirection = UfsDataOut;\r
1115 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;\r
1116 }\r
95ad8f7f 1117 Packet.DataBuffer = Attributes;\r
0591696e
FT
1118 Packet.DescId = AttrId;\r
1119 Packet.Index = Index;\r
1120 Packet.Selector = Selector;\r
1121 Packet.Timeout = UFS_TIMEOUT;\r
1122\r
95ad8f7f 1123 return UfsSendDmRequest (Private, &Packet);\r
0591696e
FT
1124}\r
1125\r
1126/**\r
1127 Read or write specified flag of a UFS device.\r
1128\r
1129 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1130 @param[in] Read The boolean variable to show r/w direction.\r
1131 @param[in] FlagId The ID of flag to be read or written.\r
1132 @param[in, out] Value The value to set or clear flag.\r
1133\r
1134 @retval EFI_SUCCESS The flag was read/written successfully.\r
32c9049d 1135 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.\r
0591696e
FT
1136 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.\r
1137 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.\r
1138\r
1139**/\r
1140EFI_STATUS\r
1141UfsRwFlags (\r
1142 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1143 IN BOOLEAN Read,\r
1144 IN UINT8 FlagId,\r
1145 IN OUT UINT8 *Value\r
1146 )\r
1147{\r
0591696e 1148 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
0591696e
FT
1149\r
1150 if (Value == NULL) {\r
1151 return EFI_INVALID_PARAMETER;\r
1152 }\r
1153\r
1154 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1155\r
1156 if (Read) {\r
1157 ASSERT (Value != NULL);\r
1158 Packet.DataDirection = UfsDataIn;\r
1159 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;\r
1160 } else {\r
1161 Packet.DataDirection = UfsDataOut;\r
1162 if (*Value == 1) {\r
1163 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;\r
1164 } else if (*Value == 0) {\r
1165 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;\r
1166 } else {\r
1167 return EFI_INVALID_PARAMETER;\r
1168 }\r
1169 }\r
95ad8f7f 1170 Packet.DataBuffer = Value;\r
0591696e
FT
1171 Packet.DescId = FlagId;\r
1172 Packet.Index = 0;\r
1173 Packet.Selector = 0;\r
1174 Packet.Timeout = UFS_TIMEOUT;\r
1175\r
95ad8f7f 1176 return UfsSendDmRequest (Private, &Packet);\r
0591696e
FT
1177}\r
1178\r
1179/**\r
1180 Set specified flag to 1 on a UFS device.\r
1181\r
1182 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1183 @param[in] FlagId The ID of flag to be set.\r
1184\r
1185 @retval EFI_SUCCESS The flag was set successfully.\r
1186 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.\r
1187 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.\r
1188\r
1189**/\r
1190EFI_STATUS\r
1191UfsSetFlag (\r
1192 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1193 IN UINT8 FlagId\r
1194 )\r
1195{\r
1196 EFI_STATUS Status;\r
1197 UINT8 Value;\r
1198\r
1199 Value = 1;\r
1200 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
1201\r
1202 return Status;\r
1203}\r
1204\r
0591696e 1205\r
0591696e
FT
1206\r
1207/**\r
1208 Read specified flag from a UFS device.\r
1209\r
1210 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1211 @param[in] FlagId The ID of flag to be read.\r
1212 @param[out] Value The flag's value.\r
1213\r
1214 @retval EFI_SUCCESS The flag was read successfully.\r
1215 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.\r
1216 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.\r
1217\r
1218**/\r
1219EFI_STATUS\r
1220UfsReadFlag (\r
1221 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1222 IN UINT8 FlagId,\r
1223 OUT UINT8 *Value\r
1224 )\r
1225{\r
1226 EFI_STATUS Status;\r
1227\r
1228 Status = UfsRwFlags (Private, TRUE, FlagId, Value);\r
1229\r
1230 return Status;\r
1231}\r
1232\r
1233/**\r
1234 Sends NOP IN cmd to a UFS device for initialization process request.\r
1235 For more details, please refer to UFS 2.0 spec Figure 13.3.\r
1236\r
1237 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1238\r
1239 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was\r
1240 received successfully.\r
1241 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.\r
1242 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1243 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.\r
1244\r
1245**/\r
1246EFI_STATUS\r
1247UfsExecNopCmds (\r
1248 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1249 )\r
1250{\r
1251 EFI_STATUS Status;\r
1252 UINT8 Slot;\r
1253 UTP_TRD *Trd;\r
1254 UTP_NOP_IN_UPIU *NopInUpiu;\r
1255 UINT32 CmdDescSize;\r
0591696e
FT
1256 VOID *CmdDescHost;\r
1257 VOID *CmdDescMapping;\r
1258 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
1259\r
1260 //\r
1261 // Find out which slot of transfer request list is available.\r
1262 //\r
1263 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
1264 if (EFI_ERROR (Status)) {\r
1265 return Status;\r
1266 }\r
1267\r
1268 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
1269 Status = UfsCreateNopCommandDesc (Private, Trd, &CmdDescHost, &CmdDescMapping);\r
1270 if (EFI_ERROR (Status)) {\r
1271 return Status;\r
1272 }\r
1273\r
1274 //\r
1275 // Check the transfer request result.\r
1276 //\r
1277 UfsHc = Private->UfsHostController;\r
1278 NopInUpiu = (UTP_NOP_IN_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
1279 ASSERT (NopInUpiu != NULL);\r
1280 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
1281\r
1282 //\r
1283 // Start to execute the transfer request.\r
1284 //\r
1285 UfsStartExecCmd (Private, Slot);\r
1286\r
1287 //\r
1288 // Wait for the completion of the transfer request.\r
d1102dba 1289 //\r
13fca387 1290 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot, 0, UFS_TIMEOUT);\r
0591696e
FT
1291 if (EFI_ERROR (Status)) {\r
1292 goto Exit;\r
1293 }\r
1294\r
1295 if (NopInUpiu->Resp != 0) {\r
1296 Status = EFI_DEVICE_ERROR;\r
1297 } else {\r
1298 Status = EFI_SUCCESS;\r
1299 }\r
1300\r
1301Exit:\r
1302 UfsHc->Flush (UfsHc);\r
1303\r
1304 UfsStopExecCmd (Private, Slot);\r
1305\r
1306 if (CmdDescMapping != NULL) {\r
1307 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
1308 }\r
1309 if (CmdDescHost != NULL) {\r
1310 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
1311 }\r
1312\r
1313 return Status;\r
1314}\r
1315\r
a37e18f6
AM
1316/**\r
1317 Cleanup data buffers after data transfer. This function\r
1318 also takes care to copy all data to user memory pool for\r
1319 unaligned data transfers.\r
1320\r
1321 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA\r
1322 @param[in] TransReq Pointer to the transfer request\r
1323**/\r
1324VOID\r
1325UfsReconcileDataTransferBuffer (\r
1326 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1327 IN UFS_PASS_THRU_TRANS_REQ *TransReq\r
1328 )\r
1329{\r
1330 if (TransReq->DataBufMapping != NULL) {\r
1331 Private->UfsHostController->Unmap (\r
1332 Private->UfsHostController,\r
1333 TransReq->DataBufMapping\r
1334 );\r
1335 }\r
1336\r
1337 //\r
1338 // Check if unaligned transfer was performed. If it was and we read\r
1339 // data from device copy memory to user data buffers before cleanup.\r
1340 // The assumption is if auxiliary aligned data buffer is not NULL then\r
1341 // unaligned transfer has been performed.\r
1342 //\r
1343 if (TransReq->AlignedDataBuf != NULL) {\r
1344 if (TransReq->Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1345 CopyMem (TransReq->Packet->InDataBuffer, TransReq->AlignedDataBuf, TransReq->Packet->InTransferLength);\r
1346 }\r
1347 //\r
1348 // Wipe out the transfer buffer in case it contains sensitive data.\r
1349 //\r
1350 ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize);\r
1351 FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES (TransReq->AlignedDataBufSize));\r
1352 TransReq->AlignedDataBuf = NULL;\r
1353 }\r
1354}\r
1355\r
1356/**\r
1357 Prepare data buffer for transfer.\r
1358\r
1359 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA\r
1360 @param[in, out] TransReq Pointer to the transfer request\r
1361\r
1362 @retval EFI_DEVICE_ERROR Failed to prepare buffer for transfer\r
1363 @retval EFI_SUCCESS Buffer ready for transfer\r
1364**/\r
1365EFI_STATUS\r
1366UfsPrepareDataTransferBuffer (\r
1367 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1368 IN OUT UFS_PASS_THRU_TRANS_REQ *TransReq\r
1369 )\r
1370{\r
1371 EFI_STATUS Status;\r
1372 VOID *DataBuf;\r
1373 UINT32 DataLen;\r
1374 UINTN MapLength;\r
1375 EFI_PHYSICAL_ADDRESS DataBufPhyAddr;\r
1376 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag;\r
1377 UTP_TR_PRD *PrdtBase;\r
1378\r
1379 DataBufPhyAddr = 0;\r
1380 DataBuf = NULL;\r
1381\r
1382 //\r
1383 // For unaligned data transfers we allocate auxiliary DWORD aligned memory pool.\r
1384 // When command is finished auxiliary memory pool is copied into actual user memory.\r
1385 // This is requiered to assure data transfer safety(DWORD alignment required by UFS spec.)\r
1386 //\r
1387 if (TransReq->Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1388 if (((UINTN)TransReq->Packet->InDataBuffer % 4 != 0) || (TransReq->Packet->InTransferLength % 4 != 0)) {\r
1389 DataLen = TransReq->Packet->InTransferLength + (4 - (TransReq->Packet->InTransferLength % 4));\r
1390 DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4);\r
1391 if (DataBuf == NULL) {\r
1392 return EFI_DEVICE_ERROR;\r
1393 }\r
1394 ZeroMem (DataBuf, DataLen);\r
1395 TransReq->AlignedDataBuf = DataBuf;\r
1396 TransReq->AlignedDataBufSize = DataLen;\r
1397 } else {\r
1398 DataLen = TransReq->Packet->InTransferLength;\r
1399 DataBuf = TransReq->Packet->InDataBuffer;\r
1400 }\r
1401 Flag = EdkiiUfsHcOperationBusMasterWrite;\r
1402 } else {\r
1403 if (((UINTN)TransReq->Packet->OutDataBuffer % 4 != 0) || (TransReq->Packet->OutTransferLength % 4 != 0)) {\r
1404 DataLen = TransReq->Packet->OutTransferLength + (4 - (TransReq->Packet->OutTransferLength % 4));\r
1405 DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4);\r
1406 if (DataBuf == NULL) {\r
1407 return EFI_DEVICE_ERROR;\r
1408 }\r
1409 CopyMem (DataBuf, TransReq->Packet->OutDataBuffer, TransReq->Packet->OutTransferLength);\r
1410 TransReq->AlignedDataBuf = DataBuf;\r
1411 TransReq->AlignedDataBufSize = DataLen;\r
1412 } else {\r
1413 DataLen = TransReq->Packet->OutTransferLength;\r
1414 DataBuf = TransReq->Packet->OutDataBuffer;\r
1415 }\r
1416 Flag = EdkiiUfsHcOperationBusMasterRead;\r
1417 }\r
1418\r
1419 if (DataLen != 0) {\r
1420 MapLength = DataLen;\r
1421 Status = Private->UfsHostController->Map (\r
1422 Private->UfsHostController,\r
1423 Flag,\r
1424 DataBuf,\r
1425 &MapLength,\r
1426 &DataBufPhyAddr,\r
1427 &TransReq->DataBufMapping\r
1428 );\r
1429\r
1430 if (EFI_ERROR (Status) || (DataLen != MapLength)) {\r
1431 if (TransReq->AlignedDataBuf != NULL) {\r
1432 //\r
1433 // Wipe out the transfer buffer in case it contains sensitive data.\r
1434 //\r
1435 ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize);\r
1436 FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES (TransReq->AlignedDataBufSize));\r
1437 TransReq->AlignedDataBuf = NULL;\r
1438 }\r
1439 return EFI_DEVICE_ERROR;\r
1440 }\r
1441 }\r
1442\r
1443 //\r
1444 // Fill PRDT table of Command UPIU for executed SCSI cmd.\r
1445 //\r
1446 PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));\r
1447 ASSERT (PrdtBase != NULL);\r
1448 UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);\r
1449\r
1450 return EFI_SUCCESS;\r
1451}\r
1452\r
0591696e
FT
1453/**\r
1454 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.\r
1455\r
1456 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1457 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.\r
1458 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the\r
1459 UFS device.\r
0350b57c
HW
1460 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking\r
1461 I/O is performed. If Event is NULL, then blocking I/O is performed. If\r
1462 Event is not NULL and non blocking I/O is supported, then\r
1463 nonblocking I/O is performed, and Event will be signaled when the\r
1464 SCSI Request Packet completes.\r
0591696e
FT
1465\r
1466 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional\r
1467 commands, InTransferLength bytes were transferred from\r
1468 InDataBuffer. For write and bi-directional commands,\r
1469 OutTransferLength bytes were transferred by\r
1470 OutDataBuffer.\r
1471 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request\r
1472 Packet.\r
1473 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1474 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.\r
1475\r
1476**/\r
1477EFI_STATUS\r
1478UfsExecScsiCmds (\r
1479 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1480 IN UINT8 Lun,\r
0350b57c
HW
1481 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
1482 IN EFI_EVENT Event OPTIONAL\r
0591696e
FT
1483 )\r
1484{\r
1485 EFI_STATUS Status;\r
0591696e
FT
1486 UTP_RESPONSE_UPIU *Response;\r
1487 UINT16 SenseDataLen;\r
1488 UINT32 ResTranCount;\r
0350b57c
HW
1489 EFI_TPL OldTpl;\r
1490 UFS_PASS_THRU_TRANS_REQ *TransReq;\r
a37e18f6 1491 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
0591696e 1492\r
a37e18f6 1493 TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));\r
0350b57c
HW
1494 if (TransReq == NULL) {\r
1495 return EFI_OUT_OF_RESOURCES;\r
1496 }\r
1497\r
1498 TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG;\r
1499 TransReq->TimeoutRemain = Packet->Timeout;\r
a37e18f6
AM
1500 TransReq->Packet = Packet;\r
1501\r
0591696e
FT
1502 UfsHc = Private->UfsHostController;\r
1503 //\r
1504 // Find out which slot of transfer request list is available.\r
1505 //\r
0350b57c 1506 Status = UfsFindAvailableSlotInTrl (Private, &TransReq->Slot);\r
0591696e
FT
1507 if (EFI_ERROR (Status)) {\r
1508 return Status;\r
1509 }\r
1510\r
0350b57c 1511 TransReq->Trd = ((UTP_TRD*)Private->UtpTrlBase) + TransReq->Slot;\r
0591696e
FT
1512\r
1513 //\r
1514 // Fill transfer request descriptor to this slot.\r
1515 //\r
0350b57c
HW
1516 Status = UfsCreateScsiCommandDesc (\r
1517 Private,\r
1518 Lun,\r
1519 Packet,\r
1520 TransReq->Trd,\r
1521 &TransReq->CmdDescHost,\r
1522 &TransReq->CmdDescMapping\r
1523 );\r
0591696e
FT
1524 if (EFI_ERROR (Status)) {\r
1525 return Status;\r
1526 }\r
1527\r
0350b57c 1528 TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD);\r
0591696e 1529\r
a37e18f6
AM
1530 Status = UfsPrepareDataTransferBuffer (Private, TransReq);\r
1531 if (EFI_ERROR (Status)) {\r
1532 goto Exit1;\r
0591696e 1533 }\r
0591696e 1534\r
0350b57c
HW
1535 //\r
1536 // Insert the async SCSI cmd to the Async I/O list\r
1537 //\r
1538 if (Event != NULL) {\r
7e4632a3 1539 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
0350b57c
HW
1540 TransReq->CallerEvent = Event;\r
1541 InsertTailList (&Private->Queue, &TransReq->TransferList);\r
1542 gBS->RestoreTPL (OldTpl);\r
1543 }\r
1544\r
0591696e
FT
1545 //\r
1546 // Start to execute the transfer request.\r
1547 //\r
0350b57c
HW
1548 UfsStartExecCmd (Private, TransReq->Slot);\r
1549\r
1550 //\r
1551 // Immediately return for async I/O.\r
1552 //\r
1553 if (Event != NULL) {\r
1554 return EFI_SUCCESS;\r
1555 }\r
0591696e
FT
1556\r
1557 //\r
1558 // Wait for the completion of the transfer request.\r
d1102dba 1559 //\r
13fca387 1560 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << TransReq->Slot, 0, Packet->Timeout);\r
0591696e
FT
1561 if (EFI_ERROR (Status)) {\r
1562 goto Exit;\r
1563 }\r
1564\r
1565 //\r
1566 // Get sense data if exists\r
1567 //\r
0350b57c 1568 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));\r
0591696e
FT
1569 ASSERT (Response != NULL);\r
1570 SenseDataLen = Response->SenseDataLen;\r
1571 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));\r
d1102dba 1572\r
0591696e 1573 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
8894c90d
HW
1574 //\r
1575 // Make sure the hardware device does not return more data than expected.\r
1576 //\r
1577 if (SenseDataLen <= Packet->SenseDataLength) {\r
1578 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
1579 Packet->SenseDataLength = (UINT8)SenseDataLen;\r
1580 } else {\r
1581 Packet->SenseDataLength = 0;\r
1582 }\r
0591696e
FT
1583 }\r
1584\r
1585 //\r
1586 // Check the transfer request result.\r
1587 //\r
1588 Packet->TargetStatus = Response->Status;\r
1589 if (Response->Response != 0) {\r
edd94e74 1590 DEBUG ((DEBUG_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));\r
0591696e
FT
1591 Status = EFI_DEVICE_ERROR;\r
1592 goto Exit;\r
1593 }\r
1594\r
0350b57c 1595 if (TransReq->Trd->Ocs == 0) {\r
0591696e
FT
1596 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1597 if ((Response->Flags & BIT5) == BIT5) {\r
1598 ResTranCount = Response->ResTranCount;\r
1599 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
1600 Packet->InTransferLength -= ResTranCount;\r
1601 }\r
1602 } else {\r
1603 if ((Response->Flags & BIT5) == BIT5) {\r
1604 ResTranCount = Response->ResTranCount;\r
1605 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
1606 Packet->OutTransferLength -= ResTranCount;\r
1607 }\r
1608 }\r
1609 } else {\r
1610 Status = EFI_DEVICE_ERROR;\r
1611 }\r
1612\r
1613Exit:\r
1614 UfsHc->Flush (UfsHc);\r
1615\r
0350b57c 1616 UfsStopExecCmd (Private, TransReq->Slot);\r
0591696e 1617\r
a37e18f6 1618 UfsReconcileDataTransferBuffer (Private, TransReq);\r
0591696e
FT
1619\r
1620Exit1:\r
0350b57c
HW
1621 if (TransReq->CmdDescMapping != NULL) {\r
1622 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);\r
0591696e 1623 }\r
0350b57c
HW
1624 if (TransReq->CmdDescHost != NULL) {\r
1625 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), TransReq->CmdDescHost);\r
1626 }\r
1627 if (TransReq != NULL) {\r
1628 FreePool (TransReq);\r
0591696e
FT
1629 }\r
1630 return Status;\r
1631}\r
1632\r
0591696e 1633/**\r
f426d874 1634 Send UIC command.\r
0591696e 1635\r
90952ad7
AM
1636 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1637 @param[in, out] UicCommand UIC command descriptor. On exit contains UIC command results.\r
0591696e
FT
1638\r
1639 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.\r
1640 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.\r
0591696e
FT
1641\r
1642**/\r
1643EFI_STATUS\r
1644UfsExecUicCommands (\r
1645 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
90952ad7 1646 IN OUT EDKII_UIC_COMMAND *UicCommand\r
0591696e
FT
1647 )\r
1648{\r
1649 EFI_STATUS Status;\r
0591696e 1650 UINT32 Data;\r
0591696e 1651\r
095f0779
FT
1652 Status = UfsMmioRead32 (Private, UFS_HC_IS_OFFSET, &Data);\r
1653 if (EFI_ERROR (Status)) {\r
1654 return Status;\r
1655 }\r
1656\r
0591696e
FT
1657 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {\r
1658 //\r
1659 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.\r
1660 //\r
095f0779
FT
1661 Status = UfsMmioWrite32 (Private, UFS_HC_IS_OFFSET, Data);\r
1662 if (EFI_ERROR (Status)) {\r
1663 return Status;\r
1664 }\r
0591696e
FT
1665 }\r
1666\r
1667 //\r
1668 // When programming UIC command registers, host software shall set the register UICCMD\r
1669 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)\r
1670 // are set.\r
1671 //\r
90952ad7 1672 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, UicCommand->Arg1);\r
095f0779
FT
1673 if (EFI_ERROR (Status)) {\r
1674 return Status;\r
1675 }\r
0591696e 1676\r
90952ad7 1677 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, UicCommand->Arg2);\r
095f0779
FT
1678 if (EFI_ERROR (Status)) {\r
1679 return Status;\r
1680 }\r
0591696e 1681\r
90952ad7 1682 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, UicCommand->Arg3);\r
095f0779
FT
1683 if (EFI_ERROR (Status)) {\r
1684 return Status;\r
1685 }\r
0591696e
FT
1686\r
1687 //\r
1688 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.\r
1689 //\r
095f0779 1690 Status = UfsWaitMemSet (Private, UFS_HC_STATUS_OFFSET, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);\r
0591696e
FT
1691 if (EFI_ERROR (Status)) {\r
1692 return Status;\r
1693 }\r
1694\r
90952ad7 1695 Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, UicCommand->Opcode);\r
095f0779
FT
1696 if (EFI_ERROR (Status)) {\r
1697 return Status;\r
1698 }\r
0591696e
FT
1699\r
1700 //\r
1701 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)\r
d1102dba 1702 // This bit is set to '1' by the host controller upon completion of a UIC command.\r
0591696e 1703 //\r
095f0779 1704 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);\r
0591696e
FT
1705 if (EFI_ERROR (Status)) {\r
1706 return Status;\r
1707 }\r
1708\r
90952ad7
AM
1709 if (UicCommand->Opcode != UfsUicDmeReset) {\r
1710 Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &UicCommand->Arg2);\r
095f0779
FT
1711 if (EFI_ERROR (Status)) {\r
1712 return Status;\r
1713 }\r
90952ad7
AM
1714 Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG3_OFFSET, &UicCommand->Arg3);\r
1715 if (EFI_ERROR (Status)) {\r
1716 return Status;\r
1717 }\r
1718 if ((UicCommand->Arg2 & 0xFF) != 0) {\r
0591696e 1719 DEBUG_CODE_BEGIN();\r
90952ad7 1720 DumpUicCmdExecResult ((UINT8)UicCommand->Opcode, (UINT8)(UicCommand->Arg2 & 0xFF));\r
0591696e
FT
1721 DEBUG_CODE_END();\r
1722 return EFI_DEVICE_ERROR;\r
1723 }\r
1724 }\r
1725\r
0591696e
FT
1726 return EFI_SUCCESS;\r
1727}\r
1728\r
1729/**\r
1730 Allocate common buffer for host and UFS bus master access simultaneously.\r
1731\r
1732 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1733 @param[in] Size The length of buffer to be allocated.\r
1734 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
1735 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.\r
1736 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
1737\r
1738 @retval EFI_SUCCESS The common buffer was allocated successfully.\r
1739 @retval EFI_DEVICE_ERROR The allocation fails.\r
1740 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
1741\r
1742**/\r
1743EFI_STATUS\r
1744UfsAllocateAlignCommonBuffer (\r
1745 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1746 IN UINTN Size,\r
1747 OUT VOID **CmdDescHost,\r
1748 OUT EFI_PHYSICAL_ADDRESS *CmdDescPhyAddr,\r
1749 OUT VOID **CmdDescMapping\r
1750 )\r
1751{\r
1752 EFI_STATUS Status;\r
1753 UINTN Bytes;\r
1754 BOOLEAN Is32BitAddr;\r
1755 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
1756\r
1757 if ((Private->Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {\r
0591696e 1758 Is32BitAddr = FALSE;\r
a2e3feb6
HZ
1759 } else {\r
1760 Is32BitAddr = TRUE;\r
0591696e
FT
1761 }\r
1762\r
1763 UfsHc = Private->UfsHostController;\r
1764 Status = UfsHc->AllocateBuffer (\r
1765 UfsHc,\r
1766 AllocateAnyPages,\r
1767 EfiBootServicesData,\r
1768 EFI_SIZE_TO_PAGES (Size),\r
1769 CmdDescHost,\r
1770 0\r
1771 );\r
1772 if (EFI_ERROR (Status)) {\r
1773 *CmdDescMapping = NULL;\r
1774 *CmdDescHost = NULL;\r
1775 *CmdDescPhyAddr = 0;\r
1776 return EFI_OUT_OF_RESOURCES;\r
1777 }\r
1778\r
1779 Bytes = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size));\r
1780 Status = UfsHc->Map (\r
1781 UfsHc,\r
1782 EdkiiUfsHcOperationBusMasterCommonBuffer,\r
1783 *CmdDescHost,\r
1784 &Bytes,\r
1785 CmdDescPhyAddr,\r
1786 CmdDescMapping\r
1787 );\r
1788\r
1789 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)))) {\r
1790 UfsHc->FreeBuffer (\r
1791 UfsHc,\r
1792 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),\r
1793 *CmdDescHost\r
1794 );\r
1795 *CmdDescHost = NULL;\r
1796 return EFI_OUT_OF_RESOURCES;\r
1797 }\r
1798\r
1799 if (Is32BitAddr && ((*CmdDescPhyAddr) > 0x100000000ULL)) {\r
1800 //\r
1801 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.\r
1802 //\r
1803 UfsHc->Unmap (\r
1804 UfsHc,\r
1805 *CmdDescMapping\r
1806 );\r
1807 UfsHc->FreeBuffer (\r
1808 UfsHc,\r
1809 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),\r
1810 *CmdDescHost\r
1811 );\r
1812 *CmdDescMapping = NULL;\r
1813 *CmdDescHost = NULL;\r
1814 return EFI_DEVICE_ERROR;\r
1815 }\r
1816\r
1817 ZeroMem (*CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)));\r
1818 return EFI_SUCCESS;\r
1819}\r
1820\r
1821/**\r
1822 Enable the UFS host controller for accessing.\r
1823\r
1824 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1825\r
1826 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.\r
1827 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.\r
1828\r
1829**/\r
1830EFI_STATUS\r
1831UfsEnableHostController (\r
1832 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1833 )\r
1834{\r
1835 EFI_STATUS Status;\r
0591696e
FT
1836 UINT32 Data;\r
1837\r
1838 //\r
1839 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization\r
1840 //\r
1841 // Reinitialize the UFS host controller if HCE bit of HC register is set.\r
1842 //\r
095f0779
FT
1843 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);\r
1844 if (EFI_ERROR (Status)) {\r
1845 return Status;\r
1846 }\r
1847\r
0591696e
FT
1848 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {\r
1849 //\r
1850 // Write a 0 to the HCE register at first to disable the host controller.\r
1851 //\r
095f0779
FT
1852 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);\r
1853 if (EFI_ERROR (Status)) {\r
1854 return Status;\r
1855 }\r
0591696e
FT
1856 //\r
1857 // Wait until HCE is read as '0' before continuing.\r
1858 //\r
095f0779 1859 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
0591696e
FT
1860 if (EFI_ERROR (Status)) {\r
1861 return EFI_DEVICE_ERROR;\r
1862 }\r
1863 }\r
1864\r
1865 //\r
1866 // Write a 1 to the HCE register to enable the UFS host controller.\r
1867 //\r
095f0779
FT
1868 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN);\r
1869 if (EFI_ERROR (Status)) {\r
1870 return Status;\r
1871 }\r
1872\r
0591696e
FT
1873 //\r
1874 // Wait until HCE is read as '1' before continuing.\r
1875 //\r
095f0779 1876 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);\r
0591696e
FT
1877 if (EFI_ERROR (Status)) {\r
1878 return EFI_DEVICE_ERROR;\r
1879 }\r
1880\r
1881 return EFI_SUCCESS;\r
1882}\r
1883\r
1884/**\r
1885 Detect if a UFS device attached.\r
1886\r
1887 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1888\r
1889 @retval EFI_SUCCESS The UFS device detection was executed successfully.\r
1890 @retval EFI_NOT_FOUND Not found a UFS device attached.\r
1891 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.\r
1892\r
1893**/\r
1894EFI_STATUS\r
1895UfsDeviceDetection (\r
1896 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1897 )\r
1898{\r
90952ad7
AM
1899 UINTN Retry;\r
1900 EFI_STATUS Status;\r
1901 UINT32 Data;\r
1902 EDKII_UIC_COMMAND LinkStartupCommand;\r
0591696e
FT
1903\r
1904 //\r
1905 // Start UFS device detection.\r
1906 // Try up to 3 times for establishing data link with device.\r
1907 //\r
1908 for (Retry = 0; Retry < 3; Retry++) {\r
90952ad7
AM
1909 LinkStartupCommand.Opcode = UfsUicDmeLinkStartup;\r
1910 LinkStartupCommand.Arg1 = 0;\r
1911 LinkStartupCommand.Arg2 = 0;\r
1912 LinkStartupCommand.Arg3 = 0;\r
1913 Status = UfsExecUicCommands (Private, &LinkStartupCommand);\r
f426d874
AM
1914 if (EFI_ERROR (Status)) {\r
1915 return EFI_DEVICE_ERROR;\r
0591696e
FT
1916 }\r
1917\r
f426d874
AM
1918 Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data);\r
1919 if (EFI_ERROR (Status)) {\r
1920 return EFI_DEVICE_ERROR;\r
0591696e
FT
1921 }\r
1922\r
f426d874
AM
1923 if ((Data & UFS_HC_HCS_DP) == 0) {\r
1924 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);\r
1925 if (EFI_ERROR (Status)) {\r
1926 return EFI_DEVICE_ERROR;\r
1927 }\r
1928 } else {\r
1929 return EFI_SUCCESS;\r
1930 }\r
0591696e
FT
1931 }\r
1932\r
f426d874 1933 return EFI_NOT_FOUND;\r
0591696e
FT
1934}\r
1935\r
1936/**\r
1937 Initialize UFS task management request list related h/w context.\r
1938\r
1939 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1940\r
1941 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.\r
1942 @retval EFI_DEVICE_ERROR The initialization fails.\r
1943\r
1944**/\r
1945EFI_STATUS\r
1946UfsInitTaskManagementRequestList (\r
1947 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1948 )\r
1949{\r
0591696e
FT
1950 UINT32 Data;\r
1951 UINT8 Nutmrs;\r
1952 VOID *CmdDescHost;\r
1953 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
1954 VOID *CmdDescMapping;\r
1955 EFI_STATUS Status;\r
d1102dba 1956\r
0591696e
FT
1957 //\r
1958 // Initial h/w and s/w context for future operations.\r
1959 //\r
1960 CmdDescHost = NULL;\r
1961 CmdDescMapping = NULL;\r
1962 CmdDescPhyAddr = 0;\r
095f0779
FT
1963\r
1964 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);\r
1965 if (EFI_ERROR (Status)) {\r
1966 return Status;\r
1967 }\r
1968\r
0591696e
FT
1969 Private->Capabilities = Data;\r
1970\r
1971 //\r
1972 // Allocate and initialize UTP Task Management Request List.\r
1973 //\r
1974 Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);\r
1975 Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
1976 if (EFI_ERROR (Status)) {\r
1977 return Status;\r
1978 }\r
1979\r
1980 //\r
1981 // Program the UTP Task Management Request List Base Address and UTP Task Management\r
1982 // Request List Base Address with a 64-bit address allocated at step 6.\r
1983 //\r
095f0779
FT
1984 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);\r
1985 if (EFI_ERROR (Status)) {\r
1986 return Status;\r
1987 }\r
1988\r
1989 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
1990 if (EFI_ERROR (Status)) {\r
1991 return Status;\r
1992 }\r
0591696e
FT
1993 Private->UtpTmrlBase = CmdDescHost;\r
1994 Private->Nutmrs = Nutmrs;\r
1995 Private->TmrlMapping = CmdDescMapping;\r
1996\r
1997 //\r
1998 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
1999 // Request List RunStop Register (UTMRLRSR) to '1'.\r
2000 //\r
095f0779
FT
2001 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, UFS_HC_UTMRLRSR);\r
2002 if (EFI_ERROR (Status)) {\r
2003 return Status;\r
2004 }\r
0591696e
FT
2005\r
2006 return EFI_SUCCESS;\r
2007}\r
2008\r
2009/**\r
2010 Initialize UFS transfer request list related h/w context.\r
2011\r
2012 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
2013\r
2014 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.\r
2015 @retval EFI_DEVICE_ERROR The initialization fails.\r
2016\r
2017**/\r
2018EFI_STATUS\r
2019UfsInitTransferRequestList (\r
2020 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
2021 )\r
2022{\r
0591696e
FT
2023 UINT32 Data;\r
2024 UINT8 Nutrs;\r
2025 VOID *CmdDescHost;\r
2026 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
d1102dba 2027 VOID *CmdDescMapping;\r
0591696e
FT
2028 EFI_STATUS Status;\r
2029\r
2030 //\r
2031 // Initial h/w and s/w context for future operations.\r
2032 //\r
2033 CmdDescHost = NULL;\r
2034 CmdDescMapping = NULL;\r
2035 CmdDescPhyAddr = 0;\r
095f0779
FT
2036\r
2037 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);\r
2038 if (EFI_ERROR (Status)) {\r
2039 return Status;\r
2040 }\r
2041\r
0591696e
FT
2042 Private->Capabilities = Data;\r
2043\r
2044 //\r
2045 // Allocate and initialize UTP Transfer Request List.\r
2046 //\r
2047 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
2048 Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
2049 if (EFI_ERROR (Status)) {\r
2050 return Status;\r
2051 }\r
2052\r
2053 //\r
2054 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List\r
2055 // Base Address with a 64-bit address allocated at step 8.\r
2056 //\r
095f0779
FT
2057 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);\r
2058 if (EFI_ERROR (Status)) {\r
2059 return Status;\r
2060 }\r
2061\r
2062 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
2063 if (EFI_ERROR (Status)) {\r
2064 return Status;\r
2065 }\r
2066\r
0591696e 2067 Private->UtpTrlBase = CmdDescHost;\r
d1102dba 2068 Private->Nutrs = Nutrs;\r
0591696e
FT
2069 Private->TrlMapping = CmdDescMapping;\r
2070\r
2071 //\r
2072 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
2073 // RunStop Register (UTRLRSR) to '1'.\r
2074 //\r
095f0779
FT
2075 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);\r
2076 if (EFI_ERROR (Status)) {\r
2077 return Status;\r
2078 }\r
0591696e
FT
2079\r
2080 return EFI_SUCCESS;\r
2081}\r
2082\r
2083/**\r
2084 Initialize the UFS host controller.\r
2085\r
2086 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
2087\r
2088 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.\r
2089 @retval Others A device error occurred while initializing the controller.\r
2090\r
2091**/\r
2092EFI_STATUS\r
2093UfsControllerInit (\r
2094 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
2095 )\r
2096{\r
2097 EFI_STATUS Status;\r
2098\r
2099 Status = UfsEnableHostController (Private);\r
2100 if (EFI_ERROR (Status)) {\r
edd94e74 2101 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status));\r
0591696e
FT
2102 return Status;\r
2103 }\r
2104\r
2105 Status = UfsDeviceDetection (Private);\r
2106 if (EFI_ERROR (Status)) {\r
edd94e74 2107 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status));\r
0591696e
FT
2108 return Status;\r
2109 }\r
2110\r
2111 Status = UfsInitTaskManagementRequestList (Private);\r
2112 if (EFI_ERROR (Status)) {\r
edd94e74 2113 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status));\r
0591696e
FT
2114 return Status;\r
2115 }\r
2116\r
2117 Status = UfsInitTransferRequestList (Private);\r
2118 if (EFI_ERROR (Status)) {\r
edd94e74 2119 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status));\r
0591696e
FT
2120 return Status;\r
2121 }\r
2122\r
edd94e74 2123 DEBUG ((DEBUG_INFO, "UfsControllerInit Finished\n"));\r
0591696e
FT
2124 return EFI_SUCCESS;\r
2125}\r
2126\r
2127/**\r
2128 Stop the UFS host controller.\r
2129\r
2130 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
2131\r
2132 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.\r
2133 @retval Others A device error occurred while stopping the controller.\r
2134\r
2135**/\r
2136EFI_STATUS\r
2137UfsControllerStop (\r
2138 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
2139 )\r
2140{\r
2141 EFI_STATUS Status;\r
0591696e
FT
2142 UINT32 Data;\r
2143\r
2144 //\r
2145 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
2146 // Request List RunStop Register (UTMRLRSR) to '1'.\r
2147 //\r
095f0779
FT
2148 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, 0);\r
2149 if (EFI_ERROR (Status)) {\r
2150 return Status;\r
2151 }\r
0591696e
FT
2152\r
2153 //\r
2154 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
2155 // RunStop Register (UTRLRSR) to '1'.\r
2156 //\r
095f0779
FT
2157 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, 0);\r
2158 if (EFI_ERROR (Status)) {\r
2159 return Status;\r
2160 }\r
0591696e
FT
2161\r
2162 //\r
2163 // Write a 0 to the HCE register in order to disable the host controller.\r
2164 //\r
095f0779
FT
2165 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);\r
2166 if (EFI_ERROR (Status)) {\r
2167 return Status;\r
2168 }\r
0591696e 2169 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);\r
095f0779
FT
2170\r
2171 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);\r
2172 if (EFI_ERROR (Status)) {\r
2173 return Status;\r
2174 }\r
0591696e
FT
2175\r
2176 //\r
2177 // Wait until HCE is read as '0' before continuing.\r
2178 //\r
095f0779 2179 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
0591696e
FT
2180 if (EFI_ERROR (Status)) {\r
2181 return EFI_DEVICE_ERROR;\r
2182 }\r
2183\r
edd94e74 2184 DEBUG ((DEBUG_INFO, "UfsController is stopped\n"));\r
0591696e
FT
2185\r
2186 return EFI_SUCCESS;\r
2187}\r
2188\r
0350b57c
HW
2189/**\r
2190 Internal helper function which will signal the caller event and clean up\r
2191 resources.\r
2192\r
2193 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data\r
2194 structure.\r
2195 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data\r
2196 structure.\r
2197\r
2198**/\r
2199VOID\r
2200EFIAPI\r
2201SignalCallerEvent (\r
2202 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
2203 IN UFS_PASS_THRU_TRANS_REQ *TransReq\r
2204 )\r
2205{\r
2206 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
2207 EFI_EVENT CallerEvent;\r
2208\r
33e2ba78
HW
2209 ASSERT ((Private != NULL) && (TransReq != NULL));\r
2210\r
0350b57c
HW
2211 UfsHc = Private->UfsHostController;\r
2212 CallerEvent = TransReq->CallerEvent;\r
2213\r
2214 RemoveEntryList (&TransReq->TransferList);\r
2215\r
2216 UfsHc->Flush (UfsHc);\r
2217\r
2218 UfsStopExecCmd (Private, TransReq->Slot);\r
2219\r
a37e18f6 2220 UfsReconcileDataTransferBuffer (Private, TransReq);\r
0350b57c
HW
2221\r
2222 if (TransReq->CmdDescMapping != NULL) {\r
2223 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);\r
2224 }\r
2225 if (TransReq->CmdDescHost != NULL) {\r
2226 UfsHc->FreeBuffer (\r
2227 UfsHc,\r
2228 EFI_SIZE_TO_PAGES (TransReq->CmdDescSize),\r
2229 TransReq->CmdDescHost\r
2230 );\r
2231 }\r
33e2ba78
HW
2232\r
2233 FreePool (TransReq);\r
0350b57c
HW
2234\r
2235 gBS->SignalEvent (CallerEvent);\r
2236 return;\r
2237}\r
2238\r
2239/**\r
2240 Call back function when the timer event is signaled.\r
2241\r
2242 @param[in] Event The Event this notify function registered to.\r
2243 @param[in] Context Pointer to the context data registered to the Event.\r
2244\r
2245**/\r
2246VOID\r
2247EFIAPI\r
2248ProcessAsyncTaskList (\r
2249 IN EFI_EVENT Event,\r
2250 IN VOID *Context\r
2251 )\r
2252{\r
2253 UFS_PASS_THRU_PRIVATE_DATA *Private;\r
2254 LIST_ENTRY *Entry;\r
2255 LIST_ENTRY *NextEntry;\r
2256 UFS_PASS_THRU_TRANS_REQ *TransReq;\r
2257 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet;\r
2258 UTP_RESPONSE_UPIU *Response;\r
2259 UINT16 SenseDataLen;\r
2260 UINT32 ResTranCount;\r
2261 UINT32 SlotsMap;\r
2262 UINT32 Value;\r
2263 EFI_STATUS Status;\r
2264\r
2265 Private = (UFS_PASS_THRU_PRIVATE_DATA*) Context;\r
2266 SlotsMap = 0;\r
2267\r
2268 //\r
2269 // Check the entries in the async I/O queue are done or not.\r
2270 //\r
2271 if (!IsListEmpty(&Private->Queue)) {\r
2272 EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {\r
2273 TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);\r
2274 Packet = TransReq->Packet;\r
2275\r
2276 if ((SlotsMap & (BIT0 << TransReq->Slot)) != 0) {\r
2277 return;\r
2278 }\r
2279 SlotsMap |= BIT0 << TransReq->Slot;\r
2280\r
2281 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Value);\r
2282 if (EFI_ERROR (Status)) {\r
2283 //\r
2284 // TODO: Should find/add a proper host adapter return status for this\r
2285 // case.\r
2286 //\r
2287 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;\r
edd94e74 2288 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq->CallerEvent));\r
0350b57c
HW
2289 SignalCallerEvent (Private, TransReq);\r
2290 continue;\r
2291 }\r
2292\r
2293 if ((Value & (BIT0 << TransReq->Slot)) != 0) {\r
2294 //\r
2295 // Scsi cmd not finished yet.\r
2296 //\r
2297 if (TransReq->TimeoutRemain > UFS_HC_ASYNC_TIMER) {\r
2298 TransReq->TimeoutRemain -= UFS_HC_ASYNC_TIMER;\r
2299 continue;\r
2300 } else {\r
2301 //\r
2302 // Timeout occurs.\r
2303 //\r
2304 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;\r
edd94e74 2305 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq->CallerEvent));\r
0350b57c
HW
2306 SignalCallerEvent (Private, TransReq);\r
2307 continue;\r
2308 }\r
2309 } else {\r
2310 //\r
2311 // Scsi cmd finished.\r
2312 //\r
2313 // Get sense data if exists\r
2314 //\r
2315 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));\r
2316 ASSERT (Response != NULL);\r
2317 SenseDataLen = Response->SenseDataLen;\r
2318 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));\r
2319\r
2320 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
8894c90d
HW
2321 //\r
2322 // Make sure the hardware device does not return more data than expected.\r
2323 //\r
2324 if (SenseDataLen <= Packet->SenseDataLength) {\r
2325 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
2326 Packet->SenseDataLength = (UINT8)SenseDataLen;\r
2327 } else {\r
2328 Packet->SenseDataLength = 0;\r
2329 }\r
0350b57c
HW
2330 }\r
2331\r
2332 //\r
2333 // Check the transfer request result.\r
2334 //\r
2335 Packet->TargetStatus = Response->Status;\r
2336 if (Response->Response != 0) {\r
edd94e74 2337 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq->CallerEvent));\r
0350b57c
HW
2338 SignalCallerEvent (Private, TransReq);\r
2339 continue;\r
2340 }\r
2341\r
2342 if (TransReq->Trd->Ocs == 0) {\r
2343 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
2344 if ((Response->Flags & BIT5) == BIT5) {\r
2345 ResTranCount = Response->ResTranCount;\r
2346 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
2347 Packet->InTransferLength -= ResTranCount;\r
2348 }\r
2349 } else {\r
2350 if ((Response->Flags & BIT5) == BIT5) {\r
2351 ResTranCount = Response->ResTranCount;\r
2352 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
2353 Packet->OutTransferLength -= ResTranCount;\r
2354 }\r
2355 }\r
2356 } else {\r
edd94e74 2357 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq->CallerEvent));\r
0350b57c
HW
2358 SignalCallerEvent (Private, TransReq);\r
2359 continue;\r
2360 }\r
2361\r
edd94e74 2362 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq->CallerEvent));\r
0350b57c
HW
2363 SignalCallerEvent (Private, TransReq);\r
2364 }\r
2365 }\r
2366 }\r
2367}\r
2368\r