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