]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c
MdeModulePkg NvmExpressDxe: Add BlockIo2 support
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NvmExpressDxe / NvmExpressHci.c
CommitLineData
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
c5921812 5 Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>\r
eb290d02
FT
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 Nvm Express controller capability register.\r
20\r
21 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
22 @param Cap The buffer used to store capability register content.\r
23\r
24 @return EFI_SUCCESS Successfully read the controller capability register content.\r
25 @return EFI_DEVICE_ERROR Fail to read the controller capability register.\r
26\r
27**/\r
28EFI_STATUS\r
29ReadNvmeControllerCapabilities (\r
30 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
31 IN NVME_CAP *Cap\r
32 )\r
33{\r
34 EFI_PCI_IO_PROTOCOL *PciIo;\r
35 EFI_STATUS Status;\r
7b8883c6 36 UINT64 Data;\r
eb290d02
FT
37\r
38 PciIo = Private->PciIo;\r
39 Status = PciIo->Mem.Read (\r
40 PciIo,\r
7b8883c6 41 EfiPciIoWidthUint32,\r
eb290d02
FT
42 NVME_BAR,\r
43 NVME_CAP_OFFSET,\r
7b8883c6
FT
44 2,\r
45 &Data\r
eb290d02
FT
46 );\r
47\r
48 if (EFI_ERROR(Status)) {\r
49 return Status;\r
50 }\r
51\r
7b8883c6 52 WriteUnaligned64 ((UINT64*)Cap, Data);\r
eb290d02
FT
53 return EFI_SUCCESS;\r
54}\r
55\r
56/**\r
57 Read Nvm Express controller configuration register.\r
58\r
59 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
60 @param Cc The buffer used to store configuration register content.\r
61\r
62 @return EFI_SUCCESS Successfully read the controller configuration register content.\r
63 @return EFI_DEVICE_ERROR Fail to read the controller configuration register.\r
64\r
65**/\r
66EFI_STATUS\r
67ReadNvmeControllerConfiguration (\r
68 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
69 IN NVME_CC *Cc\r
70 )\r
71{\r
72 EFI_PCI_IO_PROTOCOL *PciIo;\r
73 EFI_STATUS Status;\r
7b8883c6 74 UINT32 Data;\r
eb290d02
FT
75\r
76 PciIo = Private->PciIo;\r
77 Status = PciIo->Mem.Read (\r
78 PciIo,\r
79 EfiPciIoWidthUint32,\r
80 NVME_BAR,\r
81 NVME_CC_OFFSET,\r
82 1,\r
7b8883c6 83 &Data\r
eb290d02
FT
84 );\r
85\r
86 if (EFI_ERROR(Status)) {\r
87 return Status;\r
88 }\r
89\r
7b8883c6 90 WriteUnaligned32 ((UINT32*)Cc, Data);\r
eb290d02
FT
91 return EFI_SUCCESS;\r
92}\r
93\r
94/**\r
95 Write Nvm Express controller configuration register.\r
96\r
97 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
98 @param Cc The buffer used to store the content to be written into configuration register.\r
99\r
100 @return EFI_SUCCESS Successfully write data into the controller configuration register.\r
101 @return EFI_DEVICE_ERROR Fail to write data into the controller configuration register.\r
102\r
103**/\r
104EFI_STATUS\r
105WriteNvmeControllerConfiguration (\r
106 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
107 IN NVME_CC *Cc\r
108 )\r
109{\r
110 EFI_PCI_IO_PROTOCOL *PciIo;\r
111 EFI_STATUS Status;\r
7b8883c6 112 UINT32 Data;\r
eb290d02
FT
113\r
114 PciIo = Private->PciIo;\r
7b8883c6 115 Data = ReadUnaligned32 ((UINT32*)Cc);\r
eb290d02
FT
116 Status = PciIo->Mem.Write (\r
117 PciIo,\r
118 EfiPciIoWidthUint32,\r
119 NVME_BAR,\r
120 NVME_CC_OFFSET,\r
121 1,\r
7b8883c6 122 &Data\r
eb290d02
FT
123 );\r
124\r
125 if (EFI_ERROR(Status)) {\r
126 return Status;\r
127 }\r
128\r
129 DEBUG ((EFI_D_INFO, "Cc.En: %d\n", Cc->En));\r
130 DEBUG ((EFI_D_INFO, "Cc.Css: %d\n", Cc->Css));\r
131 DEBUG ((EFI_D_INFO, "Cc.Mps: %d\n", Cc->Mps));\r
132 DEBUG ((EFI_D_INFO, "Cc.Ams: %d\n", Cc->Ams));\r
133 DEBUG ((EFI_D_INFO, "Cc.Shn: %d\n", Cc->Shn));\r
134 DEBUG ((EFI_D_INFO, "Cc.Iosqes: %d\n", Cc->Iosqes));\r
135 DEBUG ((EFI_D_INFO, "Cc.Iocqes: %d\n", Cc->Iocqes));\r
136\r
137 return EFI_SUCCESS;\r
138}\r
139\r
140/**\r
141 Read Nvm Express controller status register.\r
142\r
143 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
144 @param Csts The buffer used to store status register content.\r
145\r
146 @return EFI_SUCCESS Successfully read the controller status register content.\r
147 @return EFI_DEVICE_ERROR Fail to read the controller status register.\r
148\r
149**/\r
150EFI_STATUS\r
151ReadNvmeControllerStatus (\r
152 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
153 IN NVME_CSTS *Csts\r
154 )\r
155{\r
156 EFI_PCI_IO_PROTOCOL *PciIo;\r
157 EFI_STATUS Status;\r
7b8883c6 158 UINT32 Data;\r
eb290d02
FT
159\r
160 PciIo = Private->PciIo;\r
161 Status = PciIo->Mem.Read (\r
162 PciIo,\r
163 EfiPciIoWidthUint32,\r
164 NVME_BAR,\r
165 NVME_CSTS_OFFSET,\r
166 1,\r
7b8883c6 167 &Data\r
eb290d02
FT
168 );\r
169\r
170 if (EFI_ERROR(Status)) {\r
171 return Status;\r
172 }\r
173\r
7b8883c6 174 WriteUnaligned32 ((UINT32*)Csts, Data);\r
eb290d02
FT
175 return EFI_SUCCESS;\r
176}\r
177\r
178/**\r
179 Read Nvm Express admin queue attributes register.\r
180\r
181 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
182 @param Aqa The buffer used to store admin queue attributes register content.\r
183\r
184 @return EFI_SUCCESS Successfully read the admin queue attributes register content.\r
185 @return EFI_DEVICE_ERROR Fail to read the admin queue attributes register.\r
186\r
187**/\r
188EFI_STATUS\r
189ReadNvmeAdminQueueAttributes (\r
190 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
191 IN NVME_AQA *Aqa\r
192 )\r
193{\r
194 EFI_PCI_IO_PROTOCOL *PciIo;\r
195 EFI_STATUS Status;\r
7b8883c6 196 UINT32 Data;\r
eb290d02
FT
197\r
198 PciIo = Private->PciIo;\r
199 Status = PciIo->Mem.Read (\r
200 PciIo,\r
201 EfiPciIoWidthUint32,\r
202 NVME_BAR,\r
203 NVME_AQA_OFFSET,\r
204 1,\r
7b8883c6 205 &Data\r
eb290d02
FT
206 );\r
207\r
208 if (EFI_ERROR(Status)) {\r
209 return Status;\r
210 }\r
211\r
7b8883c6 212 WriteUnaligned32 ((UINT32*)Aqa, Data);\r
eb290d02
FT
213 return EFI_SUCCESS;\r
214}\r
215\r
216/**\r
217 Write Nvm Express admin queue attributes register.\r
218\r
219 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
220 @param Aqa The buffer used to store the content to be written into admin queue attributes register.\r
221\r
222 @return EFI_SUCCESS Successfully write data into the admin queue attributes register.\r
223 @return EFI_DEVICE_ERROR Fail to write data into the admin queue attributes register.\r
224\r
225**/\r
226EFI_STATUS\r
227WriteNvmeAdminQueueAttributes (\r
228 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
229 IN NVME_AQA *Aqa\r
230 )\r
231{\r
232 EFI_PCI_IO_PROTOCOL *PciIo;\r
233 EFI_STATUS Status;\r
7b8883c6 234 UINT32 Data;\r
eb290d02
FT
235\r
236 PciIo = Private->PciIo;\r
7b8883c6 237 Data = ReadUnaligned32 ((UINT32*)Aqa);\r
eb290d02
FT
238 Status = PciIo->Mem.Write (\r
239 PciIo,\r
240 EfiPciIoWidthUint32,\r
241 NVME_BAR,\r
242 NVME_AQA_OFFSET,\r
243 1,\r
7b8883c6 244 &Data\r
eb290d02
FT
245 );\r
246\r
247 if (EFI_ERROR(Status)) {\r
248 return Status;\r
249 }\r
250\r
251 DEBUG ((EFI_D_INFO, "Aqa.Asqs: %d\n", Aqa->Asqs));\r
252 DEBUG ((EFI_D_INFO, "Aqa.Acqs: %d\n", Aqa->Acqs));\r
253\r
254 return EFI_SUCCESS;\r
255}\r
256\r
257/**\r
258 Read Nvm Express admin submission queue base address register.\r
259\r
260 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
261 @param Asq The buffer used to store admin submission queue base address register content.\r
262\r
263 @return EFI_SUCCESS Successfully read the admin submission queue base address register content.\r
264 @return EFI_DEVICE_ERROR Fail to read the admin submission queue base address register.\r
265\r
266**/\r
267EFI_STATUS\r
268ReadNvmeAdminSubmissionQueueBaseAddress (\r
269 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
270 IN NVME_ASQ *Asq\r
271 )\r
272{\r
273 EFI_PCI_IO_PROTOCOL *PciIo;\r
274 EFI_STATUS Status;\r
7b8883c6 275 UINT64 Data;\r
eb290d02
FT
276\r
277 PciIo = Private->PciIo;\r
278 Status = PciIo->Mem.Read (\r
279 PciIo,\r
7b8883c6 280 EfiPciIoWidthUint32,\r
eb290d02
FT
281 NVME_BAR,\r
282 NVME_ASQ_OFFSET,\r
7b8883c6
FT
283 2,\r
284 &Data\r
eb290d02
FT
285 );\r
286\r
287 if (EFI_ERROR(Status)) {\r
288 return Status;\r
289 }\r
290\r
7b8883c6 291 WriteUnaligned64 ((UINT64*)Asq, Data);\r
eb290d02
FT
292 return EFI_SUCCESS;\r
293}\r
294\r
295/**\r
296 Write Nvm Express admin submission queue base address register.\r
297\r
298 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
299 @param Asq The buffer used to store the content to be written into admin submission queue base address register.\r
300\r
301 @return EFI_SUCCESS Successfully write data into the admin submission queue base address register.\r
302 @return EFI_DEVICE_ERROR Fail to write data into the admin submission queue base address register.\r
303\r
304**/\r
305EFI_STATUS\r
306WriteNvmeAdminSubmissionQueueBaseAddress (\r
307 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
308 IN NVME_ASQ *Asq\r
309 )\r
310{\r
311 EFI_PCI_IO_PROTOCOL *PciIo;\r
312 EFI_STATUS Status;\r
7b8883c6 313 UINT64 Data;\r
eb290d02
FT
314\r
315 PciIo = Private->PciIo;\r
7b8883c6
FT
316 Data = ReadUnaligned64 ((UINT64*)Asq);\r
317\r
eb290d02
FT
318 Status = PciIo->Mem.Write (\r
319 PciIo,\r
7b8883c6 320 EfiPciIoWidthUint32,\r
eb290d02
FT
321 NVME_BAR,\r
322 NVME_ASQ_OFFSET,\r
7b8883c6
FT
323 2,\r
324 &Data\r
eb290d02
FT
325 );\r
326\r
327 if (EFI_ERROR(Status)) {\r
328 return Status;\r
329 }\r
330\r
c5921812 331 DEBUG ((EFI_D_INFO, "Asq: %lx\n", *Asq));\r
eb290d02
FT
332\r
333 return EFI_SUCCESS;\r
334}\r
335\r
336/**\r
337 Read Nvm Express admin completion queue base address register.\r
338\r
339 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
340 @param Acq The buffer used to store admin completion queue base address register content.\r
341\r
342 @return EFI_SUCCESS Successfully read the admin completion queue base address register content.\r
343 @return EFI_DEVICE_ERROR Fail to read the admin completion queue base address register.\r
344\r
345**/\r
346EFI_STATUS\r
347ReadNvmeAdminCompletionQueueBaseAddress (\r
348 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
349 IN NVME_ACQ *Acq\r
350 )\r
351{\r
352 EFI_PCI_IO_PROTOCOL *PciIo;\r
353 EFI_STATUS Status;\r
7b8883c6 354 UINT64 Data;\r
eb290d02
FT
355\r
356 PciIo = Private->PciIo;\r
7b8883c6 357\r
eb290d02
FT
358 Status = PciIo->Mem.Read (\r
359 PciIo,\r
7b8883c6 360 EfiPciIoWidthUint32,\r
eb290d02
FT
361 NVME_BAR,\r
362 NVME_ACQ_OFFSET,\r
7b8883c6
FT
363 2,\r
364 &Data\r
eb290d02
FT
365 );\r
366\r
367 if (EFI_ERROR(Status)) {\r
368 return Status;\r
369 }\r
370\r
7b8883c6 371 WriteUnaligned64 ((UINT64*)Acq, Data);\r
eb290d02
FT
372 return EFI_SUCCESS;\r
373}\r
374\r
375/**\r
376 Write Nvm Express admin completion queue base address register.\r
377\r
378 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
379 @param Acq The buffer used to store the content to be written into admin completion queue base address register.\r
380\r
381 @return EFI_SUCCESS Successfully write data into the admin completion queue base address register.\r
382 @return EFI_DEVICE_ERROR Fail to write data into the admin completion queue base address register.\r
383\r
384**/\r
385EFI_STATUS\r
386WriteNvmeAdminCompletionQueueBaseAddress (\r
387 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
388 IN NVME_ACQ *Acq\r
389 )\r
390{\r
391 EFI_PCI_IO_PROTOCOL *PciIo;\r
392 EFI_STATUS Status;\r
7b8883c6 393 UINT64 Data;\r
eb290d02
FT
394\r
395 PciIo = Private->PciIo;\r
7b8883c6
FT
396 Data = ReadUnaligned64 ((UINT64*)Acq);\r
397\r
eb290d02
FT
398 Status = PciIo->Mem.Write (\r
399 PciIo,\r
7b8883c6 400 EfiPciIoWidthUint32,\r
eb290d02
FT
401 NVME_BAR,\r
402 NVME_ACQ_OFFSET,\r
7b8883c6
FT
403 2,\r
404 &Data\r
eb290d02
FT
405 );\r
406\r
407 if (EFI_ERROR(Status)) {\r
408 return Status;\r
409 }\r
410\r
c5921812 411 DEBUG ((EFI_D_INFO, "Acq: %lxh\n", *Acq));\r
eb290d02
FT
412\r
413 return EFI_SUCCESS;\r
414}\r
415\r
416/**\r
417 Disable the Nvm Express controller.\r
418\r
419 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
420\r
421 @return EFI_SUCCESS Successfully disable the controller.\r
422 @return EFI_DEVICE_ERROR Fail to disable the controller.\r
423\r
424**/\r
425EFI_STATUS\r
426NvmeDisableController (\r
427 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
428 )\r
429{\r
430 NVME_CC Cc;\r
431 NVME_CSTS Csts;\r
432 EFI_STATUS Status;\r
4ab4497c
TF
433 UINT32 Index;\r
434 UINT8 Timeout;\r
eb290d02
FT
435\r
436 //\r
437 // Read Controller Configuration Register.\r
438 //\r
439 Status = ReadNvmeControllerConfiguration (Private, &Cc);\r
440 if (EFI_ERROR(Status)) {\r
441 return Status;\r
442 }\r
443\r
444 Cc.En = 0;\r
445\r
446 //\r
447 // Disable the controller.\r
448 //\r
449 Status = WriteNvmeControllerConfiguration (Private, &Cc);\r
450\r
451 if (EFI_ERROR(Status)) {\r
452 return Status;\r
453 }\r
454\r
eb290d02 455 //\r
4ab4497c
TF
456 // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to transition from 1 to 0 after\r
457 // Cc.Enable transition from 1 to 0. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.\r
eb290d02 458 //\r
4ab4497c
TF
459 if (Private->Cap.To == 0) {\r
460 Timeout = 1;\r
461 } else {\r
462 Timeout = Private->Cap.To;\r
463 }\r
eb290d02 464\r
4ab4497c
TF
465 for(Index = (Timeout * 500); Index != 0; --Index) {\r
466 gBS->Stall(1000);\r
467\r
468 //\r
469 // Check if the controller is initialized\r
470 //\r
471 Status = ReadNvmeControllerStatus (Private, &Csts);\r
472\r
473 if (EFI_ERROR(Status)) {\r
474 return Status;\r
475 }\r
476\r
477 if (Csts.Rdy == 0) {\r
478 break;\r
479 }\r
eb290d02
FT
480 }\r
481\r
4ab4497c
TF
482 if (Index == 0) {\r
483 Status = EFI_DEVICE_ERROR;\r
eb290d02
FT
484 }\r
485\r
486 DEBUG ((EFI_D_INFO, "NVMe controller is disabled with status [%r].\n", Status));\r
487 return Status;\r
488}\r
489\r
490/**\r
491 Enable the Nvm Express controller.\r
492\r
493 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
494\r
495 @return EFI_SUCCESS Successfully enable the controller.\r
496 @return EFI_DEVICE_ERROR Fail to enable the controller.\r
497 @return EFI_TIMEOUT Fail to enable the controller in given time slot.\r
498\r
499**/\r
500EFI_STATUS\r
501NvmeEnableController (\r
502 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
503 )\r
504{\r
505 NVME_CC Cc;\r
506 NVME_CSTS Csts;\r
507 EFI_STATUS Status;\r
508 UINT32 Index;\r
509 UINT8 Timeout;\r
510\r
511 //\r
d6c55989
FT
512 // Enable the controller.\r
513 // CC.AMS, CC.MPS and CC.CSS are all set to 0.\r
eb290d02
FT
514 //\r
515 ZeroMem (&Cc, sizeof (NVME_CC));\r
166801d2
FT
516 Cc.En = 1;\r
517 Cc.Iosqes = 6;\r
518 Cc.Iocqes = 4;\r
eb290d02 519\r
166801d2 520 Status = WriteNvmeControllerConfiguration (Private, &Cc);\r
eb290d02
FT
521 if (EFI_ERROR(Status)) {\r
522 return Status;\r
523 }\r
524\r
525 //\r
526 // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after\r
527 // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.\r
528 //\r
529 if (Private->Cap.To == 0) {\r
530 Timeout = 1;\r
531 } else {\r
532 Timeout = Private->Cap.To;\r
533 }\r
534\r
535 for(Index = (Timeout * 500); Index != 0; --Index) {\r
536 gBS->Stall(1000);\r
537\r
538 //\r
539 // Check if the controller is initialized\r
540 //\r
541 Status = ReadNvmeControllerStatus (Private, &Csts);\r
542\r
543 if (EFI_ERROR(Status)) {\r
544 return Status;\r
545 }\r
546\r
547 if (Csts.Rdy) {\r
548 break;\r
549 }\r
550 }\r
551\r
552 if (Index == 0) {\r
553 Status = EFI_TIMEOUT;\r
554 }\r
555\r
556 DEBUG ((EFI_D_INFO, "NVMe controller is enabled with status [%r].\n", Status));\r
557 return Status;\r
558}\r
559\r
560/**\r
561 Get identify controller data.\r
562\r
563 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
564 @param Buffer The buffer used to store the identify controller data.\r
565\r
566 @return EFI_SUCCESS Successfully get the identify controller data.\r
567 @return EFI_DEVICE_ERROR Fail to get the identify controller data.\r
568\r
569**/\r
570EFI_STATUS\r
571NvmeIdentifyController (\r
572 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
573 IN VOID *Buffer\r
574 )\r
575{\r
d6c55989
FT
576 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
577 EFI_NVM_EXPRESS_COMMAND Command;\r
578 EFI_NVM_EXPRESS_COMPLETION Completion;\r
eb290d02
FT
579 EFI_STATUS Status;\r
580\r
d6c55989
FT
581 ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
582 ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));\r
583 ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));\r
eb290d02 584\r
754b489b 585 Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;\r
eb290d02
FT
586 //\r
587 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.\r
588 // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.\r
589 //\r
590 Command.Nsid = 0;\r
591\r
592 CommandPacket.NvmeCmd = &Command;\r
d6c55989 593 CommandPacket.NvmeCompletion = &Completion;\r
eb290d02
FT
594 CommandPacket.TransferBuffer = Buffer;\r
595 CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA);\r
596 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
d6c55989 597 CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
eb290d02
FT
598 //\r
599 // Set bit 0 (Cns bit) to 1 to identify a controller\r
600 //\r
601 Command.Cdw10 = 1;\r
602 Command.Flags = CDW10_VALID;\r
603\r
604 Status = Private->Passthru.PassThru (\r
605 &Private->Passthru,\r
606 NVME_CONTROLLER_ID,\r
eb290d02
FT
607 &CommandPacket,\r
608 NULL\r
609 );\r
610\r
611 return Status;\r
612}\r
613\r
614/**\r
615 Get specified identify namespace data.\r
616\r
617 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
618 @param NamespaceId The specified namespace identifier.\r
619 @param Buffer The buffer used to store the identify namespace data.\r
620\r
621 @return EFI_SUCCESS Successfully get the identify namespace data.\r
622 @return EFI_DEVICE_ERROR Fail to get the identify namespace data.\r
623\r
624**/\r
625EFI_STATUS\r
626NvmeIdentifyNamespace (\r
627 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
628 IN UINT32 NamespaceId,\r
629 IN VOID *Buffer\r
630 )\r
631{\r
d6c55989
FT
632 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
633 EFI_NVM_EXPRESS_COMMAND Command;\r
634 EFI_NVM_EXPRESS_COMPLETION Completion;\r
eb290d02
FT
635 EFI_STATUS Status;\r
636\r
d6c55989
FT
637 ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
638 ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));\r
639 ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));\r
eb290d02 640\r
d6c55989
FT
641 CommandPacket.NvmeCmd = &Command;\r
642 CommandPacket.NvmeCompletion = &Completion;\r
eb290d02 643\r
754b489b 644 Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;\r
eb290d02
FT
645 Command.Nsid = NamespaceId;\r
646 CommandPacket.TransferBuffer = Buffer;\r
647 CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA);\r
648 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
d6c55989 649 CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
eb290d02
FT
650 //\r
651 // Set bit 0 (Cns bit) to 1 to identify a namespace\r
652 //\r
653 CommandPacket.NvmeCmd->Cdw10 = 0;\r
654 CommandPacket.NvmeCmd->Flags = CDW10_VALID;\r
655\r
656 Status = Private->Passthru.PassThru (\r
657 &Private->Passthru,\r
658 NamespaceId,\r
eb290d02
FT
659 &CommandPacket,\r
660 NULL\r
661 );\r
662\r
663 return Status;\r
664}\r
665\r
666/**\r
667 Create io completion queue.\r
668\r
669 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
670\r
671 @return EFI_SUCCESS Successfully create io completion queue.\r
672 @return EFI_DEVICE_ERROR Fail to create io completion queue.\r
673\r
674**/\r
675EFI_STATUS\r
676NvmeCreateIoCompletionQueue (\r
677 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
678 )\r
679{\r
d6c55989
FT
680 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
681 EFI_NVM_EXPRESS_COMMAND Command;\r
682 EFI_NVM_EXPRESS_COMPLETION Completion;\r
eb290d02
FT
683 EFI_STATUS Status;\r
684 NVME_ADMIN_CRIOCQ CrIoCq;\r
758ea946
HW
685 UINT32 Index;\r
686\r
687 for (Index = 1; Index < NVME_MAX_QUEUES; Index++) {\r
688 ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
689 ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));\r
690 ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));\r
691 ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));\r
692\r
693 CommandPacket.NvmeCmd = &Command;\r
694 CommandPacket.NvmeCompletion = &Completion;\r
695\r
696 Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_CMD;\r
697 CommandPacket.TransferBuffer = Private->CqBufferPciAddr[Index];\r
698 CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
699 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
700 CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
701\r
702 CrIoCq.Qid = Index;\r
703 CrIoCq.Qsize = (Index == 1) ? NVME_CCQ_SIZE : NVME_ASYNC_CCQ_SIZE;\r
704 CrIoCq.Pc = 1;\r
705 CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));\r
706 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
707\r
708 Status = Private->Passthru.PassThru (\r
709 &Private->Passthru,\r
710 0,\r
711 &CommandPacket,\r
712 NULL\r
713 );\r
714 if (EFI_ERROR (Status)) {\r
715 break;\r
716 }\r
717 }\r
eb290d02
FT
718\r
719 return Status;\r
720}\r
721\r
722/**\r
723 Create io submission queue.\r
724\r
725 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
726\r
727 @return EFI_SUCCESS Successfully create io submission queue.\r
728 @return EFI_DEVICE_ERROR Fail to create io submission queue.\r
729\r
730**/\r
731EFI_STATUS\r
732NvmeCreateIoSubmissionQueue (\r
733 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
734 )\r
735{\r
d6c55989
FT
736 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
737 EFI_NVM_EXPRESS_COMMAND Command;\r
738 EFI_NVM_EXPRESS_COMPLETION Completion;\r
eb290d02
FT
739 EFI_STATUS Status;\r
740 NVME_ADMIN_CRIOSQ CrIoSq;\r
758ea946
HW
741 UINT32 Index;\r
742\r
743 for (Index = 1; Index < NVME_MAX_QUEUES; Index++) {\r
744 ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
745 ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));\r
746 ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));\r
747 ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));\r
748\r
749 CommandPacket.NvmeCmd = &Command;\r
750 CommandPacket.NvmeCompletion = &Completion;\r
751\r
752 Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_CMD;\r
753 CommandPacket.TransferBuffer = Private->SqBufferPciAddr[Index];\r
754 CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
755 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
756 CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
757\r
758 CrIoSq.Qid = Index;\r
759 CrIoSq.Qsize = (Index == 1) ? NVME_CSQ_SIZE : NVME_ASYNC_CSQ_SIZE;\r
760 CrIoSq.Pc = 1;\r
761 CrIoSq.Cqid = Index;\r
762 CrIoSq.Qprio = 0;\r
763 CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));\r
764 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
765\r
766 Status = Private->Passthru.PassThru (\r
767 &Private->Passthru,\r
768 0,\r
769 &CommandPacket,\r
770 NULL\r
771 );\r
772 if (EFI_ERROR (Status)) {\r
773 break;\r
774 }\r
775 }\r
eb290d02
FT
776\r
777 return Status;\r
778}\r
779\r
780/**\r
781 Initialize the Nvm Express controller.\r
782\r
783 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
784\r
785 @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.\r
786 @retval Others A device error occurred while initializing the controller.\r
787\r
788**/\r
789EFI_STATUS\r
790NvmeControllerInit (\r
791 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
792 )\r
793{\r
794 EFI_STATUS Status;\r
795 EFI_PCI_IO_PROTOCOL *PciIo;\r
796 UINT64 Supports;\r
797 NVME_AQA Aqa;\r
798 NVME_ASQ Asq;\r
799 NVME_ACQ Acq;\r
da7c7274
FT
800 UINT8 Sn[21];\r
801 UINT8 Mn[41];\r
eb290d02
FT
802 //\r
803 // Save original PCI attributes and enable this controller.\r
804 //\r
805 PciIo = Private->PciIo;\r
806 Status = PciIo->Attributes (\r
807 PciIo,\r
808 EfiPciIoAttributeOperationGet,\r
809 0,\r
810 &Private->PciAttributes\r
811 );\r
812\r
813 if (EFI_ERROR (Status)) {\r
814 return Status;\r
815 }\r
816\r
817 Status = PciIo->Attributes (\r
818 PciIo,\r
819 EfiPciIoAttributeOperationSupported,\r
820 0,\r
821 &Supports\r
822 );\r
823\r
824 if (!EFI_ERROR (Status)) {\r
6e1e5405 825 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
eb290d02
FT
826 Status = PciIo->Attributes (\r
827 PciIo,\r
828 EfiPciIoAttributeOperationEnable,\r
829 Supports,\r
830 NULL\r
831 );\r
832 }\r
833\r
834 if (EFI_ERROR (Status)) {\r
835 DEBUG ((EFI_D_INFO, "NvmeControllerInit: failed to enable controller\n"));\r
836 return Status;\r
837 }\r
838\r
839 //\r
840 // Read the Controller Capabilities register and verify that the NVM command set is supported\r
841 //\r
842 Status = ReadNvmeControllerCapabilities (Private, &Private->Cap);\r
843 if (EFI_ERROR (Status)) {\r
844 return Status;\r
845 }\r
846\r
847 if (Private->Cap.Css != 0x01) {\r
848 DEBUG ((EFI_D_INFO, "NvmeControllerInit: the controller doesn't support NVMe command set\n"));\r
849 return EFI_UNSUPPORTED;\r
850 }\r
851\r
852 //\r
853 // Currently the driver only supports 4k page size.\r
854 //\r
855 ASSERT ((Private->Cap.Mpsmin + 12) <= EFI_PAGE_SHIFT);\r
856\r
857 Private->Cid[0] = 0;\r
858 Private->Cid[1] = 0;\r
758ea946 859 Private->Cid[2] = 0;\r
6523ae8b
TF
860 Private->Pt[0] = 0;\r
861 Private->Pt[1] = 0;\r
758ea946 862 Private->Pt[2] = 0;\r
6523ae8b
TF
863 Private->SqTdbl[0].Sqt = 0;\r
864 Private->SqTdbl[1].Sqt = 0;\r
758ea946 865 Private->SqTdbl[2].Sqt = 0;\r
6523ae8b
TF
866 Private->CqHdbl[0].Cqh = 0;\r
867 Private->CqHdbl[1].Cqh = 0;\r
758ea946
HW
868 Private->CqHdbl[2].Cqh = 0;\r
869 Private->AsyncSqHead = 0;\r
eb290d02
FT
870\r
871 Status = NvmeDisableController (Private);\r
872\r
873 if (EFI_ERROR(Status)) {\r
874 return Status;\r
875 }\r
876\r
877 //\r
878 // set number of entries admin submission & completion queues.\r
879 //\r
d45c8c30
FT
880 Aqa.Asqs = NVME_ASQ_SIZE;\r
881 Aqa.Rsvd1 = 0;\r
882 Aqa.Acqs = NVME_ACQ_SIZE;\r
883 Aqa.Rsvd2 = 0;\r
eb290d02
FT
884\r
885 //\r
886 // Address of admin submission queue.\r
887 //\r
c5921812 888 Asq = (UINT64)(UINTN)(Private->BufferPciAddr) & ~0xFFF;\r
eb290d02
FT
889\r
890 //\r
891 // Address of admin completion queue.\r
892 //\r
c5921812 893 Acq = (UINT64)(UINTN)(Private->BufferPciAddr + EFI_PAGE_SIZE) & ~0xFFF;\r
eb290d02
FT
894\r
895 //\r
896 // Address of I/O submission & completion queue.\r
897 //\r
758ea946 898 ZeroMem (Private->Buffer, EFI_PAGES_TO_SIZE (6));\r
eb290d02
FT
899 Private->SqBuffer[0] = (NVME_SQ *)(UINTN)(Private->Buffer);\r
900 Private->SqBufferPciAddr[0] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr);\r
901 Private->CqBuffer[0] = (NVME_CQ *)(UINTN)(Private->Buffer + 1 * EFI_PAGE_SIZE);\r
902 Private->CqBufferPciAddr[0] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 1 * EFI_PAGE_SIZE);\r
903 Private->SqBuffer[1] = (NVME_SQ *)(UINTN)(Private->Buffer + 2 * EFI_PAGE_SIZE);\r
904 Private->SqBufferPciAddr[1] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 2 * EFI_PAGE_SIZE);\r
905 Private->CqBuffer[1] = (NVME_CQ *)(UINTN)(Private->Buffer + 3 * EFI_PAGE_SIZE);\r
906 Private->CqBufferPciAddr[1] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 3 * EFI_PAGE_SIZE);\r
758ea946
HW
907 Private->SqBuffer[2] = (NVME_SQ *)(UINTN)(Private->Buffer + 4 * EFI_PAGE_SIZE);\r
908 Private->SqBufferPciAddr[2] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 4 * EFI_PAGE_SIZE);\r
909 Private->CqBuffer[2] = (NVME_CQ *)(UINTN)(Private->Buffer + 5 * EFI_PAGE_SIZE);\r
910 Private->CqBufferPciAddr[2] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 5 * EFI_PAGE_SIZE);\r
eb290d02
FT
911\r
912 DEBUG ((EFI_D_INFO, "Private->Buffer = [%016X]\n", (UINT64)(UINTN)Private->Buffer));\r
758ea946
HW
913 DEBUG ((EFI_D_INFO, "Admin Submission Queue size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));\r
914 DEBUG ((EFI_D_INFO, "Admin Completion Queue size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));\r
915 DEBUG ((EFI_D_INFO, "Admin Submission Queue (SqBuffer[0]) = [%016X]\n", Private->SqBuffer[0]));\r
916 DEBUG ((EFI_D_INFO, "Admin Completion Queue (CqBuffer[0]) = [%016X]\n", Private->CqBuffer[0]));\r
917 DEBUG ((EFI_D_INFO, "Sync I/O Submission Queue (SqBuffer[1]) = [%016X]\n", Private->SqBuffer[1]));\r
918 DEBUG ((EFI_D_INFO, "Sync I/O Completion Queue (CqBuffer[1]) = [%016X]\n", Private->CqBuffer[1]));\r
919 DEBUG ((EFI_D_INFO, "Async I/O Submission Queue (SqBuffer[2]) = [%016X]\n", Private->SqBuffer[2]));\r
920 DEBUG ((EFI_D_INFO, "Async I/O Completion Queue (CqBuffer[2]) = [%016X]\n", Private->CqBuffer[2]));\r
eb290d02
FT
921\r
922 //\r
923 // Program admin queue attributes.\r
924 //\r
925 Status = WriteNvmeAdminQueueAttributes (Private, &Aqa);\r
926\r
927 if (EFI_ERROR(Status)) {\r
928 return Status;\r
929 }\r
930\r
931 //\r
932 // Program admin submission queue address.\r
933 //\r
934 Status = WriteNvmeAdminSubmissionQueueBaseAddress (Private, &Asq);\r
935\r
936 if (EFI_ERROR(Status)) {\r
937 return Status;\r
938 }\r
939\r
940 //\r
941 // Program admin completion queue address.\r
942 //\r
943 Status = WriteNvmeAdminCompletionQueueBaseAddress (Private, &Acq);\r
944\r
945 if (EFI_ERROR(Status)) {\r
946 return Status;\r
947 }\r
948\r
949 Status = NvmeEnableController (Private);\r
950 if (EFI_ERROR(Status)) {\r
951 return Status;\r
952 }\r
953\r
eb290d02
FT
954 //\r
955 // Allocate buffer for Identify Controller data\r
956 //\r
eb290d02 957 if (Private->ControllerData == NULL) {\r
6523ae8b
TF
958 Private->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)AllocateZeroPool (sizeof(NVME_ADMIN_CONTROLLER_DATA));\r
959 \r
960 if (Private->ControllerData == NULL) {\r
961 return EFI_OUT_OF_RESOURCES;\r
962 }\r
eb290d02
FT
963 }\r
964\r
965 //\r
966 // Get current Identify Controller Data\r
967 //\r
968 Status = NvmeIdentifyController (Private, Private->ControllerData);\r
969\r
970 if (EFI_ERROR(Status)) {\r
971 FreePool(Private->ControllerData);\r
972 Private->ControllerData = NULL;\r
973 return EFI_NOT_FOUND;\r
974 }\r
7b8883c6
FT
975\r
976 //\r
977 // Dump NvmExpress Identify Controller Data\r
978 //\r
da7c7274
FT
979 CopyMem (Sn, Private->ControllerData->Sn, sizeof (Private->ControllerData->Sn));\r
980 Sn[20] = 0;\r
981 CopyMem (Mn, Private->ControllerData->Mn, sizeof (Private->ControllerData->Mn));\r
982 Mn[40] = 0;\r
7b8883c6
FT
983 DEBUG ((EFI_D_INFO, " == NVME IDENTIFY CONTROLLER DATA ==\n"));\r
984 DEBUG ((EFI_D_INFO, " PCI VID : 0x%x\n", Private->ControllerData->Vid));\r
985 DEBUG ((EFI_D_INFO, " PCI SSVID : 0x%x\n", Private->ControllerData->Ssvid));\r
da7c7274
FT
986 DEBUG ((EFI_D_INFO, " SN : %a\n", Sn));\r
987 DEBUG ((EFI_D_INFO, " MN : %a\n", Mn));\r
7b8883c6
FT
988 DEBUG ((EFI_D_INFO, " FR : 0x%x\n", *((UINT64*)Private->ControllerData->Fr)));\r
989 DEBUG ((EFI_D_INFO, " RAB : 0x%x\n", Private->ControllerData->Rab));\r
4ab4497c 990 DEBUG ((EFI_D_INFO, " IEEE : 0x%x\n", *(UINT32*)Private->ControllerData->Ieee_oui));\r
7b8883c6
FT
991 DEBUG ((EFI_D_INFO, " AERL : 0x%x\n", Private->ControllerData->Aerl));\r
992 DEBUG ((EFI_D_INFO, " SQES : 0x%x\n", Private->ControllerData->Sqes));\r
993 DEBUG ((EFI_D_INFO, " CQES : 0x%x\n", Private->ControllerData->Cqes));\r
994 DEBUG ((EFI_D_INFO, " NN : 0x%x\n", Private->ControllerData->Nn));\r
995\r
d6c55989 996 //\r
758ea946
HW
997 // Create two I/O completion queues.\r
998 // One for blocking I/O, one for non-blocking I/O.\r
d6c55989
FT
999 //\r
1000 Status = NvmeCreateIoCompletionQueue (Private);\r
1001 if (EFI_ERROR(Status)) {\r
1002 return Status;\r
1003 }\r
1004\r
1005 //\r
758ea946
HW
1006 // Create two I/O Submission queues.\r
1007 // One for blocking I/O, one for non-blocking I/O.\r
d6c55989
FT
1008 //\r
1009 Status = NvmeCreateIoSubmissionQueue (Private);\r
1010 if (EFI_ERROR(Status)) {\r
1011 return Status;\r
1012 }\r
1013\r
eb290d02
FT
1014 return Status;\r
1015}\r
1016\r