]>
Commit | Line | Data |
---|---|---|
eb290d02 FT |
1 | /** @file\r |
2 | NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows\r | |
3 | NVM Express specification.\r | |
4 | \r | |
5 | Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r | |
6 | This program and the accompanying materials\r | |
7 | are licensed and made available under the terms and conditions of the BSD License\r | |
8 | which accompanies this distribution. The full text of the license may be found at\r | |
9 | http://opensource.org/licenses/bsd-license.php.\r | |
10 | \r | |
11 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r | |
12 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r | |
13 | \r | |
14 | **/\r | |
15 | \r | |
16 | #include "NvmExpress.h"\r | |
17 | \r | |
18 | /**\r | |
19 | Read some sectors from the device.\r | |
20 | \r | |
21 | @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.\r | |
22 | @param Buffer The buffer used to store the data read from the device.\r | |
23 | @param Lba The start block number.\r | |
24 | @param Blocks Total block number to be read.\r | |
25 | \r | |
26 | @retval EFI_SUCCESS Datum are read from the device.\r | |
27 | @retval Others Fail to read all the datum.\r | |
28 | \r | |
29 | **/\r | |
30 | EFI_STATUS\r | |
31 | ReadSectors (\r | |
32 | IN NVME_DEVICE_PRIVATE_DATA *Device,\r | |
33 | IN UINT64 Buffer,\r | |
34 | IN UINT64 Lba,\r | |
35 | IN UINT32 Blocks\r | |
36 | )\r | |
37 | {\r | |
38 | NVME_CONTROLLER_PRIVATE_DATA *Controller;\r | |
39 | UINT32 Bytes;\r | |
40 | NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r | |
41 | NVM_EXPRESS_COMMAND Command;\r | |
42 | NVM_EXPRESS_RESPONSE Response;\r | |
43 | EFI_STATUS Status;\r | |
44 | UINT32 BlockSize;\r | |
45 | \r | |
46 | Controller = Device->Controller;\r | |
47 | BlockSize = Device->Media.BlockSize;\r | |
48 | Bytes = Blocks * BlockSize;\r | |
49 | \r | |
50 | ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r | |
51 | ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r | |
52 | ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r | |
53 | \r | |
54 | CommandPacket.NvmeCmd = &Command;\r | |
55 | CommandPacket.NvmeResponse = &Response;\r | |
56 | \r | |
57 | CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;\r | |
58 | CommandPacket.NvmeCmd->Cdw0.Cid = Controller->Cid[1]++;\r | |
59 | CommandPacket.NvmeCmd->Nsid = Device->NamespaceId;\r | |
60 | CommandPacket.TransferBuffer = (VOID *)(UINTN)Buffer;\r | |
61 | \r | |
62 | CommandPacket.TransferLength = Bytes;\r | |
63 | CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r | |
64 | CommandPacket.QueueId = NVME_IO_QUEUE;\r | |
65 | \r | |
66 | CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;\r | |
67 | CommandPacket.NvmeCmd->Cdw11 = (UINT32)(Lba >> 32);\r | |
68 | CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;\r | |
69 | \r | |
70 | CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;\r | |
71 | \r | |
72 | Status = Controller->Passthru.PassThru (\r | |
73 | &Controller->Passthru,\r | |
74 | Device->NamespaceId,\r | |
75 | 0,\r | |
76 | &CommandPacket,\r | |
77 | NULL\r | |
78 | );\r | |
79 | \r | |
80 | return Status;\r | |
81 | }\r | |
82 | \r | |
83 | /**\r | |
84 | Write some sectors to the device.\r | |
85 | \r | |
86 | @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.\r | |
87 | @param Buffer The buffer to be written into the device.\r | |
88 | @param Lba The start block number.\r | |
89 | @param Blocks Total block number to be written.\r | |
90 | \r | |
91 | @retval EFI_SUCCESS Datum are written into the buffer.\r | |
92 | @retval Others Fail to write all the datum.\r | |
93 | \r | |
94 | **/\r | |
95 | EFI_STATUS\r | |
96 | WriteSectors (\r | |
97 | IN NVME_DEVICE_PRIVATE_DATA *Device,\r | |
98 | IN UINT64 Buffer,\r | |
99 | IN UINT64 Lba,\r | |
100 | IN UINT32 Blocks\r | |
101 | )\r | |
102 | {\r | |
103 | NVME_CONTROLLER_PRIVATE_DATA *Controller;\r | |
104 | NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r | |
105 | NVM_EXPRESS_COMMAND Command;\r | |
106 | NVM_EXPRESS_RESPONSE Response;\r | |
107 | EFI_STATUS Status;\r | |
108 | UINT32 Bytes;\r | |
109 | UINT32 BlockSize;\r | |
110 | \r | |
111 | Controller = Device->Controller;\r | |
112 | BlockSize = Device->Media.BlockSize;\r | |
113 | Bytes = Blocks * BlockSize;\r | |
114 | \r | |
115 | ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r | |
116 | ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r | |
117 | ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r | |
118 | \r | |
119 | CommandPacket.NvmeCmd = &Command;\r | |
120 | CommandPacket.NvmeResponse = &Response;\r | |
121 | \r | |
122 | CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC;\r | |
123 | CommandPacket.NvmeCmd->Cdw0.Cid = Controller->Cid[1]++;\r | |
124 | CommandPacket.NvmeCmd->Nsid = Device->NamespaceId;\r | |
125 | CommandPacket.TransferBuffer = (VOID *)(UINTN)Buffer;\r | |
126 | \r | |
127 | CommandPacket.TransferLength = Bytes;\r | |
128 | CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r | |
129 | CommandPacket.QueueId = NVME_IO_QUEUE;\r | |
130 | \r | |
131 | CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;\r | |
132 | CommandPacket.NvmeCmd->Cdw11 = (UINT32)(Lba >> 32);\r | |
133 | CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;\r | |
134 | \r | |
135 | CommandPacket.MetadataBuffer = NULL;\r | |
136 | CommandPacket.MetadataLength = 0;\r | |
137 | \r | |
138 | CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;\r | |
139 | \r | |
140 | Status = Controller->Passthru.PassThru (\r | |
141 | &Controller->Passthru,\r | |
142 | Device->NamespaceId,\r | |
143 | 0,\r | |
144 | &CommandPacket,\r | |
145 | NULL\r | |
146 | );\r | |
147 | \r | |
148 | return Status;\r | |
149 | }\r | |
150 | \r | |
151 | /**\r | |
152 | Read some blocks from the device.\r | |
153 | \r | |
154 | @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.\r | |
155 | @param Buffer The buffer used to store the data read from the device.\r | |
156 | @param Lba The start block number.\r | |
157 | @param Blocks Total block number to be read.\r | |
158 | \r | |
159 | @retval EFI_SUCCESS Datum are read from the device.\r | |
160 | @retval Others Fail to read all the datum.\r | |
161 | \r | |
162 | **/\r | |
163 | EFI_STATUS\r | |
164 | NvmeRead (\r | |
165 | IN NVME_DEVICE_PRIVATE_DATA *Device,\r | |
166 | OUT VOID *Buffer,\r | |
167 | IN UINT64 Lba,\r | |
168 | IN UINTN Blocks\r | |
169 | )\r | |
170 | {\r | |
171 | EFI_STATUS Status;\r | |
172 | UINT32 BlockSize;\r | |
173 | NVME_CONTROLLER_PRIVATE_DATA *Controller;\r | |
174 | UINT32 MaxTransferBlocks;\r | |
7b8883c6 | 175 | UINTN OrginalBlocks;\r |
eb290d02 | 176 | \r |
7b8883c6 FT |
177 | Status = EFI_SUCCESS;\r |
178 | Controller = Device->Controller;\r | |
179 | BlockSize = Device->Media.BlockSize;\r | |
180 | OrginalBlocks = Blocks;\r | |
eb290d02 FT |
181 | \r |
182 | if (Controller->ControllerData->Mdts != 0) {\r | |
183 | MaxTransferBlocks = (1 << (Controller->ControllerData->Mdts)) * (1 << (Controller->Cap.Mpsmin + 12)) / BlockSize;\r | |
184 | } else {\r | |
185 | MaxTransferBlocks = 1024;\r | |
186 | }\r | |
187 | \r | |
188 | while (Blocks > 0) {\r | |
189 | if (Blocks > MaxTransferBlocks) {\r | |
190 | Status = ReadSectors (Device, (UINT64)(UINTN)Buffer, Lba, MaxTransferBlocks);\r | |
191 | \r | |
192 | Blocks -= MaxTransferBlocks;\r | |
193 | Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);\r | |
194 | Lba += MaxTransferBlocks;\r | |
195 | } else {\r | |
196 | Status = ReadSectors (Device, (UINT64)(UINTN)Buffer, Lba, (UINT32)Blocks);\r | |
197 | Blocks = 0;\r | |
198 | }\r | |
199 | \r | |
200 | if (EFI_ERROR(Status)) {\r | |
201 | break;\r | |
202 | }\r | |
203 | }\r | |
204 | \r | |
7b8883c6 | 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));\r |
eb290d02 FT |
206 | \r |
207 | return Status;\r | |
208 | }\r | |
209 | \r | |
210 | /**\r | |
211 | Write some blocks to the device.\r | |
212 | \r | |
213 | @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.\r | |
214 | @param Buffer The buffer to be written into the device.\r | |
215 | @param Lba The start block number.\r | |
216 | @param Blocks Total block number to be written.\r | |
217 | \r | |
218 | @retval EFI_SUCCESS Datum are written into the buffer.\r | |
219 | @retval Others Fail to write all the datum.\r | |
220 | \r | |
221 | **/\r | |
222 | EFI_STATUS\r | |
223 | NvmeWrite (\r | |
224 | IN NVME_DEVICE_PRIVATE_DATA *Device,\r | |
225 | IN VOID *Buffer,\r | |
226 | IN UINT64 Lba,\r | |
227 | IN UINTN Blocks\r | |
228 | )\r | |
229 | {\r | |
230 | EFI_STATUS Status;\r | |
231 | UINT32 BlockSize;\r | |
232 | NVME_CONTROLLER_PRIVATE_DATA *Controller;\r | |
233 | UINT32 MaxTransferBlocks;\r | |
7b8883c6 | 234 | UINTN OrginalBlocks;\r |
eb290d02 | 235 | \r |
7b8883c6 FT |
236 | Status = EFI_SUCCESS;\r |
237 | Controller = Device->Controller;\r | |
238 | BlockSize = Device->Media.BlockSize;\r | |
239 | OrginalBlocks = Blocks;\r | |
eb290d02 FT |
240 | \r |
241 | if (Controller->ControllerData->Mdts != 0) {\r | |
242 | MaxTransferBlocks = (1 << (Controller->ControllerData->Mdts)) * (1 << (Controller->Cap.Mpsmin + 12)) / BlockSize;\r | |
243 | } else {\r | |
244 | MaxTransferBlocks = 1024;\r | |
245 | }\r | |
246 | \r | |
247 | while (Blocks > 0) {\r | |
248 | if (Blocks > MaxTransferBlocks) {\r | |
249 | Status = WriteSectors (Device, (UINT64)(UINTN)Buffer, Lba, MaxTransferBlocks);\r | |
250 | \r | |
251 | Blocks -= MaxTransferBlocks;\r | |
252 | Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);\r | |
253 | Lba += MaxTransferBlocks;\r | |
254 | } else {\r | |
255 | Status = WriteSectors (Device, (UINT64)(UINTN)Buffer, Lba, (UINT32)Blocks);\r | |
256 | Blocks = 0;\r | |
257 | }\r | |
258 | \r | |
259 | if (EFI_ERROR(Status)) {\r | |
260 | break;\r | |
261 | }\r | |
262 | }\r | |
263 | \r | |
7b8883c6 | 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));\r |
eb290d02 FT |
265 | \r |
266 | return Status;\r | |
267 | }\r | |
268 | \r | |
269 | /**\r | |
270 | Flushes all modified data to the device.\r | |
271 | \r | |
272 | @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.\r | |
273 | \r | |
274 | @retval EFI_SUCCESS Datum are written into the buffer.\r | |
275 | @retval Others Fail to write all the datum.\r | |
276 | \r | |
277 | **/\r | |
278 | EFI_STATUS\r | |
279 | NvmeFlush (\r | |
280 | IN NVME_DEVICE_PRIVATE_DATA *Device\r | |
281 | )\r | |
282 | {\r | |
283 | NVME_CONTROLLER_PRIVATE_DATA *Controller;\r | |
284 | NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r | |
285 | NVM_EXPRESS_COMMAND Command;\r | |
286 | NVM_EXPRESS_RESPONSE Response;\r | |
287 | EFI_STATUS Status;\r | |
288 | \r | |
289 | Controller = Device->Controller;\r | |
290 | \r | |
291 | ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r | |
292 | ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r | |
293 | ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r | |
294 | \r | |
295 | CommandPacket.NvmeCmd = &Command;\r | |
296 | CommandPacket.NvmeResponse = &Response;\r | |
297 | \r | |
298 | CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_FLUSH_OPC;\r | |
299 | CommandPacket.NvmeCmd->Cdw0.Cid = Controller->Cid[1]++;\r | |
300 | CommandPacket.NvmeCmd->Nsid = Device->NamespaceId;\r | |
301 | CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r | |
302 | CommandPacket.QueueId = NVME_IO_QUEUE;\r | |
303 | \r | |
304 | Status = Controller->Passthru.PassThru (\r | |
305 | &Controller->Passthru,\r | |
306 | Device->NamespaceId,\r | |
307 | 0,\r | |
308 | &CommandPacket,\r | |
309 | NULL\r | |
310 | );\r | |
311 | \r | |
312 | return Status;\r | |
313 | }\r | |
314 | \r | |
315 | \r | |
316 | /**\r | |
317 | Reset the Block Device.\r | |
318 | \r | |
319 | @param This Indicates a pointer to the calling context.\r | |
320 | @param ExtendedVerification Driver may perform diagnostics on reset.\r | |
321 | \r | |
322 | @retval EFI_SUCCESS The device was reset.\r | |
323 | @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r | |
324 | not be reset.\r | |
325 | \r | |
326 | **/\r | |
327 | EFI_STATUS\r | |
328 | EFIAPI\r | |
329 | NvmeBlockIoReset (\r | |
330 | IN EFI_BLOCK_IO_PROTOCOL *This,\r | |
331 | IN BOOLEAN ExtendedVerification\r | |
332 | )\r | |
333 | {\r | |
334 | EFI_TPL OldTpl;\r | |
335 | NVME_CONTROLLER_PRIVATE_DATA *Private;\r | |
336 | NVME_DEVICE_PRIVATE_DATA *Device;\r | |
337 | EFI_STATUS Status;\r | |
338 | \r | |
339 | if (This == NULL) {\r | |
340 | return EFI_INVALID_PARAMETER;\r | |
341 | }\r | |
342 | \r | |
343 | //\r | |
344 | // For Nvm Express subsystem, reset block device means reset controller.\r | |
345 | //\r | |
346 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r | |
347 | \r | |
348 | Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);\r | |
349 | \r | |
350 | Private = Device->Controller;\r | |
351 | \r | |
352 | Status = NvmeControllerInit (Private);\r | |
353 | \r | |
354 | gBS->RestoreTPL (OldTpl);\r | |
355 | \r | |
356 | return Status;\r | |
357 | }\r | |
358 | \r | |
359 | /**\r | |
360 | Read BufferSize bytes from Lba into Buffer.\r | |
361 | \r | |
362 | @param This Indicates a pointer to the calling context.\r | |
363 | @param MediaId Id of the media, changes every time the media is replaced.\r | |
364 | @param Lba The starting Logical Block Address to read from.\r | |
365 | @param BufferSize Size of Buffer, must be a multiple of device block size.\r | |
366 | @param Buffer A pointer to the destination buffer for the data. The caller is\r | |
367 | responsible for either having implicit or explicit ownership of the buffer.\r | |
368 | \r | |
369 | @retval EFI_SUCCESS The data was read correctly from the device.\r | |
370 | @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r | |
371 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
372 | @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r | |
373 | @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r | |
374 | @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r | |
375 | or the buffer is not on proper alignment.\r | |
376 | \r | |
377 | **/\r | |
378 | EFI_STATUS\r | |
379 | EFIAPI\r | |
380 | NvmeBlockIoReadBlocks (\r | |
381 | IN EFI_BLOCK_IO_PROTOCOL *This,\r | |
382 | IN UINT32 MediaId,\r | |
383 | IN EFI_LBA Lba,\r | |
384 | IN UINTN BufferSize,\r | |
385 | OUT VOID *Buffer\r | |
386 | )\r | |
387 | {\r | |
388 | NVME_DEVICE_PRIVATE_DATA *Device;\r | |
389 | EFI_STATUS Status;\r | |
390 | EFI_BLOCK_IO_MEDIA *Media;\r | |
391 | UINTN BlockSize;\r | |
392 | UINTN NumberOfBlocks;\r | |
393 | UINTN IoAlign;\r | |
394 | EFI_TPL OldTpl;\r | |
395 | \r | |
396 | //\r | |
397 | // Check parameters.\r | |
398 | //\r | |
399 | if (This == NULL) {\r | |
400 | return EFI_INVALID_PARAMETER;\r | |
401 | }\r | |
402 | \r | |
403 | Media = This->Media;\r | |
404 | \r | |
405 | if (MediaId != Media->MediaId) {\r | |
406 | return EFI_MEDIA_CHANGED;\r | |
407 | }\r | |
408 | \r | |
409 | if (Buffer == NULL) {\r | |
410 | return EFI_INVALID_PARAMETER;\r | |
411 | }\r | |
412 | \r | |
413 | if (BufferSize == 0) {\r | |
414 | return EFI_SUCCESS;\r | |
415 | }\r | |
416 | \r | |
417 | BlockSize = Media->BlockSize;\r | |
418 | if ((BufferSize % BlockSize) != 0) {\r | |
419 | return EFI_BAD_BUFFER_SIZE;\r | |
420 | }\r | |
421 | \r | |
422 | NumberOfBlocks = BufferSize / BlockSize;\r | |
423 | if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r | |
424 | return EFI_INVALID_PARAMETER;\r | |
425 | }\r | |
426 | \r | |
427 | IoAlign = Media->IoAlign;\r | |
428 | if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r | |
429 | return EFI_INVALID_PARAMETER;\r | |
430 | }\r | |
431 | \r | |
432 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r | |
433 | \r | |
434 | Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);\r | |
435 | \r | |
436 | Status = NvmeRead (Device, Buffer, Lba, NumberOfBlocks);\r | |
437 | \r | |
438 | gBS->RestoreTPL (OldTpl);\r | |
439 | return Status;\r | |
440 | }\r | |
441 | \r | |
442 | /**\r | |
443 | Write BufferSize bytes from Lba into Buffer.\r | |
444 | \r | |
445 | @param This Indicates a pointer to the calling context.\r | |
446 | @param MediaId The media ID that the write request is for.\r | |
447 | @param Lba The starting logical block address to be written. The caller is\r | |
448 | responsible for writing to only legitimate locations.\r | |
449 | @param BufferSize Size of Buffer, must be a multiple of device block size.\r | |
450 | @param Buffer A pointer to the source buffer for the data.\r | |
451 | \r | |
452 | @retval EFI_SUCCESS The data was written correctly to the device.\r | |
453 | @retval EFI_WRITE_PROTECTED The device can not be written to.\r | |
454 | @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r | |
455 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
456 | @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r | |
457 | @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r | |
458 | @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r | |
459 | or the buffer is not on proper alignment.\r | |
460 | \r | |
461 | **/\r | |
462 | EFI_STATUS\r | |
463 | EFIAPI\r | |
464 | NvmeBlockIoWriteBlocks (\r | |
465 | IN EFI_BLOCK_IO_PROTOCOL *This,\r | |
466 | IN UINT32 MediaId,\r | |
467 | IN EFI_LBA Lba,\r | |
468 | IN UINTN BufferSize,\r | |
469 | IN VOID *Buffer\r | |
470 | )\r | |
471 | {\r | |
472 | NVME_DEVICE_PRIVATE_DATA *Device;\r | |
473 | EFI_STATUS Status;\r | |
474 | EFI_BLOCK_IO_MEDIA *Media;\r | |
475 | UINTN BlockSize;\r | |
476 | UINTN NumberOfBlocks;\r | |
477 | UINTN IoAlign;\r | |
478 | EFI_TPL OldTpl;\r | |
479 | \r | |
480 | //\r | |
481 | // Check parameters.\r | |
482 | //\r | |
483 | if (This == NULL) {\r | |
484 | return EFI_INVALID_PARAMETER;\r | |
485 | }\r | |
486 | \r | |
487 | Media = This->Media;\r | |
488 | \r | |
489 | if (MediaId != Media->MediaId) {\r | |
490 | return EFI_MEDIA_CHANGED;\r | |
491 | }\r | |
492 | \r | |
493 | if (Buffer == NULL) {\r | |
494 | return EFI_INVALID_PARAMETER;\r | |
495 | }\r | |
496 | \r | |
497 | if (BufferSize == 0) {\r | |
498 | return EFI_SUCCESS;\r | |
499 | }\r | |
500 | \r | |
501 | BlockSize = Media->BlockSize;\r | |
502 | if ((BufferSize % BlockSize) != 0) {\r | |
503 | return EFI_BAD_BUFFER_SIZE;\r | |
504 | }\r | |
505 | \r | |
506 | NumberOfBlocks = BufferSize / BlockSize;\r | |
507 | if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r | |
508 | return EFI_INVALID_PARAMETER;\r | |
509 | }\r | |
510 | \r | |
511 | IoAlign = Media->IoAlign;\r | |
512 | if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r | |
513 | return EFI_INVALID_PARAMETER;\r | |
514 | }\r | |
515 | \r | |
516 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r | |
517 | \r | |
518 | Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);\r | |
519 | \r | |
520 | Status = NvmeWrite (Device, Buffer, Lba, NumberOfBlocks);\r | |
521 | \r | |
522 | gBS->RestoreTPL (OldTpl);\r | |
523 | \r | |
524 | return Status;\r | |
525 | }\r | |
526 | \r | |
527 | /**\r | |
528 | Flush the Block Device.\r | |
529 | \r | |
530 | @param This Indicates a pointer to the calling context.\r | |
531 | \r | |
532 | @retval EFI_SUCCESS All outstanding data was written to the device.\r | |
533 | @retval EFI_DEVICE_ERROR The device reported an error while writing back the data.\r | |
534 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
535 | \r | |
536 | **/\r | |
537 | EFI_STATUS\r | |
538 | EFIAPI\r | |
539 | NvmeBlockIoFlushBlocks (\r | |
540 | IN EFI_BLOCK_IO_PROTOCOL *This\r | |
541 | )\r | |
542 | {\r | |
543 | NVME_DEVICE_PRIVATE_DATA *Device;\r | |
544 | EFI_STATUS Status;\r | |
545 | EFI_TPL OldTpl;\r | |
546 | \r | |
547 | //\r | |
548 | // Check parameters.\r | |
549 | //\r | |
550 | if (This == NULL) {\r | |
551 | return EFI_INVALID_PARAMETER;\r | |
552 | }\r | |
553 | \r | |
554 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r | |
555 | \r | |
556 | Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);\r | |
557 | \r | |
558 | Status = NvmeFlush (Device);\r | |
559 | \r | |
560 | gBS->RestoreTPL (OldTpl);\r | |
561 | \r | |
562 | return Status;\r | |
563 | }\r |