1 /** @file 2 3 Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 **/ 13 14 #include "UfsBlockIoPei.h" 15 16 // 17 // Template for UFS HC Peim Private Data. 18 // 19 UFS_PEIM_HC_PRIVATE_DATA gUfsHcPeimTemplate = { 20 UFS_PEIM_HC_SIG, // Signature 21 NULL, // Controller 22 NULL, // Pool 23 { // BlkIoPpi 24 UfsBlockIoPeimGetDeviceNo, 25 UfsBlockIoPeimGetMediaInfo, 26 UfsBlockIoPeimReadBlocks 27 }, 28 { // BlkIo2Ppi 29 EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION, 30 UfsBlockIoPeimGetDeviceNo2, 31 UfsBlockIoPeimGetMediaInfo2, 32 UfsBlockIoPeimReadBlocks2 33 }, 34 { // BlkIoPpiList 35 EFI_PEI_PPI_DESCRIPTOR_PPI, 36 &gEfiPeiVirtualBlockIoPpiGuid, 37 NULL 38 }, 39 { // BlkIo2PpiList 40 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, 41 &gEfiPeiVirtualBlockIo2PpiGuid, 42 NULL 43 }, 44 { // Media 45 { 46 MSG_UFS_DP, 47 FALSE, 48 TRUE, 49 FALSE, 50 0x1000, 51 0 52 }, 53 { 54 MSG_UFS_DP, 55 FALSE, 56 TRUE, 57 FALSE, 58 0x1000, 59 0 60 }, 61 { 62 MSG_UFS_DP, 63 FALSE, 64 TRUE, 65 FALSE, 66 0x1000, 67 0 68 }, 69 { 70 MSG_UFS_DP, 71 FALSE, 72 TRUE, 73 FALSE, 74 0x1000, 75 0 76 }, 77 { 78 MSG_UFS_DP, 79 FALSE, 80 TRUE, 81 FALSE, 82 0x1000, 83 0 84 }, 85 { 86 MSG_UFS_DP, 87 FALSE, 88 TRUE, 89 FALSE, 90 0x1000, 91 0 92 }, 93 { 94 MSG_UFS_DP, 95 FALSE, 96 TRUE, 97 FALSE, 98 0x1000, 99 0 100 }, 101 { 102 MSG_UFS_DP, 103 FALSE, 104 TRUE, 105 FALSE, 106 0x1000, 107 0 108 } 109 }, 110 0, // UfsHcBase 111 0, // Capabilities 112 0, // TaskTag 113 0, // UtpTrlBase 114 0, // Nutrs 115 0, // UtpTmrlBase 116 0, // Nutmrs 117 { // Luns 118 { 119 UFS_LUN_0, // Ufs Common Lun 0 120 UFS_LUN_1, // Ufs Common Lun 1 121 UFS_LUN_2, // Ufs Common Lun 2 122 UFS_LUN_3, // Ufs Common Lun 3 123 UFS_LUN_4, // Ufs Common Lun 4 124 UFS_LUN_5, // Ufs Common Lun 5 125 UFS_LUN_6, // Ufs Common Lun 6 126 UFS_LUN_7, // Ufs Common Lun 7 127 }, 128 0x0000, // By default exposing all Luns. 129 0x0 130 } 131 }; 132 133 /** 134 Execute Request Sense SCSI command on a specific UFS device. 135 136 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure. 137 @param[in] Lun The lun on which the SCSI cmd executed. 138 @param[out] DataBuffer A pointer to output sense data. 139 @param[out] DataBufferLength The length of output sense data. 140 141 @retval EFI_SUCCESS The command executed successfully. 142 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. 143 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. 144 145 **/ 146 EFI_STATUS 147 UfsPeimRequestSense ( 148 IN UFS_PEIM_HC_PRIVATE_DATA *Private, 149 IN UINTN Lun, 150 OUT VOID *DataBuffer, 151 OUT UINT32 *DataBufferLength 152 ) 153 { 154 UFS_SCSI_REQUEST_PACKET Packet; 155 UINT8 Cdb[UFS_SCSI_OP_LENGTH_SIX]; 156 EFI_STATUS Status; 157 158 ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET)); 159 ZeroMem (Cdb, sizeof (Cdb)); 160 161 Cdb[0] = EFI_SCSI_OP_REQUEST_SENSE; 162 163 Packet.Timeout = UFS_TIMEOUT; 164 Packet.Cdb = Cdb; 165 Packet.CdbLength = sizeof (Cdb); 166 Packet.DataDirection = UfsDataIn; 167 Packet.InDataBuffer = DataBuffer; 168 Packet.InTransferLength = *DataBufferLength; 169 Packet.SenseData = NULL; 170 Packet.SenseDataLength = 0; 171 172 Status = UfsExecScsiCmds (Private,(UINT8)Lun, &Packet); 173 174 if (!EFI_ERROR (Status)) { 175 *DataBufferLength = Packet.InTransferLength; 176 } 177 178 return Status; 179 } 180 181 /** 182 Execute TEST UNITY READY SCSI command on a specific UFS device. 183 184 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure. 185 @param[in] Lun The lun on which the SCSI cmd executed. 186 @param[out] SenseData A pointer to output sense data. 187 @param[out] SenseDataLength The length of output sense data. 188 189 @retval EFI_SUCCESS The command executed successfully. 190 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. 191 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. 192 193 **/ 194 EFI_STATUS 195 UfsPeimTestUnitReady ( 196 IN UFS_PEIM_HC_PRIVATE_DATA *Private, 197 IN UINTN Lun, 198 OUT VOID *SenseData, OPTIONAL 199 OUT UINT8 *SenseDataLength 200 ) 201 { 202 UFS_SCSI_REQUEST_PACKET Packet; 203 UINT8 Cdb[UFS_SCSI_OP_LENGTH_SIX]; 204 EFI_STATUS Status; 205 206 ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET)); 207 ZeroMem (Cdb, sizeof (Cdb)); 208 209 Cdb[0] = EFI_SCSI_OP_TEST_UNIT_READY; 210 211 Packet.Timeout = UFS_TIMEOUT; 212 Packet.Cdb = Cdb; 213 Packet.CdbLength = sizeof (Cdb); 214 Packet.DataDirection = UfsNoData; 215 Packet.SenseData = SenseData; 216 Packet.SenseDataLength = *SenseDataLength; 217 218 Status = UfsExecScsiCmds (Private,(UINT8)Lun, &Packet); 219 220 if (*SenseDataLength != 0) { 221 *SenseDataLength = Packet.SenseDataLength; 222 } 223 224 return Status; 225 } 226 227 /** 228 Execute INQUIRY SCSI command on a specific UFS device. 229 230 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure. 231 @param[in] Lun The lun on which the SCSI cmd executed. 232 @param[out] Inquiry A pointer to Inquiry data buffer. 233 @param[out] InquiryLengths The length of output Inquiry data. 234 @param[out] SenseData A pointer to output sense data. 235 @param[out] SenseDataLength The length of output sense data. 236 237 @retval EFI_SUCCESS The command executed successfully. 238 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. 239 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. 240 241 **/ 242 EFI_STATUS 243 UfsPeimInquiry ( 244 IN UFS_PEIM_HC_PRIVATE_DATA *Private, 245 IN UINTN Lun, 246 OUT VOID *Inquiry, 247 OUT UINT32 *InquiryLength, 248 OUT VOID *SenseData, OPTIONAL 249 OUT UINT8 *SenseDataLength 250 ) 251 { 252 UFS_SCSI_REQUEST_PACKET Packet; 253 UINT8 Cdb[UFS_SCSI_OP_LENGTH_SIX]; 254 EFI_STATUS Status; 255 256 ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET)); 257 ZeroMem (Cdb, sizeof (Cdb)); 258 259 Cdb[0] = EFI_SCSI_OP_INQUIRY; 260 Cdb[4] = sizeof (EFI_SCSI_INQUIRY_DATA); 261 262 Packet.Timeout = UFS_TIMEOUT; 263 Packet.Cdb = Cdb; 264 Packet.CdbLength = sizeof (Cdb); 265 Packet.InDataBuffer = Inquiry; 266 Packet.InTransferLength = *InquiryLength; 267 Packet.DataDirection = UfsDataIn; 268 Packet.SenseData = SenseData; 269 Packet.SenseDataLength = *SenseDataLength; 270 271 Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet); 272 273 if (*SenseDataLength != 0) { 274 *SenseDataLength = Packet.SenseDataLength; 275 } 276 277 if (!EFI_ERROR (Status)) { 278 *InquiryLength = Packet.InTransferLength; 279 } 280 281 return Status; 282 } 283 284 /** 285 Execute READ CAPACITY(10) SCSI command on a specific UFS device. 286 287 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure. 288 @param[in] Lun The lun on which the SCSI cmd executed. 289 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer. 290 @param[out] DataLength The length of output READ_CAPACITY data. 291 @param[out] SenseData A pointer to output sense data. 292 @param[out] SenseDataLength The length of output sense data. 293 294 @retval EFI_SUCCESS The command executed successfully. 295 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. 296 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. 297 298 **/ 299 EFI_STATUS 300 UfsPeimReadCapacity ( 301 IN UFS_PEIM_HC_PRIVATE_DATA *Private, 302 IN UINTN Lun, 303 OUT VOID *DataBuffer, 304 OUT UINT32 *DataLength, 305 OUT VOID *SenseData, OPTIONAL 306 OUT UINT8 *SenseDataLength 307 ) 308 { 309 UFS_SCSI_REQUEST_PACKET Packet; 310 UINT8 Cdb[UFS_SCSI_OP_LENGTH_TEN]; 311 EFI_STATUS Status; 312 313 ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET)); 314 ZeroMem (Cdb, sizeof (Cdb)); 315 316 Cdb[0] = EFI_SCSI_OP_READ_CAPACITY; 317 318 Packet.Timeout = UFS_TIMEOUT; 319 Packet.Cdb = Cdb; 320 Packet.CdbLength = sizeof (Cdb); 321 Packet.InDataBuffer = DataBuffer; 322 Packet.InTransferLength = *DataLength; 323 Packet.DataDirection = UfsDataIn; 324 Packet.SenseData = SenseData; 325 Packet.SenseDataLength = *SenseDataLength; 326 327 Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet); 328 329 if (*SenseDataLength != 0) { 330 *SenseDataLength = Packet.SenseDataLength; 331 } 332 333 if (!EFI_ERROR (Status)) { 334 *DataLength = Packet.InTransferLength; 335 } 336 337 return Status; 338 } 339 340 /** 341 Execute READ CAPACITY(16) SCSI command on a specific UFS device. 342 343 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure. 344 @param[in] Lun The lun on which the SCSI cmd executed. 345 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer. 346 @param[out] DataLength The length of output READ_CAPACITY data. 347 @param[out] SenseData A pointer to output sense data. 348 @param[out] SenseDataLength The length of output sense data. 349 350 @retval EFI_SUCCESS The command executed successfully. 351 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. 352 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. 353 354 **/ 355 EFI_STATUS 356 UfsPeimReadCapacity16 ( 357 IN UFS_PEIM_HC_PRIVATE_DATA *Private, 358 IN UINTN Lun, 359 OUT VOID *DataBuffer, 360 OUT UINT32 *DataLength, 361 OUT VOID *SenseData, OPTIONAL 362 OUT UINT8 *SenseDataLength 363 ) 364 { 365 UFS_SCSI_REQUEST_PACKET Packet; 366 UINT8 Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN]; 367 EFI_STATUS Status; 368 369 ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET)); 370 ZeroMem (Cdb, sizeof (Cdb)); 371 372 Cdb[0] = EFI_SCSI_OP_READ_CAPACITY16; 373 Cdb[1] = 0x10; // Service Action should be 0x10 for UFS device. 374 Cdb[13] = 0x20; // The maximum number of bytes for returned data. 375 376 Packet.Timeout = UFS_TIMEOUT; 377 Packet.Cdb = Cdb; 378 Packet.CdbLength = sizeof (Cdb); 379 Packet.InDataBuffer = DataBuffer; 380 Packet.InTransferLength = *DataLength; 381 Packet.DataDirection = UfsDataIn; 382 Packet.SenseData = SenseData; 383 Packet.SenseDataLength = *SenseDataLength; 384 385 Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet); 386 387 if (*SenseDataLength != 0) { 388 *SenseDataLength = Packet.SenseDataLength; 389 } 390 391 if (!EFI_ERROR (Status)) { 392 *DataLength = Packet.InTransferLength; 393 } 394 395 return Status; 396 } 397 398 /** 399 Execute READ (10) SCSI command on a specific UFS device. 400 401 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure. 402 @param[in] Lun The lun on which the SCSI cmd executed. 403 @param[in] StartLba The start LBA. 404 @param[in] SectorNum The sector number to be read. 405 @param[out] DataBuffer A pointer to data buffer. 406 @param[out] DataLength The length of output data. 407 @param[out] SenseData A pointer to output sense data. 408 @param[out] SenseDataLength The length of output sense data. 409 410 @retval EFI_SUCCESS The command executed successfully. 411 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. 412 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. 413 414 **/ 415 EFI_STATUS 416 UfsPeimRead10 ( 417 IN UFS_PEIM_HC_PRIVATE_DATA *Private, 418 IN UINTN Lun, 419 IN UINTN StartLba, 420 IN UINT32 SectorNum, 421 OUT VOID *DataBuffer, 422 OUT UINT32 *DataLength, 423 OUT VOID *SenseData, OPTIONAL 424 OUT UINT8 *SenseDataLength 425 ) 426 { 427 UFS_SCSI_REQUEST_PACKET Packet; 428 UINT8 Cdb[UFS_SCSI_OP_LENGTH_TEN]; 429 EFI_STATUS Status; 430 431 ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET)); 432 ZeroMem (Cdb, sizeof (Cdb)); 433 434 Cdb[0] = EFI_SCSI_OP_READ10; 435 WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 ((UINT32) StartLba)); 436 WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorNum)); 437 438 Packet.Timeout = UFS_TIMEOUT; 439 Packet.Cdb = Cdb; 440 Packet.CdbLength = sizeof (Cdb); 441 Packet.InDataBuffer = DataBuffer; 442 Packet.InTransferLength = *DataLength; 443 Packet.DataDirection = UfsDataIn; 444 Packet.SenseData = SenseData; 445 Packet.SenseDataLength = *SenseDataLength; 446 447 Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet); 448 449 if (*SenseDataLength != 0) { 450 *SenseDataLength = Packet.SenseDataLength; 451 } 452 453 if (!EFI_ERROR (Status)) { 454 *DataLength = Packet.InTransferLength; 455 } 456 457 return Status; 458 } 459 460 /** 461 Execute READ (16) SCSI command on a specific UFS device. 462 463 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure. 464 @param[in] Lun The lun on which the SCSI cmd executed. 465 @param[in] StartLba The start LBA. 466 @param[in] SectorNum The sector number to be read. 467 @param[out] DataBuffer A pointer to data buffer. 468 @param[out] DataLength The length of output data. 469 @param[out] SenseData A pointer to output sense data. 470 @param[out] SenseDataLength The length of output sense data. 471 472 @retval EFI_SUCCESS The command executed successfully. 473 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet. 474 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute. 475 476 **/ 477 EFI_STATUS 478 UfsPeimRead16 ( 479 IN UFS_PEIM_HC_PRIVATE_DATA *Private, 480 IN UINTN Lun, 481 IN UINTN StartLba, 482 IN UINT32 SectorNum, 483 OUT VOID *DataBuffer, 484 OUT UINT32 *DataLength, 485 OUT VOID *SenseData, OPTIONAL 486 OUT UINT8 *SenseDataLength 487 ) 488 { 489 UFS_SCSI_REQUEST_PACKET Packet; 490 UINT8 Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN]; 491 EFI_STATUS Status; 492 493 ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET)); 494 ZeroMem (Cdb, sizeof (Cdb)); 495 496 Cdb[0] = EFI_SCSI_OP_READ16; 497 WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba)); 498 WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorNum)); 499 500 Packet.Timeout = UFS_TIMEOUT; 501 Packet.Cdb = Cdb; 502 Packet.CdbLength = sizeof (Cdb); 503 Packet.InDataBuffer = DataBuffer; 504 Packet.InTransferLength = *DataLength; 505 Packet.DataDirection = UfsDataIn; 506 Packet.SenseData = SenseData; 507 Packet.SenseDataLength = *SenseDataLength; 508 509 Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet); 510 511 if (*SenseDataLength != 0) { 512 *SenseDataLength = Packet.SenseDataLength; 513 } 514 515 if (!EFI_ERROR (Status)) { 516 *DataLength = Packet.InTransferLength; 517 } 518 519 return Status; 520 } 521 522 /** 523 Parsing Sense Keys from sense data. 524 525 @param Media The pointer of EFI_PEI_BLOCK_IO_MEDIA 526 @param SenseData The pointer of EFI_SCSI_SENSE_DATA 527 @param NeedRetry The pointer of action which indicates what is need to retry 528 529 @retval EFI_DEVICE_ERROR Indicates that error occurs 530 @retval EFI_SUCCESS Successfully to complete the parsing 531 532 **/ 533 EFI_STATUS 534 UfsPeimParsingSenseKeys ( 535 IN EFI_PEI_BLOCK_IO2_MEDIA *Media, 536 IN EFI_SCSI_SENSE_DATA *SenseData, 537 OUT BOOLEAN *NeedRetry 538 ) 539 { 540 if ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) && 541 (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) { 542 Media->MediaPresent = FALSE; 543 *NeedRetry = FALSE; 544 DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is No Media\n")); 545 return EFI_DEVICE_ERROR; 546 } 547 548 if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) && 549 (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) { 550 *NeedRetry = TRUE; 551 DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is Media Change\n")); 552 return EFI_SUCCESS; 553 } 554 555 if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) && 556 (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) { 557 *NeedRetry = TRUE; 558 DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n")); 559 return EFI_SUCCESS; 560 } 561 562 if ((SenseData->Sense_Key == EFI_SCSI_SK_MEDIUM_ERROR) || 563 ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) && 564 (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN))) { 565 *NeedRetry = FALSE; 566 DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Media Error\n")); 567 return EFI_DEVICE_ERROR; 568 } 569 570 if (SenseData->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) { 571 *NeedRetry = FALSE; 572 DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Hardware Error\n")); 573 return EFI_DEVICE_ERROR; 574 } 575 576 if ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) && 577 (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_NOT_READY) && 578 (SenseData->Addnl_Sense_Code_Qualifier == EFI_SCSI_ASCQ_IN_PROGRESS)) { 579 *NeedRetry = TRUE; 580 DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n")); 581 return EFI_SUCCESS; 582 } 583 584 *NeedRetry = FALSE; 585 DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code)); 586 return EFI_DEVICE_ERROR; 587 } 588 589 590 /** 591 Gets the count of block I/O devices that one specific block driver detects. 592 593 This function is used for getting the count of block I/O devices that one 594 specific block driver detects. To the PEI ATAPI driver, it returns the number 595 of all the detected ATAPI devices it detects during the enumeration process. 596 To the PEI legacy floppy driver, it returns the number of all the legacy 597 devices it finds during its enumeration process. If no device is detected, 598 then the function will return zero. 599 600 @param[in] PeiServices General-purpose services that are available 601 to every PEIM. 602 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI 603 instance. 604 @param[out] NumberBlockDevices The number of block I/O devices discovered. 605 606 @retval EFI_SUCCESS The operation performed successfully. 607 608 **/ 609 EFI_STATUS 610 EFIAPI 611 UfsBlockIoPeimGetDeviceNo ( 612 IN EFI_PEI_SERVICES **PeiServices, 613 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, 614 OUT UINTN *NumberBlockDevices 615 ) 616 { 617 // 618 // For Ufs device, it has up to 8 normal Luns plus some well-known Luns. 619 // At PEI phase, we will only expose normal Luns to user. 620 // For those disabled Lun, when user try to access it, the operation would fail. 621 // 622 *NumberBlockDevices = UFS_PEIM_MAX_LUNS; 623 return EFI_SUCCESS; 624 } 625 626 /** 627 Gets a block device's media information. 628 629 This function will provide the caller with the specified block device's media 630 information. If the media changes, calling this function will update the media 631 information accordingly. 632 633 @param[in] PeiServices General-purpose services that are available to every 634 PEIM 635 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. 636 @param[in] DeviceIndex Specifies the block device to which the function wants 637 to talk. Because the driver that implements Block I/O 638 PPIs will manage multiple block devices, the PPIs that 639 want to talk to a single device must specify the 640 device index that was assigned during the enumeration 641 process. This index is a number from one to 642 NumberBlockDevices. 643 @param[out] MediaInfo The media information of the specified block media. 644 The caller is responsible for the ownership of this 645 data structure. 646 647 @par Note: 648 The MediaInfo structure describes an enumeration of possible block device 649 types. This enumeration exists because no device paths are actually passed 650 across interfaces that describe the type or class of hardware that is publishing 651 the block I/O interface. This enumeration will allow for policy decisions 652 in the Recovery PEIM, such as "Try to recover from legacy floppy first, 653 LS-120 second, CD-ROM third." If there are multiple partitions abstracted 654 by a given device type, they should be reported in ascending order; this 655 order also applies to nested partitions, such as legacy MBR, where the 656 outermost partitions would have precedence in the reporting order. The 657 same logic applies to systems such as IDE that have precedence relationships 658 like "Master/Slave" or "Primary/Secondary". The master device should be 659 reported first, the slave second. 660 661 @retval EFI_SUCCESS Media information about the specified block device 662 was obtained successfully. 663 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware 664 error. 665 666 **/ 667 EFI_STATUS 668 EFIAPI 669 UfsBlockIoPeimGetMediaInfo ( 670 IN EFI_PEI_SERVICES **PeiServices, 671 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, 672 IN UINTN DeviceIndex, 673 OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo 674 ) 675 { 676 EFI_STATUS Status; 677 UFS_PEIM_HC_PRIVATE_DATA *Private; 678 EFI_SCSI_SENSE_DATA SenseData; 679 UINT8 SenseDataLength; 680 EFI_SCSI_DISK_CAPACITY_DATA Capacity; 681 EFI_SCSI_DISK_CAPACITY_DATA16 Capacity16; 682 UINTN DataLength; 683 BOOLEAN NeedRetry; 684 685 Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); 686 NeedRetry = TRUE; 687 688 if (DeviceIndex >= UFS_PEIM_MAX_LUNS) { 689 return EFI_INVALID_PARAMETER; 690 } 691 692 if ((Private->Luns.BitMask & (BIT0 << DeviceIndex)) == 0) { 693 return EFI_ACCESS_DENIED; 694 } 695 696 ZeroMem (&SenseData, sizeof (SenseData)); 697 ZeroMem (&Capacity, sizeof (Capacity)); 698 ZeroMem (&Capacity16, sizeof (Capacity16)); 699 SenseDataLength = sizeof (SenseData); 700 // 701 // First test unit ready 702 // 703 do { 704 Status = UfsPeimTestUnitReady ( 705 Private, 706 DeviceIndex, 707 &SenseData, 708 &SenseDataLength 709 ); 710 if (!EFI_ERROR (Status)) { 711 break; 712 } 713 714 if (SenseDataLength == 0) { 715 continue; 716 } 717 718 Status = UfsPeimParsingSenseKeys (&(Private->Media[DeviceIndex]), &SenseData, &NeedRetry); 719 if (EFI_ERROR (Status)) { 720 return EFI_DEVICE_ERROR; 721 } 722 723 } while (NeedRetry); 724 725 DataLength = sizeof (EFI_SCSI_DISK_CAPACITY_DATA); 726 SenseDataLength = 0; 727 Status = UfsPeimReadCapacity (Private, DeviceIndex, &Capacity, (UINT32 *)&DataLength, NULL, &SenseDataLength); 728 if (EFI_ERROR (Status)) { 729 return EFI_DEVICE_ERROR; 730 } 731 732 if ((Capacity.LastLba3 == 0xff) && (Capacity.LastLba2 == 0xff) && 733 (Capacity.LastLba1 == 0xff) && (Capacity.LastLba0 == 0xff)) { 734 DataLength = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16); 735 SenseDataLength = 0; 736 Status = UfsPeimReadCapacity16 (Private, DeviceIndex, &Capacity16, (UINT32 *)&DataLength, NULL, &SenseDataLength); 737 if (EFI_ERROR (Status)) { 738 return EFI_DEVICE_ERROR; 739 } 740 Private->Media[DeviceIndex].LastBlock = (Capacity16.LastLba3 << 24) | (Capacity16.LastLba2 << 16) | (Capacity16.LastLba1 << 8) | Capacity16.LastLba0; 741 Private->Media[DeviceIndex].LastBlock |= LShiftU64 ((UINT64)Capacity16.LastLba7, 56) | LShiftU64((UINT64)Capacity16.LastLba6, 48) | LShiftU64 ((UINT64)Capacity16.LastLba5, 40) | LShiftU64 ((UINT64)Capacity16.LastLba4, 32); 742 Private->Media[DeviceIndex].BlockSize = (Capacity16.BlockSize3 << 24) | (Capacity16.BlockSize2 << 16) | (Capacity16.BlockSize1 << 8) | Capacity16.BlockSize0; 743 } else { 744 Private->Media[DeviceIndex].LastBlock = (Capacity.LastLba3 << 24) | (Capacity.LastLba2 << 16) | (Capacity.LastLba1 << 8) | Capacity.LastLba0; 745 Private->Media[DeviceIndex].BlockSize = (Capacity.BlockSize3 << 24) | (Capacity.BlockSize2 << 16) | (Capacity.BlockSize1 << 8) | Capacity.BlockSize0; 746 } 747 748 MediaInfo->DeviceType = UfsDevice; 749 MediaInfo->MediaPresent = Private->Media[DeviceIndex].MediaPresent; 750 MediaInfo->LastBlock = (UINTN)Private->Media[DeviceIndex].LastBlock; 751 MediaInfo->BlockSize = Private->Media[DeviceIndex].BlockSize; 752 753 return EFI_SUCCESS; 754 } 755 756 /** 757 Reads the requested number of blocks from the specified block device. 758 759 The function reads the requested number of blocks from the device. All the 760 blocks are read, or an error is returned. If there is no media in the device, 761 the function returns EFI_NO_MEDIA. 762 763 @param[in] PeiServices General-purpose services that are available to 764 every PEIM. 765 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. 766 @param[in] DeviceIndex Specifies the block device to which the function wants 767 to talk. Because the driver that implements Block I/O 768 PPIs will manage multiple block devices, PPIs that 769 want to talk to a single device must specify the device 770 index that was assigned during the enumeration process. 771 This index is a number from one to NumberBlockDevices. 772 @param[in] StartLBA The starting logical block address (LBA) to read from 773 on the device 774 @param[in] BufferSize The size of the Buffer in bytes. This number must be 775 a multiple of the intrinsic block size of the device. 776 @param[out] Buffer A pointer to the destination buffer for the data. 777 The caller is responsible for the ownership of the 778 buffer. 779 780 @retval EFI_SUCCESS The data was read correctly from the device. 781 @retval EFI_DEVICE_ERROR The device reported an error while attempting 782 to perform the read operation. 783 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not 784 valid, or the buffer is not properly aligned. 785 @retval EFI_NO_MEDIA There is no media in the device. 786 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of 787 the intrinsic block size of the device. 788 789 **/ 790 EFI_STATUS 791 EFIAPI 792 UfsBlockIoPeimReadBlocks ( 793 IN EFI_PEI_SERVICES **PeiServices, 794 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, 795 IN UINTN DeviceIndex, 796 IN EFI_PEI_LBA StartLBA, 797 IN UINTN BufferSize, 798 OUT VOID *Buffer 799 ) 800 { 801 EFI_STATUS Status; 802 UINTN BlockSize; 803 UINTN NumberOfBlocks; 804 UFS_PEIM_HC_PRIVATE_DATA *Private; 805 EFI_SCSI_SENSE_DATA SenseData; 806 UINT8 SenseDataLength; 807 BOOLEAN NeedRetry; 808 809 Status = EFI_SUCCESS; 810 NeedRetry = TRUE; 811 Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); 812 813 ZeroMem (&SenseData, sizeof (SenseData)); 814 SenseDataLength = sizeof (SenseData); 815 816 // 817 // Check parameters 818 // 819 if (Buffer == NULL) { 820 return EFI_INVALID_PARAMETER; 821 } 822 823 if (BufferSize == 0) { 824 return EFI_SUCCESS; 825 } 826 827 if (DeviceIndex >= UFS_PEIM_MAX_LUNS) { 828 return EFI_INVALID_PARAMETER; 829 } 830 831 if ((Private->Luns.BitMask & (BIT0 << DeviceIndex)) == 0) { 832 return EFI_ACCESS_DENIED; 833 } 834 835 BlockSize = Private->Media[DeviceIndex].BlockSize; 836 837 if (BufferSize % BlockSize != 0) { 838 Status = EFI_BAD_BUFFER_SIZE; 839 } 840 841 if (StartLBA > Private->Media[DeviceIndex].LastBlock) { 842 Status = EFI_INVALID_PARAMETER; 843 } 844 845 NumberOfBlocks = BufferSize / BlockSize; 846 847 do { 848 Status = UfsPeimTestUnitReady ( 849 Private, 850 DeviceIndex, 851 &SenseData, 852 &SenseDataLength 853 ); 854 if (!EFI_ERROR (Status)) { 855 break; 856 } 857 858 if (SenseDataLength == 0) { 859 continue; 860 } 861 862 Status = UfsPeimParsingSenseKeys (&(Private->Media[DeviceIndex]), &SenseData, &NeedRetry); 863 if (EFI_ERROR (Status)) { 864 return EFI_DEVICE_ERROR; 865 } 866 867 } while (NeedRetry); 868 869 SenseDataLength = 0; 870 if (Private->Media[DeviceIndex].LastBlock < 0xfffffffful) { 871 Status = UfsPeimRead10 ( 872 Private, 873 DeviceIndex, 874 (UINT32)StartLBA, 875 (UINT32)NumberOfBlocks, 876 Buffer, 877 (UINT32 *)&BufferSize, 878 NULL, 879 &SenseDataLength 880 ); 881 } else { 882 Status = UfsPeimRead16 ( 883 Private, 884 DeviceIndex, 885 (UINT32)StartLBA, 886 (UINT32)NumberOfBlocks, 887 Buffer, 888 (UINT32 *)&BufferSize, 889 NULL, 890 &SenseDataLength 891 ); 892 } 893 return Status; 894 } 895 896 /** 897 Gets the count of block I/O devices that one specific block driver detects. 898 899 This function is used for getting the count of block I/O devices that one 900 specific block driver detects. To the PEI ATAPI driver, it returns the number 901 of all the detected ATAPI devices it detects during the enumeration process. 902 To the PEI legacy floppy driver, it returns the number of all the legacy 903 devices it finds during its enumeration process. If no device is detected, 904 then the function will return zero. 905 906 @param[in] PeiServices General-purpose services that are available 907 to every PEIM. 908 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI 909 instance. 910 @param[out] NumberBlockDevices The number of block I/O devices discovered. 911 912 @retval EFI_SUCCESS The operation performed successfully. 913 914 **/ 915 EFI_STATUS 916 EFIAPI 917 UfsBlockIoPeimGetDeviceNo2 ( 918 IN EFI_PEI_SERVICES **PeiServices, 919 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, 920 OUT UINTN *NumberBlockDevices 921 ) 922 { 923 // 924 // For Ufs device, it has up to 8 normal Luns plus some well-known Luns. 925 // At PEI phase, we will only expose normal Luns to user. 926 // For those disabled Lun, when user try to access it, the operation would fail. 927 // 928 *NumberBlockDevices = UFS_PEIM_MAX_LUNS; 929 return EFI_SUCCESS; 930 } 931 932 /** 933 Gets a block device's media information. 934 935 This function will provide the caller with the specified block device's media 936 information. If the media changes, calling this function will update the media 937 information accordingly. 938 939 @param[in] PeiServices General-purpose services that are available to every 940 PEIM 941 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. 942 @param[in] DeviceIndex Specifies the block device to which the function wants 943 to talk. Because the driver that implements Block I/O 944 PPIs will manage multiple block devices, the PPIs that 945 want to talk to a single device must specify the 946 device index that was assigned during the enumeration 947 process. This index is a number from one to 948 NumberBlockDevices. 949 @param[out] MediaInfo The media information of the specified block media. 950 The caller is responsible for the ownership of this 951 data structure. 952 953 @par Note: 954 The MediaInfo structure describes an enumeration of possible block device 955 types. This enumeration exists because no device paths are actually passed 956 across interfaces that describe the type or class of hardware that is publishing 957 the block I/O interface. This enumeration will allow for policy decisions 958 in the Recovery PEIM, such as "Try to recover from legacy floppy first, 959 LS-120 second, CD-ROM third." If there are multiple partitions abstracted 960 by a given device type, they should be reported in ascending order; this 961 order also applies to nested partitions, such as legacy MBR, where the 962 outermost partitions would have precedence in the reporting order. The 963 same logic applies to systems such as IDE that have precedence relationships 964 like "Master/Slave" or "Primary/Secondary". The master device should be 965 reported first, the slave second. 966 967 @retval EFI_SUCCESS Media information about the specified block device 968 was obtained successfully. 969 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware 970 error. 971 972 **/ 973 EFI_STATUS 974 EFIAPI 975 UfsBlockIoPeimGetMediaInfo2 ( 976 IN EFI_PEI_SERVICES **PeiServices, 977 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, 978 IN UINTN DeviceIndex, 979 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo 980 ) 981 { 982 EFI_STATUS Status; 983 UFS_PEIM_HC_PRIVATE_DATA *Private; 984 EFI_PEI_BLOCK_IO_MEDIA Media; 985 986 Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); 987 988 Status = UfsBlockIoPeimGetMediaInfo ( 989 PeiServices, 990 &Private->BlkIoPpi, 991 DeviceIndex, 992 &Media 993 ); 994 if (EFI_ERROR (Status)) { 995 return Status; 996 } 997 998 CopyMem (MediaInfo, &(Private->Media[DeviceIndex]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA)); 999 return EFI_SUCCESS; 1000 } 1001 1002 /** 1003 Reads the requested number of blocks from the specified block device. 1004 1005 The function reads the requested number of blocks from the device. All the 1006 blocks are read, or an error is returned. If there is no media in the device, 1007 the function returns EFI_NO_MEDIA. 1008 1009 @param[in] PeiServices General-purpose services that are available to 1010 every PEIM. 1011 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. 1012 @param[in] DeviceIndex Specifies the block device to which the function wants 1013 to talk. Because the driver that implements Block I/O 1014 PPIs will manage multiple block devices, PPIs that 1015 want to talk to a single device must specify the device 1016 index that was assigned during the enumeration process. 1017 This index is a number from one to NumberBlockDevices. 1018 @param[in] StartLBA The starting logical block address (LBA) to read from 1019 on the device 1020 @param[in] BufferSize The size of the Buffer in bytes. This number must be 1021 a multiple of the intrinsic block size of the device. 1022 @param[out] Buffer A pointer to the destination buffer for the data. 1023 The caller is responsible for the ownership of the 1024 buffer. 1025 1026 @retval EFI_SUCCESS The data was read correctly from the device. 1027 @retval EFI_DEVICE_ERROR The device reported an error while attempting 1028 to perform the read operation. 1029 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not 1030 valid, or the buffer is not properly aligned. 1031 @retval EFI_NO_MEDIA There is no media in the device. 1032 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of 1033 the intrinsic block size of the device. 1034 1035 **/ 1036 EFI_STATUS 1037 EFIAPI 1038 UfsBlockIoPeimReadBlocks2 ( 1039 IN EFI_PEI_SERVICES **PeiServices, 1040 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, 1041 IN UINTN DeviceIndex, 1042 IN EFI_PEI_LBA StartLBA, 1043 IN UINTN BufferSize, 1044 OUT VOID *Buffer 1045 ) 1046 { 1047 EFI_STATUS Status; 1048 UFS_PEIM_HC_PRIVATE_DATA *Private; 1049 1050 Status = EFI_SUCCESS; 1051 Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); 1052 1053 Status = UfsBlockIoPeimReadBlocks ( 1054 PeiServices, 1055 &Private->BlkIoPpi, 1056 DeviceIndex, 1057 StartLBA, 1058 BufferSize, 1059 Buffer 1060 ); 1061 return Status; 1062 } 1063 1064 /** 1065 The user code starts with this function. 1066 1067 @param FileHandle Handle of the file being invoked. 1068 @param PeiServices Describes the list of possible PEI Services. 1069 1070 @retval EFI_SUCCESS The driver is successfully initialized. 1071 @retval Others Can't initialize the driver. 1072 1073 **/ 1074 EFI_STATUS 1075 EFIAPI 1076 InitializeUfsBlockIoPeim ( 1077 IN EFI_PEI_FILE_HANDLE FileHandle, 1078 IN CONST EFI_PEI_SERVICES **PeiServices 1079 ) 1080 { 1081 EFI_STATUS Status; 1082 UFS_PEIM_HC_PRIVATE_DATA *Private; 1083 EDKII_UFS_HOST_CONTROLLER_PPI *UfsHcPpi; 1084 UINT32 Index; 1085 UFS_CONFIG_DESC Config; 1086 UINTN MmioBase; 1087 UINT8 Controller; 1088 1089 // 1090 // Shadow this PEIM to run from memory 1091 // 1092 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { 1093 return EFI_SUCCESS; 1094 } 1095 1096 // 1097 // locate ufs host controller PPI 1098 // 1099 Status = PeiServicesLocatePpi ( 1100 &gEdkiiPeiUfsHostControllerPpiGuid, 1101 0, 1102 NULL, 1103 (VOID **) &UfsHcPpi 1104 ); 1105 if (EFI_ERROR (Status)) { 1106 return EFI_DEVICE_ERROR; 1107 } 1108 1109 Controller = 0; 1110 MmioBase = 0; 1111 while (TRUE) { 1112 Status = UfsHcPpi->GetUfsHcMmioBar (UfsHcPpi, Controller, &MmioBase); 1113 // 1114 // When status is error, meant no controller is found 1115 // 1116 if (EFI_ERROR (Status)) { 1117 break; 1118 } 1119 1120 Private = AllocateCopyPool (sizeof (UFS_PEIM_HC_PRIVATE_DATA), &gUfsHcPeimTemplate); 1121 if (Private == NULL) { 1122 Status = EFI_OUT_OF_RESOURCES; 1123 break; 1124 } 1125 1126 Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi; 1127 Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi; 1128 Private->UfsHcBase = MmioBase; 1129 1130 // 1131 // Initialize the memory pool which will be used in all transactions. 1132 // 1133 Status = UfsPeimInitMemPool (Private); 1134 if (EFI_ERROR (Status)) { 1135 Status = EFI_OUT_OF_RESOURCES; 1136 break; 1137 } 1138 1139 // 1140 // Initialize UFS Host Controller H/W. 1141 // 1142 Status = UfsControllerInit (Private); 1143 if (EFI_ERROR (Status)) { 1144 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Host Controller Initialization Error, Status = %r\n", Status)); 1145 Controller++; 1146 continue; 1147 } 1148 1149 // 1150 // UFS 2.0 spec Section 13.1.3.3: 1151 // At the end of the UFS Interconnect Layer initialization on both host and device side, 1152 // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready. 1153 // 1154 Status = UfsExecNopCmds (Private); 1155 if (EFI_ERROR (Status)) { 1156 DEBUG ((EFI_D_ERROR, "Ufs Sending NOP IN command Error, Status = %r\n", Status)); 1157 Controller++; 1158 continue; 1159 } 1160 1161 // 1162 // The host enables the device initialization completion by setting fDeviceInit flag. 1163 // 1164 Status = UfsSetFlag (Private, UfsFlagDevInit); 1165 if (EFI_ERROR (Status)) { 1166 DEBUG ((EFI_D_ERROR, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status)); 1167 Controller++; 1168 continue; 1169 } 1170 1171 // 1172 // Get Ufs Device's Lun Info by reading Configuration Descriptor. 1173 // 1174 Status = UfsRwDeviceDesc (Private, TRUE, UfsConfigDesc, 0, 0, &Config, sizeof (UFS_CONFIG_DESC)); 1175 if (EFI_ERROR (Status)) { 1176 DEBUG ((EFI_D_ERROR, "Ufs Get Configuration Descriptor Error, Status = %r\n", Status)); 1177 Controller++; 1178 continue; 1179 } 1180 1181 for (Index = 0; Index < UFS_PEIM_MAX_LUNS; Index++) { 1182 if (Config.UnitDescConfParams[Index].LunEn != 0) { 1183 Private->Luns.BitMask |= (BIT0 << Index); 1184 DEBUG ((EFI_D_INFO, "Ufs %d Lun %d is enabled\n", Controller, Index)); 1185 } 1186 } 1187 1188 Status = PeiServicesInstallPpi (&Private->BlkIoPpiList); 1189 Controller++; 1190 } 1191 1192 return EFI_SUCCESS; 1193 } 1194