2 The NvmExpressPei driver is used to manage non-volatile memory subsystem
3 which follows NVM Express specification at PEI phase.
5 Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "NvmExpressPei.h"
14 Read some sectors from the device.
16 @param NamespaceInfo The pointer to the PEI_NVME_NAMESPACE_INFO data structure.
17 @param Buffer The buffer used to store the data read from the device.
18 @param Lba The start block number.
19 @param Blocks Total block number to be read.
21 @retval EFI_SUCCESS Data are read from the device.
22 @retval Others Fail to read all the data.
27 IN PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
,
35 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
37 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
38 EFI_NVM_EXPRESS_COMMAND Command
;
39 EFI_NVM_EXPRESS_COMPLETION Completion
;
40 EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI
*NvmePassThru
;
42 Private
= NamespaceInfo
->Controller
;
43 NvmePassThru
= &Private
->NvmePassThruPpi
;
44 BlockSize
= NamespaceInfo
->Media
.BlockSize
;
45 Bytes
= Blocks
* BlockSize
;
47 ZeroMem (&CommandPacket
, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
48 ZeroMem (&Command
, sizeof (EFI_NVM_EXPRESS_COMMAND
));
49 ZeroMem (&Completion
, sizeof (EFI_NVM_EXPRESS_COMPLETION
));
51 CommandPacket
.NvmeCmd
= &Command
;
52 CommandPacket
.NvmeCompletion
= &Completion
;
54 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_READ_OPC
;
55 CommandPacket
.NvmeCmd
->Nsid
= NamespaceInfo
->NamespaceId
;
56 CommandPacket
.TransferBuffer
= (VOID
*)Buffer
;
58 CommandPacket
.TransferLength
= Bytes
;
59 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
60 CommandPacket
.QueueType
= NVME_IO_QUEUE
;
62 CommandPacket
.NvmeCmd
->Cdw10
= (UINT32
)Lba
;
63 CommandPacket
.NvmeCmd
->Cdw11
= (UINT32
)RShiftU64 (Lba
, 32);
64 CommandPacket
.NvmeCmd
->Cdw12
= (Blocks
- 1) & 0xFFFF;
66 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
| CDW12_VALID
;
68 Status
= NvmePassThru
->PassThru (
70 NamespaceInfo
->NamespaceId
,
78 Read some blocks from the device.
80 @param[in] NamespaceInfo The pointer to the PEI_NVME_NAMESPACE_INFO data structure.
81 @param[out] Buffer The Buffer used to store the Data read from the device.
82 @param[in] Lba The start block number.
83 @param[in] Blocks Total block number to be read.
85 @retval EFI_SUCCESS Data are read from the device.
86 @retval Others Fail to read all the data.
91 IN PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
,
100 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
101 UINT32 MaxTransferBlocks
;
104 Status
= EFI_SUCCESS
;
106 Private
= NamespaceInfo
->Controller
;
107 BlockSize
= NamespaceInfo
->Media
.BlockSize
;
108 OrginalBlocks
= Blocks
;
110 if (Private
->ControllerData
->Mdts
!= 0) {
111 MaxTransferBlocks
= (1 << (Private
->ControllerData
->Mdts
)) * (1 << (Private
->Cap
.Mpsmin
+ 12)) / BlockSize
;
113 MaxTransferBlocks
= 1024;
117 Status
= ReadSectors (
121 Blocks
> MaxTransferBlocks
? MaxTransferBlocks
: (UINT32
)Blocks
123 if (EFI_ERROR (Status
)) {
125 MaxTransferBlocks
= MaxTransferBlocks
>> 1;
127 if ((Retries
> NVME_READ_MAX_RETRY
) || (MaxTransferBlocks
< 1)) {
128 DEBUG ((DEBUG_ERROR
, "%a: ReadSectors fail, Status - %r\n", __FUNCTION__
, Status
));
134 "%a: ReadSectors fail, retry with smaller transfer block number - 0x%x\n",
141 if (Blocks
> MaxTransferBlocks
) {
142 Blocks
-= MaxTransferBlocks
;
143 Buffer
+= (MaxTransferBlocks
* BlockSize
);
144 Lba
+= MaxTransferBlocks
;
152 "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
153 "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n",
156 (UINT64
)OrginalBlocks
,
165 Gets the count of block I/O devices that one specific block driver detects.
167 This function is used for getting the count of block I/O devices that one
168 specific block driver detects. If no device is detected, then the function
171 @param[in] PeiServices General-purpose services that are available
173 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
175 @param[out] NumberBlockDevices The number of block I/O devices discovered.
177 @retval EFI_SUCCESS The operation performed successfully.
182 NvmeBlockIoPeimGetDeviceNo (
183 IN EFI_PEI_SERVICES
**PeiServices
,
184 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
185 OUT UINTN
*NumberBlockDevices
188 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
190 if ((This
== NULL
) || (NumberBlockDevices
== NULL
)) {
191 return EFI_INVALID_PARAMETER
;
194 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This
);
195 *NumberBlockDevices
= Private
->ActiveNamespaceNum
;
201 Gets a block device's media information.
203 This function will provide the caller with the specified block device's media
204 information. If the media changes, calling this function will update the media
205 information accordingly.
207 @param[in] PeiServices General-purpose services that are available to every
209 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
210 @param[in] DeviceIndex Specifies the block device to which the function wants
211 to talk. Because the driver that implements Block I/O
212 PPIs will manage multiple block devices, the PPIs that
213 want to talk to a single device must specify the
214 device index that was assigned during the enumeration
215 process. This index is a number from one to
217 @param[out] MediaInfo The media information of the specified block media.
218 The caller is responsible for the ownership of this
222 The MediaInfo structure describes an enumeration of possible block device
223 types. This enumeration exists because no device paths are actually passed
224 across interfaces that describe the type or class of hardware that is publishing
225 the block I/O interface. This enumeration will allow for policy decisions
226 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
227 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
228 by a given device type, they should be reported in ascending order; this
229 order also applies to nested partitions, such as legacy MBR, where the
230 outermost partitions would have precedence in the reporting order. The
231 same logic applies to systems such as IDE that have precedence relationships
232 like "Master/Slave" or "Primary/Secondary". The master device should be
233 reported first, the slave second.
235 @retval EFI_SUCCESS Media information about the specified block device
236 was obtained successfully.
237 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
243 NvmeBlockIoPeimGetMediaInfo (
244 IN EFI_PEI_SERVICES
**PeiServices
,
245 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
246 IN UINTN DeviceIndex
,
247 OUT EFI_PEI_BLOCK_IO_MEDIA
*MediaInfo
250 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
252 if ((This
== NULL
) || (MediaInfo
== NULL
)) {
253 return EFI_INVALID_PARAMETER
;
256 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This
);
258 if ((DeviceIndex
== 0) || (DeviceIndex
> Private
->ActiveNamespaceNum
)) {
259 return EFI_INVALID_PARAMETER
;
262 MediaInfo
->DeviceType
= (EFI_PEI_BLOCK_DEVICE_TYPE
)EDKII_PEI_BLOCK_DEVICE_TYPE_NVME
;
263 MediaInfo
->MediaPresent
= TRUE
;
264 MediaInfo
->LastBlock
= (UINTN
)Private
->NamespaceInfo
[DeviceIndex
-1].Media
.LastBlock
;
265 MediaInfo
->BlockSize
= Private
->NamespaceInfo
[DeviceIndex
-1].Media
.BlockSize
;
271 Reads the requested number of blocks from the specified block device.
273 The function reads the requested number of blocks from the device. All the
274 blocks are read, or an error is returned. If there is no media in the device,
275 the function returns EFI_NO_MEDIA.
277 @param[in] PeiServices General-purpose services that are available to
279 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
280 @param[in] DeviceIndex Specifies the block device to which the function wants
281 to talk. Because the driver that implements Block I/O
282 PPIs will manage multiple block devices, PPIs that
283 want to talk to a single device must specify the device
284 index that was assigned during the enumeration process.
285 This index is a number from one to NumberBlockDevices.
286 @param[in] StartLBA The starting logical block address (LBA) to read from
288 @param[in] BufferSize The size of the Buffer in bytes. This number must be
289 a multiple of the intrinsic block size of the device.
290 @param[out] Buffer A pointer to the destination buffer for the data.
291 The caller is responsible for the ownership of the
294 @retval EFI_SUCCESS The data was read correctly from the device.
295 @retval EFI_DEVICE_ERROR The device reported an error while attempting
296 to perform the read operation.
297 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
298 valid, or the buffer is not properly aligned.
299 @retval EFI_NO_MEDIA There is no media in the device.
300 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
301 the intrinsic block size of the device.
306 NvmeBlockIoPeimReadBlocks (
307 IN EFI_PEI_SERVICES
**PeiServices
,
308 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
309 IN UINTN DeviceIndex
,
310 IN EFI_PEI_LBA StartLBA
,
315 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
316 PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
;
318 UINTN NumberOfBlocks
;
320 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This
);
325 if ((This
== NULL
) || (Buffer
== NULL
)) {
326 return EFI_INVALID_PARAMETER
;
329 if (BufferSize
== 0) {
333 if ((DeviceIndex
== 0) || (DeviceIndex
> Private
->ActiveNamespaceNum
)) {
334 return EFI_INVALID_PARAMETER
;
338 // Check BufferSize and StartLBA
340 NamespaceInfo
= &(Private
->NamespaceInfo
[DeviceIndex
- 1]);
341 BlockSize
= NamespaceInfo
->Media
.BlockSize
;
342 if (BufferSize
% BlockSize
!= 0) {
343 return EFI_BAD_BUFFER_SIZE
;
346 if (StartLBA
> NamespaceInfo
->Media
.LastBlock
) {
347 return EFI_INVALID_PARAMETER
;
350 NumberOfBlocks
= BufferSize
/ BlockSize
;
351 if (NumberOfBlocks
- 1 > NamespaceInfo
->Media
.LastBlock
- StartLBA
) {
352 return EFI_INVALID_PARAMETER
;
355 return NvmeRead (NamespaceInfo
, (UINTN
)Buffer
, StartLBA
, NumberOfBlocks
);
359 Gets the count of block I/O devices that one specific block driver detects.
361 This function is used for getting the count of block I/O devices that one
362 specific block driver detects. If no device is detected, then the function
365 @param[in] PeiServices General-purpose services that are available
367 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
369 @param[out] NumberBlockDevices The number of block I/O devices discovered.
371 @retval EFI_SUCCESS The operation performed successfully.
376 NvmeBlockIoPeimGetDeviceNo2 (
377 IN EFI_PEI_SERVICES
**PeiServices
,
378 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
379 OUT UINTN
*NumberBlockDevices
382 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
384 if ((This
== NULL
) || (NumberBlockDevices
== NULL
)) {
385 return EFI_INVALID_PARAMETER
;
388 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This
);
389 *NumberBlockDevices
= Private
->ActiveNamespaceNum
;
395 Gets a block device's media information.
397 This function will provide the caller with the specified block device's media
398 information. If the media changes, calling this function will update the media
399 information accordingly.
401 @param[in] PeiServices General-purpose services that are available to every
403 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
404 @param[in] DeviceIndex Specifies the block device to which the function wants
405 to talk. Because the driver that implements Block I/O
406 PPIs will manage multiple block devices, the PPIs that
407 want to talk to a single device must specify the
408 device index that was assigned during the enumeration
409 process. This index is a number from one to
411 @param[out] MediaInfo The media information of the specified block media.
412 The caller is responsible for the ownership of this
416 The MediaInfo structure describes an enumeration of possible block device
417 types. This enumeration exists because no device paths are actually passed
418 across interfaces that describe the type or class of hardware that is publishing
419 the block I/O interface. This enumeration will allow for policy decisions
420 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
421 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
422 by a given device type, they should be reported in ascending order; this
423 order also applies to nested partitions, such as legacy MBR, where the
424 outermost partitions would have precedence in the reporting order. The
425 same logic applies to systems such as IDE that have precedence relationships
426 like "Master/Slave" or "Primary/Secondary". The master device should be
427 reported first, the slave second.
429 @retval EFI_SUCCESS Media information about the specified block device
430 was obtained successfully.
431 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
437 NvmeBlockIoPeimGetMediaInfo2 (
438 IN EFI_PEI_SERVICES
**PeiServices
,
439 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
440 IN UINTN DeviceIndex
,
441 OUT EFI_PEI_BLOCK_IO2_MEDIA
*MediaInfo
445 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
446 EFI_PEI_BLOCK_IO_MEDIA Media
;
448 if ((This
== NULL
) || (MediaInfo
== NULL
)) {
449 return EFI_INVALID_PARAMETER
;
452 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This
);
454 Status
= NvmeBlockIoPeimGetMediaInfo (
460 if (EFI_ERROR (Status
)) {
466 &(Private
->NamespaceInfo
[DeviceIndex
- 1].Media
),
467 sizeof (EFI_PEI_BLOCK_IO2_MEDIA
)
474 Reads the requested number of blocks from the specified block device.
476 The function reads the requested number of blocks from the device. All the
477 blocks are read, or an error is returned. If there is no media in the device,
478 the function returns EFI_NO_MEDIA.
480 @param[in] PeiServices General-purpose services that are available to
482 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
483 @param[in] DeviceIndex Specifies the block device to which the function wants
484 to talk. Because the driver that implements Block I/O
485 PPIs will manage multiple block devices, PPIs that
486 want to talk to a single device must specify the device
487 index that was assigned during the enumeration process.
488 This index is a number from one to NumberBlockDevices.
489 @param[in] StartLBA The starting logical block address (LBA) to read from
491 @param[in] BufferSize The size of the Buffer in bytes. This number must be
492 a multiple of the intrinsic block size of the device.
493 @param[out] Buffer A pointer to the destination buffer for the data.
494 The caller is responsible for the ownership of the
497 @retval EFI_SUCCESS The data was read correctly from the device.
498 @retval EFI_DEVICE_ERROR The device reported an error while attempting
499 to perform the read operation.
500 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
501 valid, or the buffer is not properly aligned.
502 @retval EFI_NO_MEDIA There is no media in the device.
503 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
504 the intrinsic block size of the device.
509 NvmeBlockIoPeimReadBlocks2 (
510 IN EFI_PEI_SERVICES
**PeiServices
,
511 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
512 IN UINTN DeviceIndex
,
513 IN EFI_PEI_LBA StartLBA
,
518 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
521 return EFI_INVALID_PARAMETER
;
524 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This
);
525 return NvmeBlockIoPeimReadBlocks (