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