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