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