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