2 NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
3 NVM Express specification.
5 Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "NvmExpress.h"
19 Read some sectors from the device.
21 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
22 @param Buffer The buffer used to store the data read from the device.
23 @param Lba The start block number.
24 @param Blocks Total block number to be read.
26 @retval EFI_SUCCESS Datum are read from the device.
27 @retval Others Fail to read all the datum.
32 IN NVME_DEVICE_PRIVATE_DATA
*Device
,
38 NVME_CONTROLLER_PRIVATE_DATA
*Private
;
40 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
41 EFI_NVM_EXPRESS_COMMAND Command
;
42 EFI_NVM_EXPRESS_COMPLETION Completion
;
46 Private
= Device
->Controller
;
47 BlockSize
= Device
->Media
.BlockSize
;
48 Bytes
= Blocks
* BlockSize
;
50 ZeroMem (&CommandPacket
, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
51 ZeroMem (&Command
, sizeof(EFI_NVM_EXPRESS_COMMAND
));
52 ZeroMem (&Completion
, sizeof(EFI_NVM_EXPRESS_COMPLETION
));
54 CommandPacket
.NvmeCmd
= &Command
;
55 CommandPacket
.NvmeCompletion
= &Completion
;
57 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_READ_OPC
;
58 CommandPacket
.NvmeCmd
->Nsid
= Device
->NamespaceId
;
59 CommandPacket
.TransferBuffer
= (VOID
*)(UINTN
)Buffer
;
61 CommandPacket
.TransferLength
= Bytes
;
62 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
63 CommandPacket
.QueueType
= NVME_IO_QUEUE
;
65 CommandPacket
.NvmeCmd
->Cdw10
= (UINT32
)Lba
;
66 CommandPacket
.NvmeCmd
->Cdw11
= (UINT32
)(Lba
>> 32);
67 CommandPacket
.NvmeCmd
->Cdw12
= (Blocks
- 1) & 0xFFFF;
69 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
| CDW12_VALID
;
71 Status
= Private
->Passthru
.PassThru (
82 Write some sectors to the device.
84 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
85 @param Buffer The buffer to be written into the device.
86 @param Lba The start block number.
87 @param Blocks Total block number to be written.
89 @retval EFI_SUCCESS Datum are written into the buffer.
90 @retval Others Fail to write all the datum.
95 IN NVME_DEVICE_PRIVATE_DATA
*Device
,
101 NVME_CONTROLLER_PRIVATE_DATA
*Private
;
102 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
103 EFI_NVM_EXPRESS_COMMAND Command
;
104 EFI_NVM_EXPRESS_COMPLETION Completion
;
109 Private
= Device
->Controller
;
110 BlockSize
= Device
->Media
.BlockSize
;
111 Bytes
= Blocks
* BlockSize
;
113 ZeroMem (&CommandPacket
, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
114 ZeroMem (&Command
, sizeof(EFI_NVM_EXPRESS_COMMAND
));
115 ZeroMem (&Completion
, sizeof(EFI_NVM_EXPRESS_COMPLETION
));
117 CommandPacket
.NvmeCmd
= &Command
;
118 CommandPacket
.NvmeCompletion
= &Completion
;
120 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_WRITE_OPC
;
121 CommandPacket
.NvmeCmd
->Nsid
= Device
->NamespaceId
;
122 CommandPacket
.TransferBuffer
= (VOID
*)(UINTN
)Buffer
;
124 CommandPacket
.TransferLength
= Bytes
;
125 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
126 CommandPacket
.QueueType
= NVME_IO_QUEUE
;
128 CommandPacket
.NvmeCmd
->Cdw10
= (UINT32
)Lba
;
129 CommandPacket
.NvmeCmd
->Cdw11
= (UINT32
)(Lba
>> 32);
130 CommandPacket
.NvmeCmd
->Cdw12
= (Blocks
- 1) & 0xFFFF;
132 CommandPacket
.MetadataBuffer
= NULL
;
133 CommandPacket
.MetadataLength
= 0;
135 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
| CDW12_VALID
;
137 Status
= Private
->Passthru
.PassThru (
148 Read some blocks from the device.
150 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
151 @param Buffer The buffer used to store the data read from the device.
152 @param Lba The start block number.
153 @param Blocks Total block number to be read.
155 @retval EFI_SUCCESS Datum are read from the device.
156 @retval Others Fail to read all the datum.
161 IN NVME_DEVICE_PRIVATE_DATA
*Device
,
169 NVME_CONTROLLER_PRIVATE_DATA
*Private
;
170 UINT32 MaxTransferBlocks
;
173 Status
= EFI_SUCCESS
;
174 Private
= Device
->Controller
;
175 BlockSize
= Device
->Media
.BlockSize
;
176 OrginalBlocks
= Blocks
;
178 if (Private
->ControllerData
->Mdts
!= 0) {
179 MaxTransferBlocks
= (1 << (Private
->ControllerData
->Mdts
)) * (1 << (Private
->Cap
.Mpsmin
+ 12)) / BlockSize
;
181 MaxTransferBlocks
= 1024;
185 if (Blocks
> MaxTransferBlocks
) {
186 Status
= ReadSectors (Device
, (UINT64
)(UINTN
)Buffer
, Lba
, MaxTransferBlocks
);
188 Blocks
-= MaxTransferBlocks
;
189 Buffer
= (VOID
*)(UINTN
)((UINT64
)(UINTN
)Buffer
+ MaxTransferBlocks
* BlockSize
);
190 Lba
+= MaxTransferBlocks
;
192 Status
= ReadSectors (Device
, (UINT64
)(UINTN
)Buffer
, Lba
, (UINT32
)Blocks
);
196 if (EFI_ERROR(Status
)) {
201 DEBUG ((EFI_D_INFO
, "NvmeRead() Lba = 0x%08x, Original = 0x%08x, Remaining = 0x%08x, BlockSize = 0x%x Status = %r\n", Lba
, OrginalBlocks
, Blocks
, BlockSize
, Status
));
207 Write some blocks to the device.
209 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
210 @param Buffer The buffer to be written into the device.
211 @param Lba The start block number.
212 @param Blocks Total block number to be written.
214 @retval EFI_SUCCESS Datum are written into the buffer.
215 @retval Others Fail to write all the datum.
220 IN NVME_DEVICE_PRIVATE_DATA
*Device
,
228 NVME_CONTROLLER_PRIVATE_DATA
*Private
;
229 UINT32 MaxTransferBlocks
;
232 Status
= EFI_SUCCESS
;
233 Private
= Device
->Controller
;
234 BlockSize
= Device
->Media
.BlockSize
;
235 OrginalBlocks
= Blocks
;
237 if (Private
->ControllerData
->Mdts
!= 0) {
238 MaxTransferBlocks
= (1 << (Private
->ControllerData
->Mdts
)) * (1 << (Private
->Cap
.Mpsmin
+ 12)) / BlockSize
;
240 MaxTransferBlocks
= 1024;
244 if (Blocks
> MaxTransferBlocks
) {
245 Status
= WriteSectors (Device
, (UINT64
)(UINTN
)Buffer
, Lba
, MaxTransferBlocks
);
247 Blocks
-= MaxTransferBlocks
;
248 Buffer
= (VOID
*)(UINTN
)((UINT64
)(UINTN
)Buffer
+ MaxTransferBlocks
* BlockSize
);
249 Lba
+= MaxTransferBlocks
;
251 Status
= WriteSectors (Device
, (UINT64
)(UINTN
)Buffer
, Lba
, (UINT32
)Blocks
);
255 if (EFI_ERROR(Status
)) {
260 DEBUG ((EFI_D_INFO
, "NvmeWrite() Lba = 0x%08x, Original = 0x%08x, Remaining = 0x%08x, BlockSize = 0x%x Status = %r\n", Lba
, OrginalBlocks
, Blocks
, BlockSize
, Status
));
266 Flushes all modified data to the device.
268 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
270 @retval EFI_SUCCESS Datum are written into the buffer.
271 @retval Others Fail to write all the datum.
276 IN NVME_DEVICE_PRIVATE_DATA
*Device
279 NVME_CONTROLLER_PRIVATE_DATA
*Private
;
280 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
281 EFI_NVM_EXPRESS_COMMAND Command
;
282 EFI_NVM_EXPRESS_COMPLETION Completion
;
285 Private
= Device
->Controller
;
287 ZeroMem (&CommandPacket
, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
288 ZeroMem (&Command
, sizeof(EFI_NVM_EXPRESS_COMMAND
));
289 ZeroMem (&Completion
, sizeof(EFI_NVM_EXPRESS_COMPLETION
));
291 CommandPacket
.NvmeCmd
= &Command
;
292 CommandPacket
.NvmeCompletion
= &Completion
;
294 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_FLUSH_OPC
;
295 CommandPacket
.NvmeCmd
->Nsid
= Device
->NamespaceId
;
296 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
297 CommandPacket
.QueueType
= NVME_IO_QUEUE
;
299 Status
= Private
->Passthru
.PassThru (
311 Reset the Block Device.
313 @param This Indicates a pointer to the calling context.
314 @param ExtendedVerification Driver may perform diagnostics on reset.
316 @retval EFI_SUCCESS The device was reset.
317 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
324 IN EFI_BLOCK_IO_PROTOCOL
*This
,
325 IN BOOLEAN ExtendedVerification
329 NVME_CONTROLLER_PRIVATE_DATA
*Private
;
330 NVME_DEVICE_PRIVATE_DATA
*Device
;
334 return EFI_INVALID_PARAMETER
;
338 // For Nvm Express subsystem, reset block device means reset controller.
340 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
342 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This
);
344 Private
= Device
->Controller
;
346 Status
= NvmeControllerInit (Private
);
348 gBS
->RestoreTPL (OldTpl
);
354 Read BufferSize bytes from Lba into Buffer.
356 @param This Indicates a pointer to the calling context.
357 @param MediaId Id of the media, changes every time the media is replaced.
358 @param Lba The starting Logical Block Address to read from.
359 @param BufferSize Size of Buffer, must be a multiple of device block size.
360 @param Buffer A pointer to the destination buffer for the data. The caller is
361 responsible for either having implicit or explicit ownership of the buffer.
363 @retval EFI_SUCCESS The data was read correctly from the device.
364 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
365 @retval EFI_NO_MEDIA There is no media in the device.
366 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
367 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
368 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
369 or the buffer is not on proper alignment.
374 NvmeBlockIoReadBlocks (
375 IN EFI_BLOCK_IO_PROTOCOL
*This
,
382 NVME_DEVICE_PRIVATE_DATA
*Device
;
384 EFI_BLOCK_IO_MEDIA
*Media
;
386 UINTN NumberOfBlocks
;
394 return EFI_INVALID_PARAMETER
;
399 if (MediaId
!= Media
->MediaId
) {
400 return EFI_MEDIA_CHANGED
;
403 if (Buffer
== NULL
) {
404 return EFI_INVALID_PARAMETER
;
407 if (BufferSize
== 0) {
411 BlockSize
= Media
->BlockSize
;
412 if ((BufferSize
% BlockSize
) != 0) {
413 return EFI_BAD_BUFFER_SIZE
;
416 NumberOfBlocks
= BufferSize
/ BlockSize
;
417 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
418 return EFI_INVALID_PARAMETER
;
421 IoAlign
= Media
->IoAlign
;
422 if (IoAlign
> 0 && (((UINTN
) Buffer
& (IoAlign
- 1)) != 0)) {
423 return EFI_INVALID_PARAMETER
;
426 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
428 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This
);
430 Status
= NvmeRead (Device
, Buffer
, Lba
, NumberOfBlocks
);
432 gBS
->RestoreTPL (OldTpl
);
437 Write BufferSize bytes from Lba into Buffer.
439 @param This Indicates a pointer to the calling context.
440 @param MediaId The media ID that the write request is for.
441 @param Lba The starting logical block address to be written. The caller is
442 responsible for writing to only legitimate locations.
443 @param BufferSize Size of Buffer, must be a multiple of device block size.
444 @param Buffer A pointer to the source buffer for the data.
446 @retval EFI_SUCCESS The data was written correctly to the device.
447 @retval EFI_WRITE_PROTECTED The device can not be written to.
448 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
449 @retval EFI_NO_MEDIA There is no media in the device.
450 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
451 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
452 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
453 or the buffer is not on proper alignment.
458 NvmeBlockIoWriteBlocks (
459 IN EFI_BLOCK_IO_PROTOCOL
*This
,
466 NVME_DEVICE_PRIVATE_DATA
*Device
;
468 EFI_BLOCK_IO_MEDIA
*Media
;
470 UINTN NumberOfBlocks
;
478 return EFI_INVALID_PARAMETER
;
483 if (MediaId
!= Media
->MediaId
) {
484 return EFI_MEDIA_CHANGED
;
487 if (Buffer
== NULL
) {
488 return EFI_INVALID_PARAMETER
;
491 if (BufferSize
== 0) {
495 BlockSize
= Media
->BlockSize
;
496 if ((BufferSize
% BlockSize
) != 0) {
497 return EFI_BAD_BUFFER_SIZE
;
500 NumberOfBlocks
= BufferSize
/ BlockSize
;
501 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
502 return EFI_INVALID_PARAMETER
;
505 IoAlign
= Media
->IoAlign
;
506 if (IoAlign
> 0 && (((UINTN
) Buffer
& (IoAlign
- 1)) != 0)) {
507 return EFI_INVALID_PARAMETER
;
510 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
512 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This
);
514 Status
= NvmeWrite (Device
, Buffer
, Lba
, NumberOfBlocks
);
516 gBS
->RestoreTPL (OldTpl
);
522 Flush the Block Device.
524 @param This Indicates a pointer to the calling context.
526 @retval EFI_SUCCESS All outstanding data was written to the device.
527 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data.
528 @retval EFI_NO_MEDIA There is no media in the device.
533 NvmeBlockIoFlushBlocks (
534 IN EFI_BLOCK_IO_PROTOCOL
*This
537 NVME_DEVICE_PRIVATE_DATA
*Device
;
545 return EFI_INVALID_PARAMETER
;
548 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
550 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This
);
552 Status
= NvmeFlush (Device
);
554 gBS
->RestoreTPL (OldTpl
);