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