]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c
MdeModulePkg/NvmExpressDxe: Fix an issue of potential uninitialized local variable
[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
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 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
331 DEBUG ((EFI_D_INFO, "Asq.Asqb: %lx\n", Asq->Asqb));\r
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
411 DEBUG ((EFI_D_INFO, "Acq.Acqb: %lxh\n", Acq->Acqb));\r
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
433\r
434 //\r
435 // Read Controller Configuration Register.\r
436 //\r
437 Status = ReadNvmeControllerConfiguration (Private, &Cc);\r
438 if (EFI_ERROR(Status)) {\r
439 return Status;\r
440 }\r
441\r
442 Cc.En = 0;\r
443\r
444 //\r
445 // Disable the controller.\r
446 //\r
447 Status = WriteNvmeControllerConfiguration (Private, &Cc);\r
448\r
449 if (EFI_ERROR(Status)) {\r
450 return Status;\r
451 }\r
452\r
453 gBS->Stall(10000);\r
454\r
455 //\r
456 // Check if the controller is reset\r
457 //\r
458 Status = ReadNvmeControllerStatus (Private, &Csts);\r
459\r
460 if (EFI_ERROR(Status)) {\r
461 return Status;\r
462 }\r
463\r
464 if (Csts.Rdy != 0) {\r
465 return EFI_DEVICE_ERROR;\r
466 }\r
467\r
468 DEBUG ((EFI_D_INFO, "NVMe controller is disabled with status [%r].\n", Status));\r
469 return Status;\r
470}\r
471\r
472/**\r
473 Enable the Nvm Express controller.\r
474\r
475 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
476\r
477 @return EFI_SUCCESS Successfully enable the controller.\r
478 @return EFI_DEVICE_ERROR Fail to enable the controller.\r
479 @return EFI_TIMEOUT Fail to enable the controller in given time slot.\r
480\r
481**/\r
482EFI_STATUS\r
483NvmeEnableController (\r
484 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
485 )\r
486{\r
487 NVME_CC Cc;\r
488 NVME_CSTS Csts;\r
489 EFI_STATUS Status;\r
490 UINT32 Index;\r
491 UINT8 Timeout;\r
492\r
493 //\r
494 // Enable the controller\r
495 //\r
496 ZeroMem (&Cc, sizeof (NVME_CC));\r
497 Cc.En = 1;\r
498 Cc.Iosqes = 6;\r
499 Cc.Iocqes = 4;\r
500 Status = WriteNvmeControllerConfiguration (Private, &Cc);\r
501\r
502 if (EFI_ERROR(Status)) {\r
503 return Status;\r
504 }\r
505\r
506 //\r
507 // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after\r
508 // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.\r
509 //\r
510 if (Private->Cap.To == 0) {\r
511 Timeout = 1;\r
512 } else {\r
513 Timeout = Private->Cap.To;\r
514 }\r
515\r
516 for(Index = (Timeout * 500); Index != 0; --Index) {\r
517 gBS->Stall(1000);\r
518\r
519 //\r
520 // Check if the controller is initialized\r
521 //\r
522 Status = ReadNvmeControllerStatus (Private, &Csts);\r
523\r
524 if (EFI_ERROR(Status)) {\r
525 return Status;\r
526 }\r
527\r
528 if (Csts.Rdy) {\r
529 break;\r
530 }\r
531 }\r
532\r
533 if (Index == 0) {\r
534 Status = EFI_TIMEOUT;\r
535 }\r
536\r
537 DEBUG ((EFI_D_INFO, "NVMe controller is enabled with status [%r].\n", Status));\r
538 return Status;\r
539}\r
540\r
541/**\r
542 Get identify controller data.\r
543\r
544 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
545 @param Buffer The buffer used to store the identify controller data.\r
546\r
547 @return EFI_SUCCESS Successfully get the identify controller data.\r
548 @return EFI_DEVICE_ERROR Fail to get the identify controller data.\r
549\r
550**/\r
551EFI_STATUS\r
552NvmeIdentifyController (\r
553 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
554 IN VOID *Buffer\r
555 )\r
556{\r
557 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
558 NVM_EXPRESS_COMMAND Command;\r
559 NVM_EXPRESS_RESPONSE Response;\r
560 EFI_STATUS Status;\r
561\r
562 ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
563 ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
564 ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
565\r
566 Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC;\r
567 Command.Cdw0.Cid = Private->Cid[0]++;\r
568 //\r
569 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.\r
570 // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.\r
571 //\r
572 Command.Nsid = 0;\r
573\r
574 CommandPacket.NvmeCmd = &Command;\r
575 CommandPacket.NvmeResponse = &Response;\r
576 CommandPacket.TransferBuffer = Buffer;\r
577 CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA);\r
578 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
579 CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
580 //\r
581 // Set bit 0 (Cns bit) to 1 to identify a controller\r
582 //\r
583 Command.Cdw10 = 1;\r
584 Command.Flags = CDW10_VALID;\r
585\r
586 Status = Private->Passthru.PassThru (\r
587 &Private->Passthru,\r
588 NVME_CONTROLLER_ID,\r
589 0,\r
590 &CommandPacket,\r
591 NULL\r
592 );\r
593\r
594 return Status;\r
595}\r
596\r
597/**\r
598 Get specified identify namespace data.\r
599\r
600 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
601 @param NamespaceId The specified namespace identifier.\r
602 @param Buffer The buffer used to store the identify namespace data.\r
603\r
604 @return EFI_SUCCESS Successfully get the identify namespace data.\r
605 @return EFI_DEVICE_ERROR Fail to get the identify namespace data.\r
606\r
607**/\r
608EFI_STATUS\r
609NvmeIdentifyNamespace (\r
610 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
611 IN UINT32 NamespaceId,\r
612 IN VOID *Buffer\r
613 )\r
614{\r
615 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
616 NVM_EXPRESS_COMMAND Command;\r
617 NVM_EXPRESS_RESPONSE Response;\r
618 EFI_STATUS Status;\r
619\r
620 ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
621 ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
622 ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
623\r
624 CommandPacket.NvmeCmd = &Command;\r
625 CommandPacket.NvmeResponse = &Response;\r
626\r
627 Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC;\r
628 Command.Cdw0.Cid = Private->Cid[0]++;\r
629 Command.Nsid = NamespaceId;\r
630 CommandPacket.TransferBuffer = Buffer;\r
631 CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA);\r
632 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
633 CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
634 //\r
635 // Set bit 0 (Cns bit) to 1 to identify a namespace\r
636 //\r
637 CommandPacket.NvmeCmd->Cdw10 = 0;\r
638 CommandPacket.NvmeCmd->Flags = CDW10_VALID;\r
639\r
640 Status = Private->Passthru.PassThru (\r
641 &Private->Passthru,\r
642 NamespaceId,\r
643 0,\r
644 &CommandPacket,\r
645 NULL\r
646 );\r
647\r
648 return Status;\r
649}\r
650\r
651/**\r
652 Create io completion queue.\r
653\r
654 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
655\r
656 @return EFI_SUCCESS Successfully create io completion queue.\r
657 @return EFI_DEVICE_ERROR Fail to create io completion queue.\r
658\r
659**/\r
660EFI_STATUS\r
661NvmeCreateIoCompletionQueue (\r
662 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
663 )\r
664{\r
665 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
666 NVM_EXPRESS_COMMAND Command;\r
667 NVM_EXPRESS_RESPONSE Response;\r
668 EFI_STATUS Status;\r
669 NVME_ADMIN_CRIOCQ CrIoCq;\r
670\r
671 ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
672 ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
673 ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
674 ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));\r
675\r
676 CommandPacket.NvmeCmd = &Command;\r
677 CommandPacket.NvmeResponse = &Response;\r
678\r
679 Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_OPC;\r
680 Command.Cdw0.Cid = Private->Cid[0]++;\r
681 CommandPacket.TransferBuffer = Private->CqBufferPciAddr[1];\r
682 CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
683 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
684 CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
685\r
686 CrIoCq.Qid = NVME_IO_QUEUE;\r
687 CrIoCq.Qsize = NVME_CCQ_SIZE;\r
688 CrIoCq.Pc = 1;\r
689 CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));\r
690 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
691\r
692 Status = Private->Passthru.PassThru (\r
693 &Private->Passthru,\r
694 0,\r
695 0,\r
696 &CommandPacket,\r
697 NULL\r
698 );\r
699\r
700 return Status;\r
701}\r
702\r
703/**\r
704 Create io submission queue.\r
705\r
706 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
707\r
708 @return EFI_SUCCESS Successfully create io submission queue.\r
709 @return EFI_DEVICE_ERROR Fail to create io submission queue.\r
710\r
711**/\r
712EFI_STATUS\r
713NvmeCreateIoSubmissionQueue (\r
714 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
715 )\r
716{\r
717 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
718 NVM_EXPRESS_COMMAND Command;\r
719 NVM_EXPRESS_RESPONSE Response;\r
720 EFI_STATUS Status;\r
721 NVME_ADMIN_CRIOSQ CrIoSq;\r
722\r
723 ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
724 ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
725 ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
726 ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));\r
727\r
728 CommandPacket.NvmeCmd = &Command;\r
729 CommandPacket.NvmeResponse = &Response;\r
730\r
731 Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_OPC;\r
732 Command.Cdw0.Cid = Private->Cid[0]++;\r
733 CommandPacket.TransferBuffer = Private->SqBufferPciAddr[1];\r
734 CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
735 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
736 CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
737\r
738 CrIoSq.Qid = NVME_IO_QUEUE;\r
739 CrIoSq.Qsize = NVME_CSQ_SIZE;\r
740 CrIoSq.Pc = 1;\r
741 CrIoSq.Cqid = NVME_IO_QUEUE;\r
742 CrIoSq.Qprio = 0;\r
743 CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));\r
744 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
745\r
746 Status = Private->Passthru.PassThru (\r
747 &Private->Passthru,\r
748 0,\r
749 0,\r
750 &CommandPacket,\r
751 NULL\r
752 );\r
753\r
754 return Status;\r
755}\r
756\r
757/**\r
758 Initialize the Nvm Express controller.\r
759\r
760 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
761\r
762 @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.\r
763 @retval Others A device error occurred while initializing the controller.\r
764\r
765**/\r
766EFI_STATUS\r
767NvmeControllerInit (\r
768 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
769 )\r
770{\r
771 EFI_STATUS Status;\r
772 EFI_PCI_IO_PROTOCOL *PciIo;\r
773 UINT64 Supports;\r
774 NVME_AQA Aqa;\r
775 NVME_ASQ Asq;\r
776 NVME_ACQ Acq;\r
777\r
778 //\r
779 // Save original PCI attributes and enable this controller.\r
780 //\r
781 PciIo = Private->PciIo;\r
782 Status = PciIo->Attributes (\r
783 PciIo,\r
784 EfiPciIoAttributeOperationGet,\r
785 0,\r
786 &Private->PciAttributes\r
787 );\r
788\r
789 if (EFI_ERROR (Status)) {\r
790 return Status;\r
791 }\r
792\r
793 Status = PciIo->Attributes (\r
794 PciIo,\r
795 EfiPciIoAttributeOperationSupported,\r
796 0,\r
797 &Supports\r
798 );\r
799\r
800 if (!EFI_ERROR (Status)) {\r
801 Supports &= EFI_PCI_DEVICE_ENABLE;\r
802 Status = PciIo->Attributes (\r
803 PciIo,\r
804 EfiPciIoAttributeOperationEnable,\r
805 Supports,\r
806 NULL\r
807 );\r
808 }\r
809\r
810 if (EFI_ERROR (Status)) {\r
811 DEBUG ((EFI_D_INFO, "NvmeControllerInit: failed to enable controller\n"));\r
812 return Status;\r
813 }\r
814\r
815 //\r
816 // Read the Controller Capabilities register and verify that the NVM command set is supported\r
817 //\r
818 Status = ReadNvmeControllerCapabilities (Private, &Private->Cap);\r
819 if (EFI_ERROR (Status)) {\r
820 return Status;\r
821 }\r
822\r
823 if (Private->Cap.Css != 0x01) {\r
824 DEBUG ((EFI_D_INFO, "NvmeControllerInit: the controller doesn't support NVMe command set\n"));\r
825 return EFI_UNSUPPORTED;\r
826 }\r
827\r
828 //\r
829 // Currently the driver only supports 4k page size.\r
830 //\r
831 ASSERT ((Private->Cap.Mpsmin + 12) <= EFI_PAGE_SHIFT);\r
832\r
833 Private->Cid[0] = 0;\r
834 Private->Cid[1] = 0;\r
835\r
836 Status = NvmeDisableController (Private);\r
837\r
838 if (EFI_ERROR(Status)) {\r
839 return Status;\r
840 }\r
841\r
842 //\r
843 // set number of entries admin submission & completion queues.\r
844 //\r
d45c8c30
FT
845 Aqa.Asqs = NVME_ASQ_SIZE;\r
846 Aqa.Rsvd1 = 0;\r
847 Aqa.Acqs = NVME_ACQ_SIZE;\r
848 Aqa.Rsvd2 = 0;\r
eb290d02
FT
849\r
850 //\r
851 // Address of admin submission queue.\r
852 //\r
853 Asq.Rsvd1 = 0;\r
854 Asq.Asqb = (UINT64)(UINTN)(Private->BufferPciAddr) >> 12;\r
855\r
856 //\r
857 // Address of admin completion queue.\r
858 //\r
859 Acq.Rsvd1 = 0;\r
860 Acq.Acqb = (UINT64)(UINTN)(Private->BufferPciAddr + EFI_PAGE_SIZE) >> 12;\r
861\r
862 //\r
863 // Address of I/O submission & completion queue.\r
864 //\r
865 Private->SqBuffer[0] = (NVME_SQ *)(UINTN)(Private->Buffer);\r
866 Private->SqBufferPciAddr[0] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr);\r
867 Private->CqBuffer[0] = (NVME_CQ *)(UINTN)(Private->Buffer + 1 * EFI_PAGE_SIZE);\r
868 Private->CqBufferPciAddr[0] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 1 * EFI_PAGE_SIZE);\r
869 Private->SqBuffer[1] = (NVME_SQ *)(UINTN)(Private->Buffer + 2 * EFI_PAGE_SIZE);\r
870 Private->SqBufferPciAddr[1] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 2 * EFI_PAGE_SIZE);\r
871 Private->CqBuffer[1] = (NVME_CQ *)(UINTN)(Private->Buffer + 3 * EFI_PAGE_SIZE);\r
872 Private->CqBufferPciAddr[1] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 3 * EFI_PAGE_SIZE);\r
873\r
874 DEBUG ((EFI_D_INFO, "Private->Buffer = [%016X]\n", (UINT64)(UINTN)Private->Buffer));\r
875 DEBUG ((EFI_D_INFO, "Admin Submission Queue size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));\r
876 DEBUG ((EFI_D_INFO, "Admin Completion Queue size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));\r
877 DEBUG ((EFI_D_INFO, "Admin Submission Queue (SqBuffer[0]) = [%016X]\n", Private->SqBuffer[0]));\r
878 DEBUG ((EFI_D_INFO, "Admin Completion Queue (CqBuffer[0]) = [%016X]\n", Private->CqBuffer[0]));\r
879 DEBUG ((EFI_D_INFO, "I/O Submission Queue (SqBuffer[1]) = [%016X]\n", Private->SqBuffer[1]));\r
880 DEBUG ((EFI_D_INFO, "I/O Completion Queue (CqBuffer[1]) = [%016X]\n", Private->CqBuffer[1]));\r
881\r
882 //\r
883 // Program admin queue attributes.\r
884 //\r
885 Status = WriteNvmeAdminQueueAttributes (Private, &Aqa);\r
886\r
887 if (EFI_ERROR(Status)) {\r
888 return Status;\r
889 }\r
890\r
891 //\r
892 // Program admin submission queue address.\r
893 //\r
894 Status = WriteNvmeAdminSubmissionQueueBaseAddress (Private, &Asq);\r
895\r
896 if (EFI_ERROR(Status)) {\r
897 return Status;\r
898 }\r
899\r
900 //\r
901 // Program admin completion queue address.\r
902 //\r
903 Status = WriteNvmeAdminCompletionQueueBaseAddress (Private, &Acq);\r
904\r
905 if (EFI_ERROR(Status)) {\r
906 return Status;\r
907 }\r
908\r
909 Status = NvmeEnableController (Private);\r
910 if (EFI_ERROR(Status)) {\r
911 return Status;\r
912 }\r
913\r
914 //\r
915 // Create one I/O completion queue.\r
916 //\r
917 Status = NvmeCreateIoCompletionQueue (Private);\r
918 if (EFI_ERROR(Status)) {\r
919 return Status;\r
920 }\r
921\r
922 //\r
923 // Create one I/O Submission queue.\r
924 //\r
925 Status = NvmeCreateIoSubmissionQueue (Private);\r
926 if (EFI_ERROR(Status)) {\r
927 return Status;\r
928 }\r
929\r
930 //\r
931 // Allocate buffer for Identify Controller data\r
932 //\r
933 Private->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)AllocateZeroPool (sizeof(NVME_ADMIN_CONTROLLER_DATA));\r
934\r
935 if (Private->ControllerData == NULL) {\r
936 return EFI_OUT_OF_RESOURCES;\r
937 }\r
938\r
939 //\r
940 // Get current Identify Controller Data\r
941 //\r
942 Status = NvmeIdentifyController (Private, Private->ControllerData);\r
943\r
944 if (EFI_ERROR(Status)) {\r
945 FreePool(Private->ControllerData);\r
946 Private->ControllerData = NULL;\r
947 return EFI_NOT_FOUND;\r
948 }\r
7b8883c6
FT
949\r
950 //\r
951 // Dump NvmExpress Identify Controller Data\r
952 //\r
953 Private->ControllerData->Sn[19] = 0;\r
954 Private->ControllerData->Mn[39] = 0;\r
955 DEBUG ((EFI_D_INFO, " == NVME IDENTIFY CONTROLLER DATA ==\n"));\r
956 DEBUG ((EFI_D_INFO, " PCI VID : 0x%x\n", Private->ControllerData->Vid));\r
957 DEBUG ((EFI_D_INFO, " PCI SSVID : 0x%x\n", Private->ControllerData->Ssvid));\r
958 DEBUG ((EFI_D_INFO, " SN : %a\n", (CHAR8 *)(Private->ControllerData->Sn)));\r
959 DEBUG ((EFI_D_INFO, " MN : %a\n", (CHAR8 *)(Private->ControllerData->Mn)));\r
960 DEBUG ((EFI_D_INFO, " FR : 0x%x\n", *((UINT64*)Private->ControllerData->Fr)));\r
961 DEBUG ((EFI_D_INFO, " RAB : 0x%x\n", Private->ControllerData->Rab));\r
962 DEBUG ((EFI_D_INFO, " IEEE : 0x%x\n", *(UINT32*)Private->ControllerData->Ieee_oiu));\r
963 DEBUG ((EFI_D_INFO, " AERL : 0x%x\n", Private->ControllerData->Aerl));\r
964 DEBUG ((EFI_D_INFO, " SQES : 0x%x\n", Private->ControllerData->Sqes));\r
965 DEBUG ((EFI_D_INFO, " CQES : 0x%x\n", Private->ControllerData->Cqes));\r
966 DEBUG ((EFI_D_INFO, " NN : 0x%x\n", Private->ControllerData->Nn));\r
967\r
eb290d02
FT
968 return Status;\r
969}\r
970\r