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