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