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