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