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 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 EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
38 EDKII_PEI_NVM_EXPRESS_COMMAND Command
;
39 EDKII_PEI_NVM_EXPRESS_COMPLETION Completion
;
41 Private
= NamespaceInfo
->Controller
;
42 BlockSize
= NamespaceInfo
->Media
.BlockSize
;
43 Bytes
= Blocks
* BlockSize
;
45 ZeroMem (&CommandPacket
, sizeof(EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
46 ZeroMem (&Command
, sizeof(EDKII_PEI_NVM_EXPRESS_COMMAND
));
47 ZeroMem (&Completion
, sizeof(EDKII_PEI_NVM_EXPRESS_COMPLETION
));
49 CommandPacket
.NvmeCmd
= &Command
;
50 CommandPacket
.NvmeCompletion
= &Completion
;
52 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_READ_OPC
;
53 CommandPacket
.NvmeCmd
->Nsid
= NamespaceInfo
->NamespaceId
;
54 CommandPacket
.TransferBuffer
= (VOID
*)Buffer
;
56 CommandPacket
.TransferLength
= Bytes
;
57 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
58 CommandPacket
.QueueType
= NVME_IO_QUEUE
;
60 CommandPacket
.NvmeCmd
->Cdw10
= (UINT32
)Lba
;
61 CommandPacket
.NvmeCmd
->Cdw11
= (UINT32
)RShiftU64(Lba
, 32);
62 CommandPacket
.NvmeCmd
->Cdw12
= (Blocks
- 1) & 0xFFFF;
64 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
| CDW12_VALID
;
66 Status
= NvmePassThru (
68 NamespaceInfo
->NamespaceId
,
75 Read some blocks from the device.
77 @param[in] NamespaceInfo The pointer to the PEI_NVME_NAMESPACE_INFO data structure.
78 @param[out] Buffer The Buffer used to store the Data read from the device.
79 @param[in] Lba The start block number.
80 @param[in] Blocks Total block number to be read.
82 @retval EFI_SUCCESS Data are read from the device.
83 @retval Others Fail to read all the data.
88 IN PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
,
97 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
98 UINT32 MaxTransferBlocks
;
101 Status
= EFI_SUCCESS
;
103 Private
= NamespaceInfo
->Controller
;
104 BlockSize
= NamespaceInfo
->Media
.BlockSize
;
105 OrginalBlocks
= Blocks
;
107 if (Private
->ControllerData
->Mdts
!= 0) {
108 MaxTransferBlocks
= (1 << (Private
->ControllerData
->Mdts
)) * (1 << (Private
->Cap
.Mpsmin
+ 12)) / BlockSize
;
110 MaxTransferBlocks
= 1024;
114 Status
= ReadSectors (
118 Blocks
> MaxTransferBlocks
? MaxTransferBlocks
: (UINT32
)Blocks
120 if (EFI_ERROR(Status
)) {
122 MaxTransferBlocks
= MaxTransferBlocks
>> 1;
124 if (Retries
> NVME_READ_MAX_RETRY
|| MaxTransferBlocks
< 1) {
125 DEBUG ((DEBUG_ERROR
, "%a: ReadSectors fail, Status - %r\n", __FUNCTION__
, Status
));
130 "%a: ReadSectors fail, retry with smaller transfer block number - 0x%x\n",
137 if (Blocks
> MaxTransferBlocks
) {
138 Blocks
-= MaxTransferBlocks
;
139 Buffer
+= (MaxTransferBlocks
* BlockSize
);
140 Lba
+= MaxTransferBlocks
;
146 DEBUG ((DEBUG_BLKIO
, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
147 "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__
, Lba
,
148 (UINT64
)OrginalBlocks
, (UINT64
)Blocks
, BlockSize
, Status
));
153 Gets the count of block I/O devices that one specific block driver detects.
155 This function is used for getting the count of block I/O devices that one
156 specific block driver detects. If no device is detected, then the function
159 @param[in] PeiServices General-purpose services that are available
161 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
163 @param[out] NumberBlockDevices The number of block I/O devices discovered.
165 @retval EFI_SUCCESS The operation performed successfully.
170 NvmeBlockIoPeimGetDeviceNo (
171 IN EFI_PEI_SERVICES
**PeiServices
,
172 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
173 OUT UINTN
*NumberBlockDevices
176 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
178 if (This
== NULL
|| NumberBlockDevices
== NULL
) {
179 return EFI_INVALID_PARAMETER
;
182 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This
);
183 *NumberBlockDevices
= Private
->ActiveNamespaceNum
;
189 Gets a block device's media information.
191 This function will provide the caller with the specified block device's media
192 information. If the media changes, calling this function will update the media
193 information accordingly.
195 @param[in] PeiServices General-purpose services that are available to every
197 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
198 @param[in] DeviceIndex Specifies the block device to which the function wants
199 to talk. Because the driver that implements Block I/O
200 PPIs will manage multiple block devices, the PPIs that
201 want to talk to a single device must specify the
202 device index that was assigned during the enumeration
203 process. This index is a number from one to
205 @param[out] MediaInfo The media information of the specified block media.
206 The caller is responsible for the ownership of this
210 The MediaInfo structure describes an enumeration of possible block device
211 types. This enumeration exists because no device paths are actually passed
212 across interfaces that describe the type or class of hardware that is publishing
213 the block I/O interface. This enumeration will allow for policy decisions
214 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
215 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
216 by a given device type, they should be reported in ascending order; this
217 order also applies to nested partitions, such as legacy MBR, where the
218 outermost partitions would have precedence in the reporting order. The
219 same logic applies to systems such as IDE that have precedence relationships
220 like "Master/Slave" or "Primary/Secondary". The master device should be
221 reported first, the slave second.
223 @retval EFI_SUCCESS Media information about the specified block device
224 was obtained successfully.
225 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
231 NvmeBlockIoPeimGetMediaInfo (
232 IN EFI_PEI_SERVICES
**PeiServices
,
233 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
234 IN UINTN DeviceIndex
,
235 OUT EFI_PEI_BLOCK_IO_MEDIA
*MediaInfo
238 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
240 if (This
== NULL
|| MediaInfo
== NULL
) {
241 return EFI_INVALID_PARAMETER
;
244 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This
);
246 if ((DeviceIndex
== 0) || (DeviceIndex
> Private
->ActiveNamespaceNum
)) {
247 return EFI_INVALID_PARAMETER
;
250 MediaInfo
->DeviceType
= (EFI_PEI_BLOCK_DEVICE_TYPE
) EDKII_PEI_BLOCK_DEVICE_TYPE_NVME
;
251 MediaInfo
->MediaPresent
= TRUE
;
252 MediaInfo
->LastBlock
= (UINTN
)Private
->NamespaceInfo
[DeviceIndex
-1].Media
.LastBlock
;
253 MediaInfo
->BlockSize
= Private
->NamespaceInfo
[DeviceIndex
-1].Media
.BlockSize
;
259 Reads the requested number of blocks from the specified block device.
261 The function reads the requested number of blocks from the device. All the
262 blocks are read, or an error is returned. If there is no media in the device,
263 the function returns EFI_NO_MEDIA.
265 @param[in] PeiServices General-purpose services that are available to
267 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
268 @param[in] DeviceIndex Specifies the block device to which the function wants
269 to talk. Because the driver that implements Block I/O
270 PPIs will manage multiple block devices, PPIs that
271 want to talk to a single device must specify the device
272 index that was assigned during the enumeration process.
273 This index is a number from one to NumberBlockDevices.
274 @param[in] StartLBA The starting logical block address (LBA) to read from
276 @param[in] BufferSize The size of the Buffer in bytes. This number must be
277 a multiple of the intrinsic block size of the device.
278 @param[out] Buffer A pointer to the destination buffer for the data.
279 The caller is responsible for the ownership of the
282 @retval EFI_SUCCESS The data was read correctly from the device.
283 @retval EFI_DEVICE_ERROR The device reported an error while attempting
284 to perform the read operation.
285 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
286 valid, or the buffer is not properly aligned.
287 @retval EFI_NO_MEDIA There is no media in the device.
288 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
289 the intrinsic block size of the device.
294 NvmeBlockIoPeimReadBlocks (
295 IN EFI_PEI_SERVICES
**PeiServices
,
296 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
297 IN UINTN DeviceIndex
,
298 IN EFI_PEI_LBA StartLBA
,
303 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
304 PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
;
306 UINTN NumberOfBlocks
;
308 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This
);
313 if (This
== NULL
|| Buffer
== NULL
) {
314 return EFI_INVALID_PARAMETER
;
317 if (BufferSize
== 0) {
321 if ((DeviceIndex
== 0) || (DeviceIndex
> Private
->ActiveNamespaceNum
)) {
322 return EFI_INVALID_PARAMETER
;
326 // Check BufferSize and StartLBA
328 NamespaceInfo
= &(Private
->NamespaceInfo
[DeviceIndex
- 1]);
329 BlockSize
= NamespaceInfo
->Media
.BlockSize
;
330 if (BufferSize
% BlockSize
!= 0) {
331 return EFI_BAD_BUFFER_SIZE
;
334 if (StartLBA
> NamespaceInfo
->Media
.LastBlock
) {
335 return EFI_INVALID_PARAMETER
;
337 NumberOfBlocks
= BufferSize
/ BlockSize
;
338 if (NumberOfBlocks
- 1 > NamespaceInfo
->Media
.LastBlock
- StartLBA
) {
339 return EFI_INVALID_PARAMETER
;
342 return NvmeRead (NamespaceInfo
, (UINTN
)Buffer
, StartLBA
, NumberOfBlocks
);
346 Gets the count of block I/O devices that one specific block driver detects.
348 This function is used for getting the count of block I/O devices that one
349 specific block driver detects. If no device is detected, then the function
352 @param[in] PeiServices General-purpose services that are available
354 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
356 @param[out] NumberBlockDevices The number of block I/O devices discovered.
358 @retval EFI_SUCCESS The operation performed successfully.
363 NvmeBlockIoPeimGetDeviceNo2 (
364 IN EFI_PEI_SERVICES
**PeiServices
,
365 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
366 OUT UINTN
*NumberBlockDevices
369 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
371 if (This
== NULL
|| NumberBlockDevices
== NULL
) {
372 return EFI_INVALID_PARAMETER
;
375 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This
);
376 *NumberBlockDevices
= Private
->ActiveNamespaceNum
;
382 Gets a block device's media information.
384 This function will provide the caller with the specified block device's media
385 information. If the media changes, calling this function will update the media
386 information accordingly.
388 @param[in] PeiServices General-purpose services that are available to every
390 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
391 @param[in] DeviceIndex Specifies the block device to which the function wants
392 to talk. Because the driver that implements Block I/O
393 PPIs will manage multiple block devices, the PPIs that
394 want to talk to a single device must specify the
395 device index that was assigned during the enumeration
396 process. This index is a number from one to
398 @param[out] MediaInfo The media information of the specified block media.
399 The caller is responsible for the ownership of this
403 The MediaInfo structure describes an enumeration of possible block device
404 types. This enumeration exists because no device paths are actually passed
405 across interfaces that describe the type or class of hardware that is publishing
406 the block I/O interface. This enumeration will allow for policy decisions
407 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
408 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
409 by a given device type, they should be reported in ascending order; this
410 order also applies to nested partitions, such as legacy MBR, where the
411 outermost partitions would have precedence in the reporting order. The
412 same logic applies to systems such as IDE that have precedence relationships
413 like "Master/Slave" or "Primary/Secondary". The master device should be
414 reported first, the slave second.
416 @retval EFI_SUCCESS Media information about the specified block device
417 was obtained successfully.
418 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
424 NvmeBlockIoPeimGetMediaInfo2 (
425 IN EFI_PEI_SERVICES
**PeiServices
,
426 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
427 IN UINTN DeviceIndex
,
428 OUT EFI_PEI_BLOCK_IO2_MEDIA
*MediaInfo
432 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
433 EFI_PEI_BLOCK_IO_MEDIA Media
;
435 if (This
== NULL
|| MediaInfo
== NULL
) {
436 return EFI_INVALID_PARAMETER
;
439 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This
);
441 Status
= NvmeBlockIoPeimGetMediaInfo (
447 if (EFI_ERROR (Status
)) {
453 &(Private
->NamespaceInfo
[DeviceIndex
- 1].Media
),
454 sizeof (EFI_PEI_BLOCK_IO2_MEDIA
)
461 Reads the requested number of blocks from the specified block device.
463 The function reads the requested number of blocks from the device. All the
464 blocks are read, or an error is returned. If there is no media in the device,
465 the function returns EFI_NO_MEDIA.
467 @param[in] PeiServices General-purpose services that are available to
469 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
470 @param[in] DeviceIndex Specifies the block device to which the function wants
471 to talk. Because the driver that implements Block I/O
472 PPIs will manage multiple block devices, PPIs that
473 want to talk to a single device must specify the device
474 index that was assigned during the enumeration process.
475 This index is a number from one to NumberBlockDevices.
476 @param[in] StartLBA The starting logical block address (LBA) to read from
478 @param[in] BufferSize The size of the Buffer in bytes. This number must be
479 a multiple of the intrinsic block size of the device.
480 @param[out] Buffer A pointer to the destination buffer for the data.
481 The caller is responsible for the ownership of the
484 @retval EFI_SUCCESS The data was read correctly from the device.
485 @retval EFI_DEVICE_ERROR The device reported an error while attempting
486 to perform the read operation.
487 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
488 valid, or the buffer is not properly aligned.
489 @retval EFI_NO_MEDIA There is no media in the device.
490 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
491 the intrinsic block size of the device.
496 NvmeBlockIoPeimReadBlocks2 (
497 IN EFI_PEI_SERVICES
**PeiServices
,
498 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
499 IN UINTN DeviceIndex
,
500 IN EFI_PEI_LBA StartLBA
,
505 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
508 return EFI_INVALID_PARAMETER
;
511 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This
);
512 return NvmeBlockIoPeimReadBlocks (