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