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
;
176 Status
= EFI_SUCCESS
;
177 Controller
= Device
->Controller
;
178 BlockSize
= Device
->Media
.BlockSize
;
180 if (Controller
->ControllerData
->Mdts
!= 0) {
181 MaxTransferBlocks
= (1 << (Controller
->ControllerData
->Mdts
)) * (1 << (Controller
->Cap
.Mpsmin
+ 12)) / BlockSize
;
183 MaxTransferBlocks
= 1024;
187 if (Blocks
> MaxTransferBlocks
) {
188 Status
= ReadSectors (Device
, (UINT64
)(UINTN
)Buffer
, Lba
, MaxTransferBlocks
);
190 Blocks
-= MaxTransferBlocks
;
191 Buffer
= (VOID
*)(UINTN
)((UINT64
)(UINTN
)Buffer
+ MaxTransferBlocks
* BlockSize
);
192 Lba
+= MaxTransferBlocks
;
194 Status
= ReadSectors (Device
, (UINT64
)(UINTN
)Buffer
, Lba
, (UINT32
)Blocks
);
198 if (EFI_ERROR(Status
)) {
203 DEBUG ((EFI_D_INFO
, "NvmeRead() Lba = %8d, Blocks = %8d, BlockSize = %d Status = %r\n", Lba
, Blocks
, BlockSize
, Status
));
209 Write some blocks to the device.
211 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
212 @param Buffer The buffer to be written into the device.
213 @param Lba The start block number.
214 @param Blocks Total block number to be written.
216 @retval EFI_SUCCESS Datum are written into the buffer.
217 @retval Others Fail to write all the datum.
222 IN NVME_DEVICE_PRIVATE_DATA
*Device
,
230 NVME_CONTROLLER_PRIVATE_DATA
*Controller
;
231 UINT32 MaxTransferBlocks
;
233 Status
= EFI_SUCCESS
;
234 Controller
= Device
->Controller
;
235 BlockSize
= Device
->Media
.BlockSize
;
237 if (Controller
->ControllerData
->Mdts
!= 0) {
238 MaxTransferBlocks
= (1 << (Controller
->ControllerData
->Mdts
)) * (1 << (Controller
->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 = %8d, Blocks = %8d, BlockSize = %d Status = %r\n", Lba
, 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
*Controller
;
280 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
281 NVM_EXPRESS_COMMAND Command
;
282 NVM_EXPRESS_RESPONSE Response
;
285 Controller
= Device
->Controller
;
287 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
288 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
289 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
291 CommandPacket
.NvmeCmd
= &Command
;
292 CommandPacket
.NvmeResponse
= &Response
;
294 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_FLUSH_OPC
;
295 CommandPacket
.NvmeCmd
->Cdw0
.Cid
= Controller
->Cid
[1]++;
296 CommandPacket
.NvmeCmd
->Nsid
= Device
->NamespaceId
;
297 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
298 CommandPacket
.QueueId
= NVME_IO_QUEUE
;
300 Status
= Controller
->Passthru
.PassThru (
301 &Controller
->Passthru
,
313 Reset the Block Device.
315 @param This Indicates a pointer to the calling context.
316 @param ExtendedVerification Driver may perform diagnostics on reset.
318 @retval EFI_SUCCESS The device was reset.
319 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
326 IN EFI_BLOCK_IO_PROTOCOL
*This
,
327 IN BOOLEAN ExtendedVerification
331 NVME_CONTROLLER_PRIVATE_DATA
*Private
;
332 NVME_DEVICE_PRIVATE_DATA
*Device
;
336 return EFI_INVALID_PARAMETER
;
340 // For Nvm Express subsystem, reset block device means reset controller.
342 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
344 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This
);
346 Private
= Device
->Controller
;
348 Status
= NvmeControllerInit (Private
);
350 gBS
->RestoreTPL (OldTpl
);
356 Read BufferSize bytes from Lba into Buffer.
358 @param This Indicates a pointer to the calling context.
359 @param MediaId Id of the media, changes every time the media is replaced.
360 @param Lba The starting Logical Block Address to read from.
361 @param BufferSize Size of Buffer, must be a multiple of device block size.
362 @param Buffer A pointer to the destination buffer for the data. The caller is
363 responsible for either having implicit or explicit ownership of the buffer.
365 @retval EFI_SUCCESS The data was read correctly from the device.
366 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
367 @retval EFI_NO_MEDIA There is no media in the device.
368 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
369 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
370 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
371 or the buffer is not on proper alignment.
376 NvmeBlockIoReadBlocks (
377 IN EFI_BLOCK_IO_PROTOCOL
*This
,
384 NVME_DEVICE_PRIVATE_DATA
*Device
;
386 EFI_BLOCK_IO_MEDIA
*Media
;
388 UINTN NumberOfBlocks
;
396 return EFI_INVALID_PARAMETER
;
401 if (MediaId
!= Media
->MediaId
) {
402 return EFI_MEDIA_CHANGED
;
405 if (Buffer
== NULL
) {
406 return EFI_INVALID_PARAMETER
;
409 if (BufferSize
== 0) {
413 BlockSize
= Media
->BlockSize
;
414 if ((BufferSize
% BlockSize
) != 0) {
415 return EFI_BAD_BUFFER_SIZE
;
418 NumberOfBlocks
= BufferSize
/ BlockSize
;
419 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
420 return EFI_INVALID_PARAMETER
;
423 IoAlign
= Media
->IoAlign
;
424 if (IoAlign
> 0 && (((UINTN
) Buffer
& (IoAlign
- 1)) != 0)) {
425 return EFI_INVALID_PARAMETER
;
428 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
430 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This
);
432 Status
= NvmeRead (Device
, Buffer
, Lba
, NumberOfBlocks
);
434 gBS
->RestoreTPL (OldTpl
);
439 Write BufferSize bytes from Lba into Buffer.
441 @param This Indicates a pointer to the calling context.
442 @param MediaId The media ID that the write request is for.
443 @param Lba The starting logical block address to be written. The caller is
444 responsible for writing to only legitimate locations.
445 @param BufferSize Size of Buffer, must be a multiple of device block size.
446 @param Buffer A pointer to the source buffer for the data.
448 @retval EFI_SUCCESS The data was written correctly to the device.
449 @retval EFI_WRITE_PROTECTED The device can not be written to.
450 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
451 @retval EFI_NO_MEDIA There is no media in the device.
452 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
453 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
454 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
455 or the buffer is not on proper alignment.
460 NvmeBlockIoWriteBlocks (
461 IN EFI_BLOCK_IO_PROTOCOL
*This
,
468 NVME_DEVICE_PRIVATE_DATA
*Device
;
470 EFI_BLOCK_IO_MEDIA
*Media
;
472 UINTN NumberOfBlocks
;
480 return EFI_INVALID_PARAMETER
;
485 if (MediaId
!= Media
->MediaId
) {
486 return EFI_MEDIA_CHANGED
;
489 if (Buffer
== NULL
) {
490 return EFI_INVALID_PARAMETER
;
493 if (BufferSize
== 0) {
497 BlockSize
= Media
->BlockSize
;
498 if ((BufferSize
% BlockSize
) != 0) {
499 return EFI_BAD_BUFFER_SIZE
;
502 NumberOfBlocks
= BufferSize
/ BlockSize
;
503 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
504 return EFI_INVALID_PARAMETER
;
507 IoAlign
= Media
->IoAlign
;
508 if (IoAlign
> 0 && (((UINTN
) Buffer
& (IoAlign
- 1)) != 0)) {
509 return EFI_INVALID_PARAMETER
;
512 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
514 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This
);
516 Status
= NvmeWrite (Device
, Buffer
, Lba
, NumberOfBlocks
);
518 gBS
->RestoreTPL (OldTpl
);
524 Flush the Block Device.
526 @param This Indicates a pointer to the calling context.
528 @retval EFI_SUCCESS All outstanding data was written to the device.
529 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data.
530 @retval EFI_NO_MEDIA There is no media in the device.
535 NvmeBlockIoFlushBlocks (
536 IN EFI_BLOCK_IO_PROTOCOL
*This
539 NVME_DEVICE_PRIVATE_DATA
*Device
;
547 return EFI_INVALID_PARAMETER
;
550 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
552 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This
);
554 Status
= NvmeFlush (Device
);
556 gBS
->RestoreTPL (OldTpl
);