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, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution. The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include "NvmExpressPei.h"
21 Read some sectors from the device.
23 @param NamespaceInfo The pointer to the PEI_NVME_NAMESPACE_INFO data structure.
24 @param Buffer The buffer used to store the data read from the device.
25 @param Lba The start block number.
26 @param Blocks Total block number to be read.
28 @retval EFI_SUCCESS Data are read from the device.
29 @retval Others Fail to read all the data.
34 IN PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
,
42 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
44 EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
45 EDKII_PEI_NVM_EXPRESS_COMMAND Command
;
46 EDKII_PEI_NVM_EXPRESS_COMPLETION Completion
;
48 Private
= NamespaceInfo
->Controller
;
49 BlockSize
= NamespaceInfo
->Media
.BlockSize
;
50 Bytes
= Blocks
* BlockSize
;
52 ZeroMem (&CommandPacket
, sizeof(EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
53 ZeroMem (&Command
, sizeof(EDKII_PEI_NVM_EXPRESS_COMMAND
));
54 ZeroMem (&Completion
, sizeof(EDKII_PEI_NVM_EXPRESS_COMPLETION
));
56 CommandPacket
.NvmeCmd
= &Command
;
57 CommandPacket
.NvmeCompletion
= &Completion
;
59 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_READ_OPC
;
60 CommandPacket
.NvmeCmd
->Nsid
= NamespaceInfo
->NamespaceId
;
61 CommandPacket
.TransferBuffer
= (VOID
*)Buffer
;
63 CommandPacket
.TransferLength
= Bytes
;
64 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
65 CommandPacket
.QueueType
= NVME_IO_QUEUE
;
67 CommandPacket
.NvmeCmd
->Cdw10
= (UINT32
)Lba
;
68 CommandPacket
.NvmeCmd
->Cdw11
= (UINT32
)RShiftU64(Lba
, 32);
69 CommandPacket
.NvmeCmd
->Cdw12
= (Blocks
- 1) & 0xFFFF;
71 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
| CDW12_VALID
;
73 Status
= NvmePassThru (
75 NamespaceInfo
->NamespaceId
,
82 Read some blocks from the device.
84 @param[in] NamespaceInfo The pointer to the PEI_NVME_NAMESPACE_INFO data structure.
85 @param[out] Buffer The Buffer used to store the Data read from the device.
86 @param[in] Lba The start block number.
87 @param[in] Blocks Total block number to be read.
89 @retval EFI_SUCCESS Data are read from the device.
90 @retval Others Fail to read all the data.
95 IN PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
,
104 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
105 UINT32 MaxTransferBlocks
;
108 Status
= EFI_SUCCESS
;
110 Private
= NamespaceInfo
->Controller
;
111 BlockSize
= NamespaceInfo
->Media
.BlockSize
;
112 OrginalBlocks
= Blocks
;
114 if (Private
->ControllerData
->Mdts
!= 0) {
115 MaxTransferBlocks
= (1 << (Private
->ControllerData
->Mdts
)) * (1 << (Private
->Cap
.Mpsmin
+ 12)) / BlockSize
;
117 MaxTransferBlocks
= 1024;
121 Status
= ReadSectors (
125 Blocks
> MaxTransferBlocks
? MaxTransferBlocks
: (UINT32
)Blocks
127 if (EFI_ERROR(Status
)) {
129 MaxTransferBlocks
= MaxTransferBlocks
>> 1;
131 if (Retries
> NVME_READ_MAX_RETRY
|| MaxTransferBlocks
< 1) {
132 DEBUG ((DEBUG_ERROR
, "%a: ReadSectors fail, Status - %r\n", __FUNCTION__
, Status
));
137 "%a: ReadSectors fail, retry with smaller transfer block number - 0x%x\n",
144 if (Blocks
> MaxTransferBlocks
) {
145 Blocks
-= MaxTransferBlocks
;
146 Buffer
+= (MaxTransferBlocks
* BlockSize
);
147 Lba
+= MaxTransferBlocks
;
153 DEBUG ((DEBUG_BLKIO
, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
154 "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__
, Lba
,
155 (UINT64
)OrginalBlocks
, (UINT64
)Blocks
, BlockSize
, Status
));
160 Gets the count of block I/O devices that one specific block driver detects.
162 This function is used for getting the count of block I/O devices that one
163 specific block driver detects. If no device is detected, then the function
166 @param[in] PeiServices General-purpose services that are available
168 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
170 @param[out] NumberBlockDevices The number of block I/O devices discovered.
172 @retval EFI_SUCCESS The operation performed successfully.
177 NvmeBlockIoPeimGetDeviceNo (
178 IN EFI_PEI_SERVICES
**PeiServices
,
179 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
180 OUT UINTN
*NumberBlockDevices
183 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
185 if (This
== NULL
|| NumberBlockDevices
== NULL
) {
186 return EFI_INVALID_PARAMETER
;
189 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This
);
190 *NumberBlockDevices
= Private
->ActiveNamespaceNum
;
196 Gets a block device's media information.
198 This function will provide the caller with the specified block device's media
199 information. If the media changes, calling this function will update the media
200 information accordingly.
202 @param[in] PeiServices General-purpose services that are available to every
204 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
205 @param[in] DeviceIndex Specifies the block device to which the function wants
206 to talk. Because the driver that implements Block I/O
207 PPIs will manage multiple block devices, the PPIs that
208 want to talk to a single device must specify the
209 device index that was assigned during the enumeration
210 process. This index is a number from one to
212 @param[out] MediaInfo The media information of the specified block media.
213 The caller is responsible for the ownership of this
217 The MediaInfo structure describes an enumeration of possible block device
218 types. This enumeration exists because no device paths are actually passed
219 across interfaces that describe the type or class of hardware that is publishing
220 the block I/O interface. This enumeration will allow for policy decisions
221 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
222 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
223 by a given device type, they should be reported in ascending order; this
224 order also applies to nested partitions, such as legacy MBR, where the
225 outermost partitions would have precedence in the reporting order. The
226 same logic applies to systems such as IDE that have precedence relationships
227 like "Master/Slave" or "Primary/Secondary". The master device should be
228 reported first, the slave second.
230 @retval EFI_SUCCESS Media information about the specified block device
231 was obtained successfully.
232 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
238 NvmeBlockIoPeimGetMediaInfo (
239 IN EFI_PEI_SERVICES
**PeiServices
,
240 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
241 IN UINTN DeviceIndex
,
242 OUT EFI_PEI_BLOCK_IO_MEDIA
*MediaInfo
245 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
247 if (This
== NULL
|| MediaInfo
== NULL
) {
248 return EFI_INVALID_PARAMETER
;
251 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This
);
253 if ((DeviceIndex
== 0) || (DeviceIndex
> Private
->ActiveNamespaceNum
)) {
254 return EFI_INVALID_PARAMETER
;
257 MediaInfo
->DeviceType
= (EFI_PEI_BLOCK_DEVICE_TYPE
) EDKII_PEI_BLOCK_DEVICE_TYPE_NVME
;
258 MediaInfo
->MediaPresent
= TRUE
;
259 MediaInfo
->LastBlock
= (UINTN
)Private
->NamespaceInfo
[DeviceIndex
-1].Media
.LastBlock
;
260 MediaInfo
->BlockSize
= Private
->NamespaceInfo
[DeviceIndex
-1].Media
.BlockSize
;
266 Reads the requested number of blocks from the specified block device.
268 The function reads the requested number of blocks from the device. All the
269 blocks are read, or an error is returned. If there is no media in the device,
270 the function returns EFI_NO_MEDIA.
272 @param[in] PeiServices General-purpose services that are available to
274 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
275 @param[in] DeviceIndex Specifies the block device to which the function wants
276 to talk. Because the driver that implements Block I/O
277 PPIs will manage multiple block devices, PPIs that
278 want to talk to a single device must specify the device
279 index that was assigned during the enumeration process.
280 This index is a number from one to NumberBlockDevices.
281 @param[in] StartLBA The starting logical block address (LBA) to read from
283 @param[in] BufferSize The size of the Buffer in bytes. This number must be
284 a multiple of the intrinsic block size of the device.
285 @param[out] Buffer A pointer to the destination buffer for the data.
286 The caller is responsible for the ownership of the
289 @retval EFI_SUCCESS The data was read correctly from the device.
290 @retval EFI_DEVICE_ERROR The device reported an error while attempting
291 to perform the read operation.
292 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
293 valid, or the buffer is not properly aligned.
294 @retval EFI_NO_MEDIA There is no media in the device.
295 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
296 the intrinsic block size of the device.
301 NvmeBlockIoPeimReadBlocks (
302 IN EFI_PEI_SERVICES
**PeiServices
,
303 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
304 IN UINTN DeviceIndex
,
305 IN EFI_PEI_LBA StartLBA
,
310 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
311 PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
;
313 UINTN NumberOfBlocks
;
315 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This
);
320 if (This
== NULL
|| Buffer
== NULL
) {
321 return EFI_INVALID_PARAMETER
;
324 if (BufferSize
== 0) {
328 if ((DeviceIndex
== 0) || (DeviceIndex
> Private
->ActiveNamespaceNum
)) {
329 return EFI_INVALID_PARAMETER
;
333 // Check BufferSize and StartLBA
335 NamespaceInfo
= &(Private
->NamespaceInfo
[DeviceIndex
- 1]);
336 BlockSize
= NamespaceInfo
->Media
.BlockSize
;
337 if (BufferSize
% BlockSize
!= 0) {
338 return EFI_BAD_BUFFER_SIZE
;
341 if (StartLBA
> NamespaceInfo
->Media
.LastBlock
) {
342 return EFI_INVALID_PARAMETER
;
344 NumberOfBlocks
= BufferSize
/ BlockSize
;
345 if (NumberOfBlocks
- 1 > NamespaceInfo
->Media
.LastBlock
- StartLBA
) {
346 return EFI_INVALID_PARAMETER
;
349 return NvmeRead (NamespaceInfo
, (UINTN
)Buffer
, StartLBA
, NumberOfBlocks
);
353 Gets the count of block I/O devices that one specific block driver detects.
355 This function is used for getting the count of block I/O devices that one
356 specific block driver detects. If no device is detected, then the function
359 @param[in] PeiServices General-purpose services that are available
361 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
363 @param[out] NumberBlockDevices The number of block I/O devices discovered.
365 @retval EFI_SUCCESS The operation performed successfully.
370 NvmeBlockIoPeimGetDeviceNo2 (
371 IN EFI_PEI_SERVICES
**PeiServices
,
372 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
373 OUT UINTN
*NumberBlockDevices
376 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
378 if (This
== NULL
|| NumberBlockDevices
== NULL
) {
379 return EFI_INVALID_PARAMETER
;
382 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This
);
383 *NumberBlockDevices
= Private
->ActiveNamespaceNum
;
389 Gets a block device's media information.
391 This function will provide the caller with the specified block device's media
392 information. If the media changes, calling this function will update the media
393 information accordingly.
395 @param[in] PeiServices General-purpose services that are available to every
397 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
398 @param[in] DeviceIndex Specifies the block device to which the function wants
399 to talk. Because the driver that implements Block I/O
400 PPIs will manage multiple block devices, the PPIs that
401 want to talk to a single device must specify the
402 device index that was assigned during the enumeration
403 process. This index is a number from one to
405 @param[out] MediaInfo The media information of the specified block media.
406 The caller is responsible for the ownership of this
410 The MediaInfo structure describes an enumeration of possible block device
411 types. This enumeration exists because no device paths are actually passed
412 across interfaces that describe the type or class of hardware that is publishing
413 the block I/O interface. This enumeration will allow for policy decisions
414 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
415 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
416 by a given device type, they should be reported in ascending order; this
417 order also applies to nested partitions, such as legacy MBR, where the
418 outermost partitions would have precedence in the reporting order. The
419 same logic applies to systems such as IDE that have precedence relationships
420 like "Master/Slave" or "Primary/Secondary". The master device should be
421 reported first, the slave second.
423 @retval EFI_SUCCESS Media information about the specified block device
424 was obtained successfully.
425 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
431 NvmeBlockIoPeimGetMediaInfo2 (
432 IN EFI_PEI_SERVICES
**PeiServices
,
433 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
434 IN UINTN DeviceIndex
,
435 OUT EFI_PEI_BLOCK_IO2_MEDIA
*MediaInfo
439 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
440 EFI_PEI_BLOCK_IO_MEDIA Media
;
442 if (This
== NULL
|| MediaInfo
== NULL
) {
443 return EFI_INVALID_PARAMETER
;
446 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This
);
448 Status
= NvmeBlockIoPeimGetMediaInfo (
454 if (EFI_ERROR (Status
)) {
460 &(Private
->NamespaceInfo
[DeviceIndex
- 1].Media
),
461 sizeof (EFI_PEI_BLOCK_IO2_MEDIA
)
468 Reads the requested number of blocks from the specified block device.
470 The function reads the requested number of blocks from the device. All the
471 blocks are read, or an error is returned. If there is no media in the device,
472 the function returns EFI_NO_MEDIA.
474 @param[in] PeiServices General-purpose services that are available to
476 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
477 @param[in] DeviceIndex Specifies the block device to which the function wants
478 to talk. Because the driver that implements Block I/O
479 PPIs will manage multiple block devices, PPIs that
480 want to talk to a single device must specify the device
481 index that was assigned during the enumeration process.
482 This index is a number from one to NumberBlockDevices.
483 @param[in] StartLBA The starting logical block address (LBA) to read from
485 @param[in] BufferSize The size of the Buffer in bytes. This number must be
486 a multiple of the intrinsic block size of the device.
487 @param[out] Buffer A pointer to the destination buffer for the data.
488 The caller is responsible for the ownership of the
491 @retval EFI_SUCCESS The data was read correctly from the device.
492 @retval EFI_DEVICE_ERROR The device reported an error while attempting
493 to perform the read operation.
494 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
495 valid, or the buffer is not properly aligned.
496 @retval EFI_NO_MEDIA There is no media in the device.
497 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
498 the intrinsic block size of the device.
503 NvmeBlockIoPeimReadBlocks2 (
504 IN EFI_PEI_SERVICES
**PeiServices
,
505 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
506 IN UINTN DeviceIndex
,
507 IN EFI_PEI_LBA StartLBA
,
512 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
515 return EFI_INVALID_PARAMETER
;
518 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This
);
519 return NvmeBlockIoPeimReadBlocks (