2 NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
3 NVM Express specification.
5 Copyright (c) 2013, 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
*Controller
;
40 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
41 NVM_EXPRESS_COMMAND Command
;
42 NVM_EXPRESS_RESPONSE Response
;
46 Controller
= Device
->Controller
;
47 BlockSize
= Device
->Media
.BlockSize
;
48 Bytes
= Blocks
* BlockSize
;
50 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
51 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
52 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
54 CommandPacket
.NvmeCmd
= &Command
;
55 CommandPacket
.NvmeResponse
= &Response
;
57 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_READ_OPC
;
58 CommandPacket
.NvmeCmd
->Cdw0
.Cid
= Controller
->Cid
[1]++;
59 CommandPacket
.NvmeCmd
->Nsid
= Device
->NamespaceId
;
60 CommandPacket
.TransferBuffer
= (VOID
*)(UINTN
)Buffer
;
62 CommandPacket
.TransferLength
= Bytes
;
63 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
64 CommandPacket
.QueueId
= NVME_IO_QUEUE
;
66 CommandPacket
.NvmeCmd
->Cdw10
= (UINT32
)Lba
;
67 CommandPacket
.NvmeCmd
->Cdw11
= (UINT32
)(Lba
>> 32);
68 CommandPacket
.NvmeCmd
->Cdw12
= (Blocks
- 1) & 0xFFFF;
70 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
| CDW12_VALID
;
72 Status
= Controller
->Passthru
.PassThru (
73 &Controller
->Passthru
,
84 Write some sectors to the device.
86 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
87 @param Buffer The buffer to be written into the device.
88 @param Lba The start block number.
89 @param Blocks Total block number to be written.
91 @retval EFI_SUCCESS Datum are written into the buffer.
92 @retval Others Fail to write all the datum.
97 IN NVME_DEVICE_PRIVATE_DATA
*Device
,
103 NVME_CONTROLLER_PRIVATE_DATA
*Controller
;
104 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
105 NVM_EXPRESS_COMMAND Command
;
106 NVM_EXPRESS_RESPONSE Response
;
111 Controller
= Device
->Controller
;
112 BlockSize
= Device
->Media
.BlockSize
;
113 Bytes
= Blocks
* BlockSize
;
115 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
116 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
117 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
119 CommandPacket
.NvmeCmd
= &Command
;
120 CommandPacket
.NvmeResponse
= &Response
;
122 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_WRITE_OPC
;
123 CommandPacket
.NvmeCmd
->Cdw0
.Cid
= Controller
->Cid
[1]++;
124 CommandPacket
.NvmeCmd
->Nsid
= Device
->NamespaceId
;
125 CommandPacket
.TransferBuffer
= (VOID
*)(UINTN
)Buffer
;
127 CommandPacket
.TransferLength
= Bytes
;
128 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
129 CommandPacket
.QueueId
= NVME_IO_QUEUE
;
131 CommandPacket
.NvmeCmd
->Cdw10
= (UINT32
)Lba
;
132 CommandPacket
.NvmeCmd
->Cdw11
= (UINT32
)(Lba
>> 32);
133 CommandPacket
.NvmeCmd
->Cdw12
= (Blocks
- 1) & 0xFFFF;
135 CommandPacket
.MetadataBuffer
= NULL
;
136 CommandPacket
.MetadataLength
= 0;
138 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
| CDW12_VALID
;
140 Status
= Controller
->Passthru
.PassThru (
141 &Controller
->Passthru
,
152 Read some blocks from the device.
154 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
155 @param Buffer The buffer used to store the data read from the device.
156 @param Lba The start block number.
157 @param Blocks Total block number to be read.
159 @retval EFI_SUCCESS Datum are read from the device.
160 @retval Others Fail to read all the datum.
165 IN NVME_DEVICE_PRIVATE_DATA
*Device
,
173 NVME_CONTROLLER_PRIVATE_DATA
*Controller
;
174 UINT32 MaxTransferBlocks
;
177 Status
= EFI_SUCCESS
;
178 Controller
= Device
->Controller
;
179 BlockSize
= Device
->Media
.BlockSize
;
180 OrginalBlocks
= Blocks
;
182 if (Controller
->ControllerData
->Mdts
!= 0) {
183 MaxTransferBlocks
= (1 << (Controller
->ControllerData
->Mdts
)) * (1 << (Controller
->Cap
.Mpsmin
+ 12)) / BlockSize
;
185 MaxTransferBlocks
= 1024;
189 if (Blocks
> MaxTransferBlocks
) {
190 Status
= ReadSectors (Device
, (UINT64
)(UINTN
)Buffer
, Lba
, MaxTransferBlocks
);
192 Blocks
-= MaxTransferBlocks
;
193 Buffer
= (VOID
*)(UINTN
)((UINT64
)(UINTN
)Buffer
+ MaxTransferBlocks
* BlockSize
);
194 Lba
+= MaxTransferBlocks
;
196 Status
= ReadSectors (Device
, (UINT64
)(UINTN
)Buffer
, Lba
, (UINT32
)Blocks
);
200 if (EFI_ERROR(Status
)) {
205 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
));
211 Write some blocks to the device.
213 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
214 @param Buffer The buffer to be written into the device.
215 @param Lba The start block number.
216 @param Blocks Total block number to be written.
218 @retval EFI_SUCCESS Datum are written into the buffer.
219 @retval Others Fail to write all the datum.
224 IN NVME_DEVICE_PRIVATE_DATA
*Device
,
232 NVME_CONTROLLER_PRIVATE_DATA
*Controller
;
233 UINT32 MaxTransferBlocks
;
236 Status
= EFI_SUCCESS
;
237 Controller
= Device
->Controller
;
238 BlockSize
= Device
->Media
.BlockSize
;
239 OrginalBlocks
= Blocks
;
241 if (Controller
->ControllerData
->Mdts
!= 0) {
242 MaxTransferBlocks
= (1 << (Controller
->ControllerData
->Mdts
)) * (1 << (Controller
->Cap
.Mpsmin
+ 12)) / BlockSize
;
244 MaxTransferBlocks
= 1024;
248 if (Blocks
> MaxTransferBlocks
) {
249 Status
= WriteSectors (Device
, (UINT64
)(UINTN
)Buffer
, Lba
, MaxTransferBlocks
);
251 Blocks
-= MaxTransferBlocks
;
252 Buffer
= (VOID
*)(UINTN
)((UINT64
)(UINTN
)Buffer
+ MaxTransferBlocks
* BlockSize
);
253 Lba
+= MaxTransferBlocks
;
255 Status
= WriteSectors (Device
, (UINT64
)(UINTN
)Buffer
, Lba
, (UINT32
)Blocks
);
259 if (EFI_ERROR(Status
)) {
264 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
));
270 Flushes all modified data to the device.
272 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
274 @retval EFI_SUCCESS Datum are written into the buffer.
275 @retval Others Fail to write all the datum.
280 IN NVME_DEVICE_PRIVATE_DATA
*Device
283 NVME_CONTROLLER_PRIVATE_DATA
*Controller
;
284 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
285 NVM_EXPRESS_COMMAND Command
;
286 NVM_EXPRESS_RESPONSE Response
;
289 Controller
= Device
->Controller
;
291 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
292 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
293 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
295 CommandPacket
.NvmeCmd
= &Command
;
296 CommandPacket
.NvmeResponse
= &Response
;
298 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_FLUSH_OPC
;
299 CommandPacket
.NvmeCmd
->Cdw0
.Cid
= Controller
->Cid
[1]++;
300 CommandPacket
.NvmeCmd
->Nsid
= Device
->NamespaceId
;
301 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
302 CommandPacket
.QueueId
= NVME_IO_QUEUE
;
304 Status
= Controller
->Passthru
.PassThru (
305 &Controller
->Passthru
,
317 Reset the Block Device.
319 @param This Indicates a pointer to the calling context.
320 @param ExtendedVerification Driver may perform diagnostics on reset.
322 @retval EFI_SUCCESS The device was reset.
323 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
330 IN EFI_BLOCK_IO_PROTOCOL
*This
,
331 IN BOOLEAN ExtendedVerification
335 NVME_CONTROLLER_PRIVATE_DATA
*Private
;
336 NVME_DEVICE_PRIVATE_DATA
*Device
;
340 return EFI_INVALID_PARAMETER
;
344 // For Nvm Express subsystem, reset block device means reset controller.
346 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
348 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This
);
350 Private
= Device
->Controller
;
352 Status
= NvmeControllerInit (Private
);
354 gBS
->RestoreTPL (OldTpl
);
360 Read BufferSize bytes from Lba into Buffer.
362 @param This Indicates a pointer to the calling context.
363 @param MediaId Id of the media, changes every time the media is replaced.
364 @param Lba The starting Logical Block Address to read from.
365 @param BufferSize Size of Buffer, must be a multiple of device block size.
366 @param Buffer A pointer to the destination buffer for the data. The caller is
367 responsible for either having implicit or explicit ownership of the buffer.
369 @retval EFI_SUCCESS The data was read correctly from the device.
370 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
371 @retval EFI_NO_MEDIA There is no media in the device.
372 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
373 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
374 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
375 or the buffer is not on proper alignment.
380 NvmeBlockIoReadBlocks (
381 IN EFI_BLOCK_IO_PROTOCOL
*This
,
388 NVME_DEVICE_PRIVATE_DATA
*Device
;
390 EFI_BLOCK_IO_MEDIA
*Media
;
392 UINTN NumberOfBlocks
;
400 return EFI_INVALID_PARAMETER
;
405 if (MediaId
!= Media
->MediaId
) {
406 return EFI_MEDIA_CHANGED
;
409 if (Buffer
== NULL
) {
410 return EFI_INVALID_PARAMETER
;
413 if (BufferSize
== 0) {
417 BlockSize
= Media
->BlockSize
;
418 if ((BufferSize
% BlockSize
) != 0) {
419 return EFI_BAD_BUFFER_SIZE
;
422 NumberOfBlocks
= BufferSize
/ BlockSize
;
423 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
424 return EFI_INVALID_PARAMETER
;
427 IoAlign
= Media
->IoAlign
;
428 if (IoAlign
> 0 && (((UINTN
) Buffer
& (IoAlign
- 1)) != 0)) {
429 return EFI_INVALID_PARAMETER
;
432 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
434 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This
);
436 Status
= NvmeRead (Device
, Buffer
, Lba
, NumberOfBlocks
);
438 gBS
->RestoreTPL (OldTpl
);
443 Write BufferSize bytes from Lba into Buffer.
445 @param This Indicates a pointer to the calling context.
446 @param MediaId The media ID that the write request is for.
447 @param Lba The starting logical block address to be written. The caller is
448 responsible for writing to only legitimate locations.
449 @param BufferSize Size of Buffer, must be a multiple of device block size.
450 @param Buffer A pointer to the source buffer for the data.
452 @retval EFI_SUCCESS The data was written correctly to the device.
453 @retval EFI_WRITE_PROTECTED The device can not be written to.
454 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
455 @retval EFI_NO_MEDIA There is no media in the device.
456 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
457 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
458 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
459 or the buffer is not on proper alignment.
464 NvmeBlockIoWriteBlocks (
465 IN EFI_BLOCK_IO_PROTOCOL
*This
,
472 NVME_DEVICE_PRIVATE_DATA
*Device
;
474 EFI_BLOCK_IO_MEDIA
*Media
;
476 UINTN NumberOfBlocks
;
484 return EFI_INVALID_PARAMETER
;
489 if (MediaId
!= Media
->MediaId
) {
490 return EFI_MEDIA_CHANGED
;
493 if (Buffer
== NULL
) {
494 return EFI_INVALID_PARAMETER
;
497 if (BufferSize
== 0) {
501 BlockSize
= Media
->BlockSize
;
502 if ((BufferSize
% BlockSize
) != 0) {
503 return EFI_BAD_BUFFER_SIZE
;
506 NumberOfBlocks
= BufferSize
/ BlockSize
;
507 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
508 return EFI_INVALID_PARAMETER
;
511 IoAlign
= Media
->IoAlign
;
512 if (IoAlign
> 0 && (((UINTN
) Buffer
& (IoAlign
- 1)) != 0)) {
513 return EFI_INVALID_PARAMETER
;
516 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
518 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This
);
520 Status
= NvmeWrite (Device
, Buffer
, Lba
, NumberOfBlocks
);
522 gBS
->RestoreTPL (OldTpl
);
528 Flush the Block Device.
530 @param This Indicates a pointer to the calling context.
532 @retval EFI_SUCCESS All outstanding data was written to the device.
533 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data.
534 @retval EFI_NO_MEDIA There is no media in the device.
539 NvmeBlockIoFlushBlocks (
540 IN EFI_BLOCK_IO_PROTOCOL
*This
543 NVME_DEVICE_PRIVATE_DATA
*Device
;
551 return EFI_INVALID_PARAMETER
;
554 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
556 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This
);
558 Status
= NvmeFlush (Device
);
560 gBS
->RestoreTPL (OldTpl
);