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