]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsBlockIoPei.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsBlockIoPei / UfsBlockIoPei.c
1 /** @file
2
3 Copyright (c) 2014 - 2019, 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
136 /**
137 Execute TEST UNITY READY SCSI command on a specific UFS device.
138
139 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
140 @param[in] Lun The lun on which the SCSI cmd executed.
141 @param[out] SenseData A pointer to output sense data.
142 @param[out] SenseDataLength The length of output sense data.
143
144 @retval EFI_SUCCESS The command executed successfully.
145 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
146 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
147
148 **/
149 EFI_STATUS
150 UfsPeimTestUnitReady (
151 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
152 IN UINTN Lun,
153 OUT VOID *SenseData, OPTIONAL
154 OUT UINT8 *SenseDataLength
155 )
156 {
157 UFS_SCSI_REQUEST_PACKET Packet;
158 UINT8 Cdb[UFS_SCSI_OP_LENGTH_SIX];
159 EFI_STATUS Status;
160
161 ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
162 ZeroMem (Cdb, sizeof (Cdb));
163
164 Cdb[0] = EFI_SCSI_OP_TEST_UNIT_READY;
165
166 Packet.Timeout = UFS_TIMEOUT;
167 Packet.Cdb = Cdb;
168 Packet.CdbLength = sizeof (Cdb);
169 Packet.DataDirection = UfsNoData;
170 Packet.SenseData = SenseData;
171 Packet.SenseDataLength = *SenseDataLength;
172
173 Status = UfsExecScsiCmds (Private,(UINT8)Lun, &Packet);
174
175 if (*SenseDataLength != 0) {
176 *SenseDataLength = Packet.SenseDataLength;
177 }
178
179 return Status;
180 }
181
182
183
184 /**
185 Execute READ CAPACITY(10) SCSI command on a specific UFS device.
186
187 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
188 @param[in] Lun The lun on which the SCSI cmd executed.
189 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
190 @param[out] DataLength The length of output READ_CAPACITY data.
191 @param[out] SenseData A pointer to output sense data.
192 @param[out] SenseDataLength The length of output sense data.
193
194 @retval EFI_SUCCESS The command executed successfully.
195 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
196 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
197
198 **/
199 EFI_STATUS
200 UfsPeimReadCapacity (
201 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
202 IN UINTN Lun,
203 OUT VOID *DataBuffer,
204 OUT UINT32 *DataLength,
205 OUT VOID *SenseData, OPTIONAL
206 OUT UINT8 *SenseDataLength
207 )
208 {
209 UFS_SCSI_REQUEST_PACKET Packet;
210 UINT8 Cdb[UFS_SCSI_OP_LENGTH_TEN];
211 EFI_STATUS Status;
212
213 ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
214 ZeroMem (Cdb, sizeof (Cdb));
215
216 Cdb[0] = EFI_SCSI_OP_READ_CAPACITY;
217
218 Packet.Timeout = UFS_TIMEOUT;
219 Packet.Cdb = Cdb;
220 Packet.CdbLength = sizeof (Cdb);
221 Packet.InDataBuffer = DataBuffer;
222 Packet.InTransferLength = *DataLength;
223 Packet.DataDirection = UfsDataIn;
224 Packet.SenseData = SenseData;
225 Packet.SenseDataLength = *SenseDataLength;
226
227 Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
228
229 if (*SenseDataLength != 0) {
230 *SenseDataLength = Packet.SenseDataLength;
231 }
232
233 if (!EFI_ERROR (Status)) {
234 *DataLength = Packet.InTransferLength;
235 }
236
237 return Status;
238 }
239
240 /**
241 Execute READ CAPACITY(16) SCSI command on a specific UFS device.
242
243 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
244 @param[in] Lun The lun on which the SCSI cmd executed.
245 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
246 @param[out] DataLength The length of output READ_CAPACITY data.
247 @param[out] SenseData A pointer to output sense data.
248 @param[out] SenseDataLength The length of output sense data.
249
250 @retval EFI_SUCCESS The command executed successfully.
251 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
252 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
253
254 **/
255 EFI_STATUS
256 UfsPeimReadCapacity16 (
257 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
258 IN UINTN Lun,
259 OUT VOID *DataBuffer,
260 OUT UINT32 *DataLength,
261 OUT VOID *SenseData, OPTIONAL
262 OUT UINT8 *SenseDataLength
263 )
264 {
265 UFS_SCSI_REQUEST_PACKET Packet;
266 UINT8 Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN];
267 EFI_STATUS Status;
268
269 ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
270 ZeroMem (Cdb, sizeof (Cdb));
271
272 Cdb[0] = EFI_SCSI_OP_READ_CAPACITY16;
273 Cdb[1] = 0x10; // Service Action should be 0x10 for UFS device.
274 Cdb[13] = 0x20; // The maximum number of bytes for returned data.
275
276 Packet.Timeout = UFS_TIMEOUT;
277 Packet.Cdb = Cdb;
278 Packet.CdbLength = sizeof (Cdb);
279 Packet.InDataBuffer = DataBuffer;
280 Packet.InTransferLength = *DataLength;
281 Packet.DataDirection = UfsDataIn;
282 Packet.SenseData = SenseData;
283 Packet.SenseDataLength = *SenseDataLength;
284
285 Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
286
287 if (*SenseDataLength != 0) {
288 *SenseDataLength = Packet.SenseDataLength;
289 }
290
291 if (!EFI_ERROR (Status)) {
292 *DataLength = Packet.InTransferLength;
293 }
294
295 return Status;
296 }
297
298 /**
299 Execute READ (10) SCSI command on a specific UFS device.
300
301 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
302 @param[in] Lun The lun on which the SCSI cmd executed.
303 @param[in] StartLba The start LBA.
304 @param[in] SectorNum The sector number to be read.
305 @param[out] DataBuffer A pointer to data buffer.
306 @param[out] DataLength The length of output data.
307 @param[out] SenseData A pointer to output sense data.
308 @param[out] SenseDataLength The length of output sense data.
309
310 @retval EFI_SUCCESS The command executed successfully.
311 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
312 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
313
314 **/
315 EFI_STATUS
316 UfsPeimRead10 (
317 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
318 IN UINTN Lun,
319 IN UINTN StartLba,
320 IN UINT32 SectorNum,
321 OUT VOID *DataBuffer,
322 OUT UINT32 *DataLength,
323 OUT VOID *SenseData, OPTIONAL
324 OUT UINT8 *SenseDataLength
325 )
326 {
327 UFS_SCSI_REQUEST_PACKET Packet;
328 UINT8 Cdb[UFS_SCSI_OP_LENGTH_TEN];
329 EFI_STATUS Status;
330
331 ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
332 ZeroMem (Cdb, sizeof (Cdb));
333
334 Cdb[0] = EFI_SCSI_OP_READ10;
335 WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 ((UINT32) StartLba));
336 WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorNum));
337
338 Packet.Timeout = UFS_TIMEOUT;
339 Packet.Cdb = Cdb;
340 Packet.CdbLength = sizeof (Cdb);
341 Packet.InDataBuffer = DataBuffer;
342 Packet.InTransferLength = *DataLength;
343 Packet.DataDirection = UfsDataIn;
344 Packet.SenseData = SenseData;
345 Packet.SenseDataLength = *SenseDataLength;
346
347 Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
348
349 if (*SenseDataLength != 0) {
350 *SenseDataLength = Packet.SenseDataLength;
351 }
352
353 if (!EFI_ERROR (Status)) {
354 *DataLength = Packet.InTransferLength;
355 }
356
357 return Status;
358 }
359
360 /**
361 Execute READ (16) SCSI command on a specific UFS device.
362
363 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
364 @param[in] Lun The lun on which the SCSI cmd executed.
365 @param[in] StartLba The start LBA.
366 @param[in] SectorNum The sector number to be read.
367 @param[out] DataBuffer A pointer to data buffer.
368 @param[out] DataLength The length of output data.
369 @param[out] SenseData A pointer to output sense data.
370 @param[out] SenseDataLength The length of output sense data.
371
372 @retval EFI_SUCCESS The command executed successfully.
373 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
374 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
375
376 **/
377 EFI_STATUS
378 UfsPeimRead16 (
379 IN UFS_PEIM_HC_PRIVATE_DATA *Private,
380 IN UINTN Lun,
381 IN UINTN StartLba,
382 IN UINT32 SectorNum,
383 OUT VOID *DataBuffer,
384 OUT UINT32 *DataLength,
385 OUT VOID *SenseData, OPTIONAL
386 OUT UINT8 *SenseDataLength
387 )
388 {
389 UFS_SCSI_REQUEST_PACKET Packet;
390 UINT8 Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN];
391 EFI_STATUS Status;
392
393 ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
394 ZeroMem (Cdb, sizeof (Cdb));
395
396 Cdb[0] = EFI_SCSI_OP_READ16;
397 WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));
398 WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorNum));
399
400 Packet.Timeout = UFS_TIMEOUT;
401 Packet.Cdb = Cdb;
402 Packet.CdbLength = sizeof (Cdb);
403 Packet.InDataBuffer = DataBuffer;
404 Packet.InTransferLength = *DataLength;
405 Packet.DataDirection = UfsDataIn;
406 Packet.SenseData = SenseData;
407 Packet.SenseDataLength = *SenseDataLength;
408
409 Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
410
411 if (*SenseDataLength != 0) {
412 *SenseDataLength = Packet.SenseDataLength;
413 }
414
415 if (!EFI_ERROR (Status)) {
416 *DataLength = Packet.InTransferLength;
417 }
418
419 return Status;
420 }
421
422 /**
423 Parsing Sense Keys from sense data.
424
425 @param Media The pointer of EFI_PEI_BLOCK_IO_MEDIA
426 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
427 @param NeedRetry The pointer of action which indicates what is need to retry
428
429 @retval EFI_DEVICE_ERROR Indicates that error occurs
430 @retval EFI_SUCCESS Successfully to complete the parsing
431
432 **/
433 EFI_STATUS
434 UfsPeimParsingSenseKeys (
435 IN EFI_PEI_BLOCK_IO2_MEDIA *Media,
436 IN EFI_SCSI_SENSE_DATA *SenseData,
437 OUT BOOLEAN *NeedRetry
438 )
439 {
440 if ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
441 (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
442 Media->MediaPresent = FALSE;
443 *NeedRetry = FALSE;
444 DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is No Media\n"));
445 return EFI_DEVICE_ERROR;
446 }
447
448 if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
449 (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
450 *NeedRetry = TRUE;
451 DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is Media Change\n"));
452 return EFI_SUCCESS;
453 }
454
455 if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
456 (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
457 *NeedRetry = TRUE;
458 DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n"));
459 return EFI_SUCCESS;
460 }
461
462 if ((SenseData->Sense_Key == EFI_SCSI_SK_MEDIUM_ERROR) ||
463 ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
464 (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN))) {
465 *NeedRetry = FALSE;
466 DEBUG ((EFI_D_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 ((EFI_D_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 *NeedRetry = TRUE;
480 DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n"));
481 return EFI_SUCCESS;
482 }
483
484 *NeedRetry = FALSE;
485 DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
486 return EFI_DEVICE_ERROR;
487 }
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
625 } while (NeedRetry);
626
627 DataLength = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
628 SenseDataLength = 0;
629 Status = UfsPeimReadCapacity (Private, Lun, &Capacity, (UINT32 *)&DataLength, NULL, &SenseDataLength);
630 if (EFI_ERROR (Status)) {
631 return EFI_DEVICE_ERROR;
632 }
633
634 if ((Capacity.LastLba3 == 0xff) && (Capacity.LastLba2 == 0xff) &&
635 (Capacity.LastLba1 == 0xff) && (Capacity.LastLba0 == 0xff)) {
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 Private->Media[Lun].LastBlock = ((UINT32)Capacity16.LastLba3 << 24) | (Capacity16.LastLba2 << 16) | (Capacity16.LastLba1 << 8) | Capacity16.LastLba0;
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);
644 Private->Media[Lun].BlockSize = (Capacity16.BlockSize3 << 24) | (Capacity16.BlockSize2 << 16) | (Capacity16.BlockSize1 << 8) | Capacity16.BlockSize0;
645 } else {
646 Private->Media[Lun].LastBlock = ((UINT32)Capacity.LastLba3 << 24) | (Capacity.LastLba2 << 16) | (Capacity.LastLba1 << 8) | Capacity.LastLba0;
647 Private->Media[Lun].BlockSize = (Capacity.BlockSize3 << 24) | (Capacity.BlockSize2 << 16) | (Capacity.BlockSize1 << 8) | Capacity.BlockSize0;
648 }
649
650 MediaInfo->DeviceType = UfsDevice;
651 MediaInfo->MediaPresent = Private->Media[Lun].MediaPresent;
652 MediaInfo->LastBlock = (UINTN)Private->Media[Lun].LastBlock;
653 MediaInfo->BlockSize = Private->Media[Lun].BlockSize;
654
655 return EFI_SUCCESS;
656 }
657
658 /**
659 Reads the requested number of blocks from the specified block device.
660
661 The function reads the requested number of blocks from the device. All the
662 blocks are read, or an error is returned. If there is no media in the device,
663 the function returns EFI_NO_MEDIA.
664
665 @param[in] PeiServices General-purpose services that are available to
666 every PEIM.
667 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
668 @param[in] DeviceIndex Specifies the block device to which the function wants
669 to talk. Because the driver that implements Block I/O
670 PPIs will manage multiple block devices, PPIs that
671 want to talk to a single device must specify the device
672 index that was assigned during the enumeration process.
673 This index is a number from one to NumberBlockDevices.
674 @param[in] StartLBA The starting logical block address (LBA) to read from
675 on the device
676 @param[in] BufferSize The size of the Buffer in bytes. This number must be
677 a multiple of the intrinsic block size of the device.
678 @param[out] Buffer A pointer to the destination buffer for the data.
679 The caller is responsible for the ownership of the
680 buffer.
681
682 @retval EFI_SUCCESS The data was read correctly from the device.
683 @retval EFI_DEVICE_ERROR The device reported an error while attempting
684 to perform the read operation.
685 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
686 valid, or the buffer is not properly aligned.
687 @retval EFI_NO_MEDIA There is no media in the device.
688 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
689 the intrinsic block size of the device.
690
691 **/
692 EFI_STATUS
693 EFIAPI
694 UfsBlockIoPeimReadBlocks (
695 IN EFI_PEI_SERVICES **PeiServices,
696 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
697 IN UINTN DeviceIndex,
698 IN EFI_PEI_LBA StartLBA,
699 IN UINTN BufferSize,
700 OUT VOID *Buffer
701 )
702 {
703 EFI_STATUS Status;
704 UINTN BlockSize;
705 UINTN NumberOfBlocks;
706 UFS_PEIM_HC_PRIVATE_DATA *Private;
707 EFI_SCSI_SENSE_DATA SenseData;
708 UINT8 SenseDataLength;
709 BOOLEAN NeedRetry;
710 UINTN Lun;
711
712 Status = EFI_SUCCESS;
713 NeedRetry = TRUE;
714 Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
715
716 ZeroMem (&SenseData, sizeof (SenseData));
717 SenseDataLength = sizeof (SenseData);
718
719 //
720 // Check parameters
721 //
722 if (Buffer == NULL) {
723 return EFI_INVALID_PARAMETER;
724 }
725
726 if (BufferSize == 0) {
727 return EFI_SUCCESS;
728 }
729
730 if ((DeviceIndex == 0) || (DeviceIndex > UFS_PEIM_MAX_LUNS)) {
731 return EFI_INVALID_PARAMETER;
732 }
733
734 Lun = DeviceIndex - 1;
735 if ((Private->Luns.BitMask & (BIT0 << Lun)) == 0) {
736 return EFI_ACCESS_DENIED;
737 }
738
739 BlockSize = Private->Media[Lun].BlockSize;
740
741 if (BufferSize % BlockSize != 0) {
742 Status = EFI_BAD_BUFFER_SIZE;
743 }
744
745 if (StartLBA > Private->Media[Lun].LastBlock) {
746 Status = EFI_INVALID_PARAMETER;
747 }
748
749 NumberOfBlocks = BufferSize / BlockSize;
750
751 do {
752 Status = UfsPeimTestUnitReady (
753 Private,
754 Lun,
755 &SenseData,
756 &SenseDataLength
757 );
758 if (!EFI_ERROR (Status)) {
759 break;
760 }
761
762 if (SenseDataLength == 0) {
763 continue;
764 }
765
766 Status = UfsPeimParsingSenseKeys (&(Private->Media[Lun]), &SenseData, &NeedRetry);
767 if (EFI_ERROR (Status)) {
768 return EFI_DEVICE_ERROR;
769 }
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 return Status;
798 }
799
800 /**
801 Gets the count of block I/O devices that one specific block driver detects.
802
803 This function is used for getting the count of block I/O devices that one
804 specific block driver detects. To the PEI ATAPI driver, it returns the number
805 of all the detected ATAPI devices it detects during the enumeration process.
806 To the PEI legacy floppy driver, it returns the number of all the legacy
807 devices it finds during its enumeration process. If no device is detected,
808 then the function will return zero.
809
810 @param[in] PeiServices General-purpose services that are available
811 to every PEIM.
812 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
813 instance.
814 @param[out] NumberBlockDevices The number of block I/O devices discovered.
815
816 @retval EFI_SUCCESS The operation performed successfully.
817
818 **/
819 EFI_STATUS
820 EFIAPI
821 UfsBlockIoPeimGetDeviceNo2 (
822 IN EFI_PEI_SERVICES **PeiServices,
823 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
824 OUT UINTN *NumberBlockDevices
825 )
826 {
827 //
828 // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
829 // At PEI phase, we will only expose normal Luns to user.
830 // For those disabled Lun, when user try to access it, the operation would fail.
831 //
832 *NumberBlockDevices = UFS_PEIM_MAX_LUNS;
833 return EFI_SUCCESS;
834 }
835
836 /**
837 Gets a block device's media information.
838
839 This function will provide the caller with the specified block device's media
840 information. If the media changes, calling this function will update the media
841 information accordingly.
842
843 @param[in] PeiServices General-purpose services that are available to every
844 PEIM
845 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
846 @param[in] DeviceIndex Specifies the block device to which the function wants
847 to talk. Because the driver that implements Block I/O
848 PPIs will manage multiple block devices, the PPIs that
849 want to talk to a single device must specify the
850 device index that was assigned during the enumeration
851 process. This index is a number from one to
852 NumberBlockDevices.
853 @param[out] MediaInfo The media information of the specified block media.
854 The caller is responsible for the ownership of this
855 data structure.
856
857 @par Note:
858 The MediaInfo structure describes an enumeration of possible block device
859 types. This enumeration exists because no device paths are actually passed
860 across interfaces that describe the type or class of hardware that is publishing
861 the block I/O interface. This enumeration will allow for policy decisions
862 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
863 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
864 by a given device type, they should be reported in ascending order; this
865 order also applies to nested partitions, such as legacy MBR, where the
866 outermost partitions would have precedence in the reporting order. The
867 same logic applies to systems such as IDE that have precedence relationships
868 like "Master/Slave" or "Primary/Secondary". The master device should be
869 reported first, the slave second.
870
871 @retval EFI_SUCCESS Media information about the specified block device
872 was obtained successfully.
873 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
874 error.
875
876 **/
877 EFI_STATUS
878 EFIAPI
879 UfsBlockIoPeimGetMediaInfo2 (
880 IN EFI_PEI_SERVICES **PeiServices,
881 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
882 IN UINTN DeviceIndex,
883 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
884 )
885 {
886 EFI_STATUS Status;
887 UFS_PEIM_HC_PRIVATE_DATA *Private;
888 EFI_PEI_BLOCK_IO_MEDIA Media;
889 UINTN Lun;
890
891 Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
892
893 Status = UfsBlockIoPeimGetMediaInfo (
894 PeiServices,
895 &Private->BlkIoPpi,
896 DeviceIndex,
897 &Media
898 );
899 if (EFI_ERROR (Status)) {
900 return Status;
901 }
902
903 Lun = DeviceIndex - 1;
904 CopyMem (MediaInfo, &(Private->Media[Lun]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));
905 return EFI_SUCCESS;
906 }
907
908 /**
909 Reads the requested number of blocks from the specified block device.
910
911 The function reads the requested number of blocks from the device. All the
912 blocks are read, or an error is returned. If there is no media in the device,
913 the function returns EFI_NO_MEDIA.
914
915 @param[in] PeiServices General-purpose services that are available to
916 every PEIM.
917 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
918 @param[in] DeviceIndex Specifies the block device to which the function wants
919 to talk. Because the driver that implements Block I/O
920 PPIs will manage multiple block devices, PPIs that
921 want to talk to a single device must specify the device
922 index that was assigned during the enumeration process.
923 This index is a number from one to NumberBlockDevices.
924 @param[in] StartLBA The starting logical block address (LBA) to read from
925 on the device
926 @param[in] BufferSize The size of the Buffer in bytes. This number must be
927 a multiple of the intrinsic block size of the device.
928 @param[out] Buffer A pointer to the destination buffer for the data.
929 The caller is responsible for the ownership of the
930 buffer.
931
932 @retval EFI_SUCCESS The data was read correctly from the device.
933 @retval EFI_DEVICE_ERROR The device reported an error while attempting
934 to perform the read operation.
935 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
936 valid, or the buffer is not properly aligned.
937 @retval EFI_NO_MEDIA There is no media in the device.
938 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
939 the intrinsic block size of the device.
940
941 **/
942 EFI_STATUS
943 EFIAPI
944 UfsBlockIoPeimReadBlocks2 (
945 IN EFI_PEI_SERVICES **PeiServices,
946 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
947 IN UINTN DeviceIndex,
948 IN EFI_PEI_LBA StartLBA,
949 IN UINTN BufferSize,
950 OUT VOID *Buffer
951 )
952 {
953 EFI_STATUS Status;
954 UFS_PEIM_HC_PRIVATE_DATA *Private;
955
956 Status = EFI_SUCCESS;
957 Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
958
959 Status = UfsBlockIoPeimReadBlocks (
960 PeiServices,
961 &Private->BlkIoPpi,
962 DeviceIndex,
963 StartLBA,
964 BufferSize,
965 Buffer
966 );
967 return Status;
968 }
969
970 /**
971 One notified function to cleanup the allocated DMA buffers at the end of PEI.
972
973 @param[in] PeiServices Pointer to PEI Services Table.
974 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
975 event that caused this function to execute.
976 @param[in] Ppi Pointer to the PPI data associated with this function.
977
978 @retval EFI_SUCCESS The function completes successfully
979
980 **/
981 EFI_STATUS
982 EFIAPI
983 UfsEndOfPei (
984 IN EFI_PEI_SERVICES **PeiServices,
985 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
986 IN VOID *Ppi
987 )
988 {
989 UFS_PEIM_HC_PRIVATE_DATA *Private;
990
991 Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
992
993 if ((Private->Pool != NULL) && (Private->Pool->Head != NULL)) {
994 UfsPeimFreeMemPool (Private->Pool);
995 }
996
997 if (Private->UtpTmrlBase != NULL) {
998 IoMmuFreeBuffer (
999 EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)),
1000 Private->UtpTmrlBase,
1001 Private->TmrlMapping
1002 );
1003 }
1004
1005 if (Private->UtpTrlBase != NULL) {
1006 IoMmuFreeBuffer (
1007 EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TRD)),
1008 Private->UtpTrlBase,
1009 Private->TrlMapping
1010 );
1011 }
1012
1013 UfsControllerStop (Private);
1014
1015 return EFI_SUCCESS;
1016 }
1017
1018 /**
1019 The user code starts with this function.
1020
1021 @param FileHandle Handle of the file being invoked.
1022 @param PeiServices Describes the list of possible PEI Services.
1023
1024 @retval EFI_SUCCESS The driver is successfully initialized.
1025 @retval Others Can't initialize the driver.
1026
1027 **/
1028 EFI_STATUS
1029 EFIAPI
1030 InitializeUfsBlockIoPeim (
1031 IN EFI_PEI_FILE_HANDLE FileHandle,
1032 IN CONST EFI_PEI_SERVICES **PeiServices
1033 )
1034 {
1035 EFI_STATUS Status;
1036 UFS_PEIM_HC_PRIVATE_DATA *Private;
1037 EDKII_UFS_HOST_CONTROLLER_PPI *UfsHcPpi;
1038 UINT32 Index;
1039 UFS_CONFIG_DESC Config;
1040 UINTN MmioBase;
1041 UINT8 Controller;
1042
1043 //
1044 // Shadow this PEIM to run from memory
1045 //
1046 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
1047 return EFI_SUCCESS;
1048 }
1049
1050 //
1051 // locate ufs host controller PPI
1052 //
1053 Status = PeiServicesLocatePpi (
1054 &gEdkiiPeiUfsHostControllerPpiGuid,
1055 0,
1056 NULL,
1057 (VOID **) &UfsHcPpi
1058 );
1059 if (EFI_ERROR (Status)) {
1060 return EFI_DEVICE_ERROR;
1061 }
1062
1063 IoMmuInit ();
1064
1065 Controller = 0;
1066 MmioBase = 0;
1067 while (TRUE) {
1068 Status = UfsHcPpi->GetUfsHcMmioBar (UfsHcPpi, Controller, &MmioBase);
1069 //
1070 // When status is error, meant no controller is found
1071 //
1072 if (EFI_ERROR (Status)) {
1073 break;
1074 }
1075
1076 Private = AllocateCopyPool (sizeof (UFS_PEIM_HC_PRIVATE_DATA), &gUfsHcPeimTemplate);
1077 if (Private == NULL) {
1078 Status = EFI_OUT_OF_RESOURCES;
1079 break;
1080 }
1081
1082 Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;
1083 Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;
1084 Private->UfsHcBase = MmioBase;
1085
1086 //
1087 // Initialize the memory pool which will be used in all transactions.
1088 //
1089 Status = UfsPeimInitMemPool (Private);
1090 if (EFI_ERROR (Status)) {
1091 Status = EFI_OUT_OF_RESOURCES;
1092 break;
1093 }
1094
1095 //
1096 // Initialize UFS Host Controller H/W.
1097 //
1098 Status = UfsControllerInit (Private);
1099 if (EFI_ERROR (Status)) {
1100 DEBUG ((EFI_D_ERROR, "UfsDevicePei: Host Controller Initialization Error, Status = %r\n", Status));
1101 Controller++;
1102 continue;
1103 }
1104
1105 //
1106 // UFS 2.0 spec Section 13.1.3.3:
1107 // At the end of the UFS Interconnect Layer initialization on both host and device side,
1108 // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready.
1109 //
1110 Status = UfsExecNopCmds (Private);
1111 if (EFI_ERROR (Status)) {
1112 DEBUG ((EFI_D_ERROR, "Ufs Sending NOP IN command Error, Status = %r\n", Status));
1113 Controller++;
1114 continue;
1115 }
1116
1117 //
1118 // The host enables the device initialization completion by setting fDeviceInit flag.
1119 //
1120 Status = UfsSetFlag (Private, UfsFlagDevInit);
1121 if (EFI_ERROR (Status)) {
1122 DEBUG ((EFI_D_ERROR, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status));
1123 Controller++;
1124 continue;
1125 }
1126
1127 //
1128 // Get Ufs Device's Lun Info by reading Configuration Descriptor.
1129 //
1130 Status = UfsRwDeviceDesc (Private, TRUE, UfsConfigDesc, 0, 0, &Config, sizeof (UFS_CONFIG_DESC));
1131 if (EFI_ERROR (Status)) {
1132 DEBUG ((EFI_D_ERROR, "Ufs Get Configuration Descriptor Error, Status = %r\n", Status));
1133 Controller++;
1134 continue;
1135 }
1136
1137 for (Index = 0; Index < UFS_PEIM_MAX_LUNS; Index++) {
1138 if (Config.UnitDescConfParams[Index].LunEn != 0) {
1139 Private->Luns.BitMask |= (BIT0 << Index);
1140 DEBUG ((EFI_D_INFO, "Ufs %d Lun %d is enabled\n", Controller, Index));
1141 }
1142 }
1143
1144 PeiServicesInstallPpi (&Private->BlkIoPpiList);
1145 PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
1146 Controller++;
1147 }
1148
1149 return EFI_SUCCESS;
1150 }