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