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
UfsPeimRequestSense(IN UFS_PEIM_HC_PRIVATE_DATA * Private,IN UINTN Lun,OUT VOID * DataBuffer,OUT UINT32 * DataBufferLength)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
UfsPeimTestUnitReady(IN UFS_PEIM_HC_PRIVATE_DATA * Private,IN UINTN Lun,OUT VOID * SenseData,OPTIONAL OUT UINT8 * SenseDataLength)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
UfsPeimInquiry(IN UFS_PEIM_HC_PRIVATE_DATA * Private,IN UINTN Lun,OUT VOID * Inquiry,OUT UINT32 * InquiryLength,OUT VOID * SenseData,OPTIONAL OUT UINT8 * SenseDataLength)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
UfsPeimReadCapacity(IN UFS_PEIM_HC_PRIVATE_DATA * Private,IN UINTN Lun,OUT VOID * DataBuffer,OUT UINT32 * DataLength,OUT VOID * SenseData,OPTIONAL OUT UINT8 * SenseDataLength)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
UfsPeimReadCapacity16(IN UFS_PEIM_HC_PRIVATE_DATA * Private,IN UINTN Lun,OUT VOID * DataBuffer,OUT UINT32 * DataLength,OUT VOID * SenseData,OPTIONAL OUT UINT8 * SenseDataLength)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
UfsPeimRead10(IN UFS_PEIM_HC_PRIVATE_DATA * Private,IN UINTN Lun,IN UINTN StartLba,IN UINT32 SectorNum,OUT VOID * DataBuffer,OUT UINT32 * DataLength,OUT VOID * SenseData,OPTIONAL OUT UINT8 * SenseDataLength)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
UfsPeimRead16(IN UFS_PEIM_HC_PRIVATE_DATA * Private,IN UINTN Lun,IN UINTN StartLba,IN UINT32 SectorNum,OUT VOID * DataBuffer,OUT UINT32 * DataLength,OUT VOID * SenseData,OPTIONAL OUT UINT8 * SenseDataLength)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
UfsPeimParsingSenseKeys(IN EFI_PEI_BLOCK_IO2_MEDIA * Media,IN EFI_SCSI_SENSE_DATA * SenseData,OUT BOOLEAN * NeedRetry)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
UfsBlockIoPeimGetDeviceNo(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * This,OUT UINTN * NumberBlockDevices)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
UfsBlockIoPeimGetMediaInfo(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * This,IN UINTN DeviceIndex,OUT EFI_PEI_BLOCK_IO_MEDIA * MediaInfo)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
UfsBlockIoPeimReadBlocks(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * This,IN UINTN DeviceIndex,IN EFI_PEI_LBA StartLBA,IN UINTN BufferSize,OUT VOID * Buffer)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
UfsBlockIoPeimGetDeviceNo2(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * This,OUT UINTN * NumberBlockDevices)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
UfsBlockIoPeimGetMediaInfo2(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * This,IN UINTN DeviceIndex,OUT EFI_PEI_BLOCK_IO2_MEDIA * MediaInfo)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
UfsBlockIoPeimReadBlocks2(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * This,IN UINTN DeviceIndex,IN EFI_PEI_LBA StartLBA,IN UINTN BufferSize,OUT VOID * Buffer)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
InitializeUfsBlockIoPeim(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)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