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