]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c
MdeModulePkg: Clean up source files
[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
d1102dba 5 Copyright (c) 2013 - 2018, 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
7111e46f
RN
18#define NVME_SHUTDOWN_PROCESS_TIMEOUT 45\r
19\r
20//\r
21// The number of NVME controllers managed by this driver, used by\r
22// NvmeRegisterShutdownNotification() and NvmeUnregisterShutdownNotification().\r
23//\r
24UINTN mNvmeControllerNumber = 0;\r
25\r
eb290d02
FT
26/**\r
27 Read Nvm Express controller capability register.\r
28\r
29 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
30 @param Cap The buffer used to store capability register content.\r
31\r
32 @return EFI_SUCCESS Successfully read the controller capability register content.\r
33 @return EFI_DEVICE_ERROR Fail to read the controller capability register.\r
34\r
35**/\r
36EFI_STATUS\r
37ReadNvmeControllerCapabilities (\r
38 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
39 IN NVME_CAP *Cap\r
40 )\r
41{\r
42 EFI_PCI_IO_PROTOCOL *PciIo;\r
43 EFI_STATUS Status;\r
7b8883c6 44 UINT64 Data;\r
eb290d02
FT
45\r
46 PciIo = Private->PciIo;\r
47 Status = PciIo->Mem.Read (\r
48 PciIo,\r
7b8883c6 49 EfiPciIoWidthUint32,\r
eb290d02
FT
50 NVME_BAR,\r
51 NVME_CAP_OFFSET,\r
7b8883c6
FT
52 2,\r
53 &Data\r
eb290d02
FT
54 );\r
55\r
56 if (EFI_ERROR(Status)) {\r
57 return Status;\r
58 }\r
59\r
7b8883c6 60 WriteUnaligned64 ((UINT64*)Cap, Data);\r
eb290d02
FT
61 return EFI_SUCCESS;\r
62}\r
63\r
64/**\r
65 Read Nvm Express controller configuration register.\r
66\r
67 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
68 @param Cc The buffer used to store configuration register content.\r
69\r
70 @return EFI_SUCCESS Successfully read the controller configuration register content.\r
71 @return EFI_DEVICE_ERROR Fail to read the controller configuration register.\r
72\r
73**/\r
74EFI_STATUS\r
75ReadNvmeControllerConfiguration (\r
76 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
77 IN NVME_CC *Cc\r
78 )\r
79{\r
80 EFI_PCI_IO_PROTOCOL *PciIo;\r
81 EFI_STATUS Status;\r
7b8883c6 82 UINT32 Data;\r
eb290d02
FT
83\r
84 PciIo = Private->PciIo;\r
85 Status = PciIo->Mem.Read (\r
86 PciIo,\r
87 EfiPciIoWidthUint32,\r
88 NVME_BAR,\r
89 NVME_CC_OFFSET,\r
90 1,\r
7b8883c6 91 &Data\r
eb290d02
FT
92 );\r
93\r
94 if (EFI_ERROR(Status)) {\r
95 return Status;\r
96 }\r
97\r
7b8883c6 98 WriteUnaligned32 ((UINT32*)Cc, Data);\r
eb290d02
FT
99 return EFI_SUCCESS;\r
100}\r
101\r
102/**\r
103 Write Nvm Express controller configuration register.\r
104\r
105 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
106 @param Cc The buffer used to store the content to be written into configuration register.\r
107\r
108 @return EFI_SUCCESS Successfully write data into the controller configuration register.\r
109 @return EFI_DEVICE_ERROR Fail to write data into the controller configuration register.\r
110\r
111**/\r
112EFI_STATUS\r
113WriteNvmeControllerConfiguration (\r
114 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
115 IN NVME_CC *Cc\r
116 )\r
117{\r
118 EFI_PCI_IO_PROTOCOL *PciIo;\r
119 EFI_STATUS Status;\r
7b8883c6 120 UINT32 Data;\r
eb290d02
FT
121\r
122 PciIo = Private->PciIo;\r
7b8883c6 123 Data = ReadUnaligned32 ((UINT32*)Cc);\r
eb290d02
FT
124 Status = PciIo->Mem.Write (\r
125 PciIo,\r
126 EfiPciIoWidthUint32,\r
127 NVME_BAR,\r
128 NVME_CC_OFFSET,\r
129 1,\r
7b8883c6 130 &Data\r
eb290d02
FT
131 );\r
132\r
133 if (EFI_ERROR(Status)) {\r
134 return Status;\r
135 }\r
136\r
137 DEBUG ((EFI_D_INFO, "Cc.En: %d\n", Cc->En));\r
138 DEBUG ((EFI_D_INFO, "Cc.Css: %d\n", Cc->Css));\r
139 DEBUG ((EFI_D_INFO, "Cc.Mps: %d\n", Cc->Mps));\r
140 DEBUG ((EFI_D_INFO, "Cc.Ams: %d\n", Cc->Ams));\r
141 DEBUG ((EFI_D_INFO, "Cc.Shn: %d\n", Cc->Shn));\r
142 DEBUG ((EFI_D_INFO, "Cc.Iosqes: %d\n", Cc->Iosqes));\r
143 DEBUG ((EFI_D_INFO, "Cc.Iocqes: %d\n", Cc->Iocqes));\r
144\r
145 return EFI_SUCCESS;\r
146}\r
147\r
148/**\r
149 Read Nvm Express controller status register.\r
150\r
151 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
152 @param Csts The buffer used to store status register content.\r
153\r
154 @return EFI_SUCCESS Successfully read the controller status register content.\r
155 @return EFI_DEVICE_ERROR Fail to read the controller status register.\r
156\r
157**/\r
158EFI_STATUS\r
159ReadNvmeControllerStatus (\r
160 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
161 IN NVME_CSTS *Csts\r
162 )\r
163{\r
164 EFI_PCI_IO_PROTOCOL *PciIo;\r
165 EFI_STATUS Status;\r
7b8883c6 166 UINT32 Data;\r
eb290d02
FT
167\r
168 PciIo = Private->PciIo;\r
169 Status = PciIo->Mem.Read (\r
170 PciIo,\r
171 EfiPciIoWidthUint32,\r
172 NVME_BAR,\r
173 NVME_CSTS_OFFSET,\r
174 1,\r
7b8883c6 175 &Data\r
eb290d02
FT
176 );\r
177\r
178 if (EFI_ERROR(Status)) {\r
179 return Status;\r
180 }\r
181\r
7b8883c6 182 WriteUnaligned32 ((UINT32*)Csts, Data);\r
eb290d02
FT
183 return EFI_SUCCESS;\r
184}\r
185\r
186/**\r
187 Read Nvm Express admin queue attributes register.\r
188\r
189 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
190 @param Aqa The buffer used to store admin queue attributes register content.\r
191\r
192 @return EFI_SUCCESS Successfully read the admin queue attributes register content.\r
193 @return EFI_DEVICE_ERROR Fail to read the admin queue attributes register.\r
194\r
195**/\r
196EFI_STATUS\r
197ReadNvmeAdminQueueAttributes (\r
198 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
199 IN NVME_AQA *Aqa\r
200 )\r
201{\r
202 EFI_PCI_IO_PROTOCOL *PciIo;\r
203 EFI_STATUS Status;\r
7b8883c6 204 UINT32 Data;\r
eb290d02
FT
205\r
206 PciIo = Private->PciIo;\r
207 Status = PciIo->Mem.Read (\r
208 PciIo,\r
209 EfiPciIoWidthUint32,\r
210 NVME_BAR,\r
211 NVME_AQA_OFFSET,\r
212 1,\r
7b8883c6 213 &Data\r
eb290d02
FT
214 );\r
215\r
216 if (EFI_ERROR(Status)) {\r
217 return Status;\r
218 }\r
219\r
7b8883c6 220 WriteUnaligned32 ((UINT32*)Aqa, Data);\r
eb290d02
FT
221 return EFI_SUCCESS;\r
222}\r
223\r
224/**\r
225 Write Nvm Express admin queue attributes register.\r
226\r
227 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
228 @param Aqa The buffer used to store the content to be written into admin queue attributes register.\r
229\r
230 @return EFI_SUCCESS Successfully write data into the admin queue attributes register.\r
231 @return EFI_DEVICE_ERROR Fail to write data into the admin queue attributes register.\r
232\r
233**/\r
234EFI_STATUS\r
235WriteNvmeAdminQueueAttributes (\r
236 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
237 IN NVME_AQA *Aqa\r
238 )\r
239{\r
240 EFI_PCI_IO_PROTOCOL *PciIo;\r
241 EFI_STATUS Status;\r
7b8883c6 242 UINT32 Data;\r
eb290d02
FT
243\r
244 PciIo = Private->PciIo;\r
7b8883c6 245 Data = ReadUnaligned32 ((UINT32*)Aqa);\r
eb290d02
FT
246 Status = PciIo->Mem.Write (\r
247 PciIo,\r
248 EfiPciIoWidthUint32,\r
249 NVME_BAR,\r
250 NVME_AQA_OFFSET,\r
251 1,\r
7b8883c6 252 &Data\r
eb290d02
FT
253 );\r
254\r
255 if (EFI_ERROR(Status)) {\r
256 return Status;\r
257 }\r
258\r
259 DEBUG ((EFI_D_INFO, "Aqa.Asqs: %d\n", Aqa->Asqs));\r
260 DEBUG ((EFI_D_INFO, "Aqa.Acqs: %d\n", Aqa->Acqs));\r
261\r
262 return EFI_SUCCESS;\r
263}\r
264\r
265/**\r
266 Read Nvm Express admin submission queue base address register.\r
267\r
268 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
269 @param Asq The buffer used to store admin submission queue base address register content.\r
270\r
271 @return EFI_SUCCESS Successfully read the admin submission queue base address register content.\r
272 @return EFI_DEVICE_ERROR Fail to read the admin submission queue base address register.\r
273\r
274**/\r
275EFI_STATUS\r
276ReadNvmeAdminSubmissionQueueBaseAddress (\r
277 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
278 IN NVME_ASQ *Asq\r
279 )\r
280{\r
281 EFI_PCI_IO_PROTOCOL *PciIo;\r
282 EFI_STATUS Status;\r
7b8883c6 283 UINT64 Data;\r
eb290d02
FT
284\r
285 PciIo = Private->PciIo;\r
286 Status = PciIo->Mem.Read (\r
287 PciIo,\r
7b8883c6 288 EfiPciIoWidthUint32,\r
eb290d02
FT
289 NVME_BAR,\r
290 NVME_ASQ_OFFSET,\r
7b8883c6
FT
291 2,\r
292 &Data\r
eb290d02
FT
293 );\r
294\r
295 if (EFI_ERROR(Status)) {\r
296 return Status;\r
297 }\r
298\r
7b8883c6 299 WriteUnaligned64 ((UINT64*)Asq, Data);\r
eb290d02
FT
300 return EFI_SUCCESS;\r
301}\r
302\r
303/**\r
304 Write Nvm Express admin submission queue base address register.\r
305\r
306 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
307 @param Asq The buffer used to store the content to be written into admin submission queue base address register.\r
308\r
309 @return EFI_SUCCESS Successfully write data into the admin submission queue base address register.\r
310 @return EFI_DEVICE_ERROR Fail to write data into the admin submission queue base address register.\r
311\r
312**/\r
313EFI_STATUS\r
314WriteNvmeAdminSubmissionQueueBaseAddress (\r
315 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
316 IN NVME_ASQ *Asq\r
317 )\r
318{\r
319 EFI_PCI_IO_PROTOCOL *PciIo;\r
320 EFI_STATUS Status;\r
7b8883c6 321 UINT64 Data;\r
eb290d02
FT
322\r
323 PciIo = Private->PciIo;\r
7b8883c6
FT
324 Data = ReadUnaligned64 ((UINT64*)Asq);\r
325\r
eb290d02
FT
326 Status = PciIo->Mem.Write (\r
327 PciIo,\r
7b8883c6 328 EfiPciIoWidthUint32,\r
eb290d02
FT
329 NVME_BAR,\r
330 NVME_ASQ_OFFSET,\r
7b8883c6
FT
331 2,\r
332 &Data\r
eb290d02
FT
333 );\r
334\r
335 if (EFI_ERROR(Status)) {\r
336 return Status;\r
337 }\r
338\r
c5921812 339 DEBUG ((EFI_D_INFO, "Asq: %lx\n", *Asq));\r
eb290d02
FT
340\r
341 return EFI_SUCCESS;\r
342}\r
343\r
344/**\r
345 Read Nvm Express admin completion queue base address register.\r
346\r
347 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
348 @param Acq The buffer used to store admin completion queue base address register content.\r
349\r
350 @return EFI_SUCCESS Successfully read the admin completion queue base address register content.\r
351 @return EFI_DEVICE_ERROR Fail to read the admin completion queue base address register.\r
352\r
353**/\r
354EFI_STATUS\r
355ReadNvmeAdminCompletionQueueBaseAddress (\r
356 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
357 IN NVME_ACQ *Acq\r
358 )\r
359{\r
360 EFI_PCI_IO_PROTOCOL *PciIo;\r
361 EFI_STATUS Status;\r
7b8883c6 362 UINT64 Data;\r
eb290d02
FT
363\r
364 PciIo = Private->PciIo;\r
7b8883c6 365\r
eb290d02
FT
366 Status = PciIo->Mem.Read (\r
367 PciIo,\r
7b8883c6 368 EfiPciIoWidthUint32,\r
eb290d02
FT
369 NVME_BAR,\r
370 NVME_ACQ_OFFSET,\r
7b8883c6
FT
371 2,\r
372 &Data\r
eb290d02
FT
373 );\r
374\r
375 if (EFI_ERROR(Status)) {\r
376 return Status;\r
377 }\r
378\r
7b8883c6 379 WriteUnaligned64 ((UINT64*)Acq, Data);\r
eb290d02
FT
380 return EFI_SUCCESS;\r
381}\r
382\r
383/**\r
384 Write Nvm Express admin completion queue base address register.\r
385\r
386 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
387 @param Acq The buffer used to store the content to be written into admin completion queue base address register.\r
388\r
389 @return EFI_SUCCESS Successfully write data into the admin completion queue base address register.\r
390 @return EFI_DEVICE_ERROR Fail to write data into the admin completion queue base address register.\r
391\r
392**/\r
393EFI_STATUS\r
394WriteNvmeAdminCompletionQueueBaseAddress (\r
395 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
396 IN NVME_ACQ *Acq\r
397 )\r
398{\r
399 EFI_PCI_IO_PROTOCOL *PciIo;\r
400 EFI_STATUS Status;\r
7b8883c6 401 UINT64 Data;\r
eb290d02
FT
402\r
403 PciIo = Private->PciIo;\r
7b8883c6
FT
404 Data = ReadUnaligned64 ((UINT64*)Acq);\r
405\r
eb290d02
FT
406 Status = PciIo->Mem.Write (\r
407 PciIo,\r
7b8883c6 408 EfiPciIoWidthUint32,\r
eb290d02
FT
409 NVME_BAR,\r
410 NVME_ACQ_OFFSET,\r
7b8883c6
FT
411 2,\r
412 &Data\r
eb290d02
FT
413 );\r
414\r
415 if (EFI_ERROR(Status)) {\r
416 return Status;\r
417 }\r
418\r
c5921812 419 DEBUG ((EFI_D_INFO, "Acq: %lxh\n", *Acq));\r
eb290d02
FT
420\r
421 return EFI_SUCCESS;\r
422}\r
423\r
424/**\r
425 Disable the Nvm Express controller.\r
426\r
427 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
428\r
429 @return EFI_SUCCESS Successfully disable the controller.\r
430 @return EFI_DEVICE_ERROR Fail to disable the controller.\r
431\r
432**/\r
433EFI_STATUS\r
434NvmeDisableController (\r
435 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
436 )\r
437{\r
438 NVME_CC Cc;\r
439 NVME_CSTS Csts;\r
440 EFI_STATUS Status;\r
4ab4497c
TF
441 UINT32 Index;\r
442 UINT8 Timeout;\r
eb290d02
FT
443\r
444 //\r
445 // Read Controller Configuration Register.\r
446 //\r
447 Status = ReadNvmeControllerConfiguration (Private, &Cc);\r
448 if (EFI_ERROR(Status)) {\r
449 return Status;\r
450 }\r
451\r
452 Cc.En = 0;\r
453\r
454 //\r
455 // Disable the controller.\r
456 //\r
457 Status = WriteNvmeControllerConfiguration (Private, &Cc);\r
458\r
459 if (EFI_ERROR(Status)) {\r
460 return Status;\r
461 }\r
462\r
eb290d02 463 //\r
4ab4497c
TF
464 // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to transition from 1 to 0 after\r
465 // Cc.Enable transition from 1 to 0. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.\r
eb290d02 466 //\r
4ab4497c
TF
467 if (Private->Cap.To == 0) {\r
468 Timeout = 1;\r
469 } else {\r
470 Timeout = Private->Cap.To;\r
471 }\r
eb290d02 472\r
4ab4497c
TF
473 for(Index = (Timeout * 500); Index != 0; --Index) {\r
474 gBS->Stall(1000);\r
475\r
476 //\r
477 // Check if the controller is initialized\r
478 //\r
479 Status = ReadNvmeControllerStatus (Private, &Csts);\r
480\r
481 if (EFI_ERROR(Status)) {\r
482 return Status;\r
483 }\r
484\r
485 if (Csts.Rdy == 0) {\r
486 break;\r
487 }\r
eb290d02
FT
488 }\r
489\r
4ab4497c
TF
490 if (Index == 0) {\r
491 Status = EFI_DEVICE_ERROR;\r
eb290d02
FT
492 }\r
493\r
494 DEBUG ((EFI_D_INFO, "NVMe controller is disabled with status [%r].\n", Status));\r
495 return Status;\r
496}\r
497\r
498/**\r
499 Enable the Nvm Express controller.\r
500\r
501 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
502\r
503 @return EFI_SUCCESS Successfully enable the controller.\r
504 @return EFI_DEVICE_ERROR Fail to enable the controller.\r
505 @return EFI_TIMEOUT Fail to enable the controller in given time slot.\r
506\r
507**/\r
508EFI_STATUS\r
509NvmeEnableController (\r
510 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
511 )\r
512{\r
513 NVME_CC Cc;\r
514 NVME_CSTS Csts;\r
515 EFI_STATUS Status;\r
516 UINT32 Index;\r
517 UINT8 Timeout;\r
518\r
519 //\r
d6c55989
FT
520 // Enable the controller.\r
521 // CC.AMS, CC.MPS and CC.CSS are all set to 0.\r
eb290d02
FT
522 //\r
523 ZeroMem (&Cc, sizeof (NVME_CC));\r
166801d2
FT
524 Cc.En = 1;\r
525 Cc.Iosqes = 6;\r
526 Cc.Iocqes = 4;\r
eb290d02 527\r
166801d2 528 Status = WriteNvmeControllerConfiguration (Private, &Cc);\r
eb290d02
FT
529 if (EFI_ERROR(Status)) {\r
530 return Status;\r
531 }\r
532\r
533 //\r
534 // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after\r
535 // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.\r
536 //\r
537 if (Private->Cap.To == 0) {\r
538 Timeout = 1;\r
539 } else {\r
540 Timeout = Private->Cap.To;\r
541 }\r
542\r
543 for(Index = (Timeout * 500); Index != 0; --Index) {\r
544 gBS->Stall(1000);\r
545\r
546 //\r
547 // Check if the controller is initialized\r
548 //\r
549 Status = ReadNvmeControllerStatus (Private, &Csts);\r
550\r
551 if (EFI_ERROR(Status)) {\r
552 return Status;\r
553 }\r
554\r
555 if (Csts.Rdy) {\r
556 break;\r
557 }\r
558 }\r
559\r
560 if (Index == 0) {\r
561 Status = EFI_TIMEOUT;\r
562 }\r
563\r
564 DEBUG ((EFI_D_INFO, "NVMe controller is enabled with status [%r].\n", Status));\r
565 return Status;\r
566}\r
567\r
568/**\r
569 Get identify controller data.\r
570\r
571 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
572 @param Buffer The buffer used to store the identify controller data.\r
573\r
574 @return EFI_SUCCESS Successfully get the identify controller data.\r
575 @return EFI_DEVICE_ERROR Fail to get the identify controller data.\r
576\r
577**/\r
578EFI_STATUS\r
579NvmeIdentifyController (\r
580 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
581 IN VOID *Buffer\r
582 )\r
583{\r
d6c55989
FT
584 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
585 EFI_NVM_EXPRESS_COMMAND Command;\r
586 EFI_NVM_EXPRESS_COMPLETION Completion;\r
eb290d02
FT
587 EFI_STATUS Status;\r
588\r
d6c55989
FT
589 ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
590 ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));\r
591 ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));\r
eb290d02 592\r
754b489b 593 Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;\r
eb290d02
FT
594 //\r
595 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.\r
596 // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.\r
597 //\r
598 Command.Nsid = 0;\r
599\r
600 CommandPacket.NvmeCmd = &Command;\r
d6c55989 601 CommandPacket.NvmeCompletion = &Completion;\r
eb290d02
FT
602 CommandPacket.TransferBuffer = Buffer;\r
603 CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA);\r
604 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
d6c55989 605 CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
eb290d02
FT
606 //\r
607 // Set bit 0 (Cns bit) to 1 to identify a controller\r
608 //\r
609 Command.Cdw10 = 1;\r
610 Command.Flags = CDW10_VALID;\r
611\r
612 Status = Private->Passthru.PassThru (\r
613 &Private->Passthru,\r
614 NVME_CONTROLLER_ID,\r
eb290d02
FT
615 &CommandPacket,\r
616 NULL\r
617 );\r
618\r
619 return Status;\r
620}\r
621\r
622/**\r
623 Get specified identify namespace data.\r
624\r
625 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
626 @param NamespaceId The specified namespace identifier.\r
627 @param Buffer The buffer used to store the identify namespace data.\r
628\r
629 @return EFI_SUCCESS Successfully get the identify namespace data.\r
630 @return EFI_DEVICE_ERROR Fail to get the identify namespace data.\r
631\r
632**/\r
633EFI_STATUS\r
634NvmeIdentifyNamespace (\r
635 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
636 IN UINT32 NamespaceId,\r
637 IN VOID *Buffer\r
638 )\r
639{\r
d6c55989
FT
640 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
641 EFI_NVM_EXPRESS_COMMAND Command;\r
642 EFI_NVM_EXPRESS_COMPLETION Completion;\r
eb290d02
FT
643 EFI_STATUS Status;\r
644\r
d6c55989
FT
645 ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
646 ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));\r
647 ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));\r
eb290d02 648\r
d6c55989
FT
649 CommandPacket.NvmeCmd = &Command;\r
650 CommandPacket.NvmeCompletion = &Completion;\r
eb290d02 651\r
754b489b 652 Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;\r
eb290d02
FT
653 Command.Nsid = NamespaceId;\r
654 CommandPacket.TransferBuffer = Buffer;\r
655 CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA);\r
656 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
d6c55989 657 CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
eb290d02
FT
658 //\r
659 // Set bit 0 (Cns bit) to 1 to identify a namespace\r
660 //\r
661 CommandPacket.NvmeCmd->Cdw10 = 0;\r
662 CommandPacket.NvmeCmd->Flags = CDW10_VALID;\r
663\r
664 Status = Private->Passthru.PassThru (\r
665 &Private->Passthru,\r
666 NamespaceId,\r
eb290d02
FT
667 &CommandPacket,\r
668 NULL\r
669 );\r
670\r
671 return Status;\r
672}\r
673\r
674/**\r
675 Create io completion queue.\r
676\r
677 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
678\r
679 @return EFI_SUCCESS Successfully create io completion queue.\r
680 @return EFI_DEVICE_ERROR Fail to create io completion queue.\r
681\r
682**/\r
683EFI_STATUS\r
684NvmeCreateIoCompletionQueue (\r
685 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
686 )\r
687{\r
d6c55989
FT
688 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
689 EFI_NVM_EXPRESS_COMMAND Command;\r
690 EFI_NVM_EXPRESS_COMPLETION Completion;\r
eb290d02
FT
691 EFI_STATUS Status;\r
692 NVME_ADMIN_CRIOCQ CrIoCq;\r
758ea946 693 UINT32 Index;\r
05bf4747 694 UINT16 QueueSize;\r
758ea946 695\r
6b571c4d
HW
696 Status = EFI_SUCCESS;\r
697\r
758ea946
HW
698 for (Index = 1; Index < NVME_MAX_QUEUES; Index++) {\r
699 ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
700 ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));\r
701 ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));\r
702 ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));\r
703\r
704 CommandPacket.NvmeCmd = &Command;\r
705 CommandPacket.NvmeCompletion = &Completion;\r
706\r
707 Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_CMD;\r
708 CommandPacket.TransferBuffer = Private->CqBufferPciAddr[Index];\r
709 CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
710 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
711 CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
712\r
05bf4747
HW
713 if (Index == 1) {\r
714 QueueSize = NVME_CCQ_SIZE;\r
715 } else {\r
716 if (Private->Cap.Mqes > NVME_ASYNC_CCQ_SIZE) {\r
717 QueueSize = NVME_ASYNC_CCQ_SIZE;\r
718 } else {\r
719 QueueSize = Private->Cap.Mqes;\r
720 }\r
721 }\r
722\r
758ea946 723 CrIoCq.Qid = Index;\r
05bf4747 724 CrIoCq.Qsize = QueueSize;\r
758ea946
HW
725 CrIoCq.Pc = 1;\r
726 CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));\r
727 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
728\r
729 Status = Private->Passthru.PassThru (\r
730 &Private->Passthru,\r
731 0,\r
732 &CommandPacket,\r
733 NULL\r
734 );\r
735 if (EFI_ERROR (Status)) {\r
736 break;\r
737 }\r
738 }\r
eb290d02
FT
739\r
740 return Status;\r
741}\r
742\r
743/**\r
744 Create io submission queue.\r
745\r
746 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
747\r
748 @return EFI_SUCCESS Successfully create io submission queue.\r
749 @return EFI_DEVICE_ERROR Fail to create io submission queue.\r
750\r
751**/\r
752EFI_STATUS\r
753NvmeCreateIoSubmissionQueue (\r
754 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
755 )\r
756{\r
d6c55989
FT
757 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
758 EFI_NVM_EXPRESS_COMMAND Command;\r
759 EFI_NVM_EXPRESS_COMPLETION Completion;\r
eb290d02
FT
760 EFI_STATUS Status;\r
761 NVME_ADMIN_CRIOSQ CrIoSq;\r
758ea946 762 UINT32 Index;\r
05bf4747 763 UINT16 QueueSize;\r
758ea946 764\r
6b571c4d
HW
765 Status = EFI_SUCCESS;\r
766\r
758ea946
HW
767 for (Index = 1; Index < NVME_MAX_QUEUES; Index++) {\r
768 ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
769 ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));\r
770 ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));\r
771 ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));\r
772\r
773 CommandPacket.NvmeCmd = &Command;\r
774 CommandPacket.NvmeCompletion = &Completion;\r
775\r
776 Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_CMD;\r
777 CommandPacket.TransferBuffer = Private->SqBufferPciAddr[Index];\r
778 CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
779 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
780 CommandPacket.QueueType = NVME_ADMIN_QUEUE;\r
781\r
05bf4747
HW
782 if (Index == 1) {\r
783 QueueSize = NVME_CSQ_SIZE;\r
784 } else {\r
785 if (Private->Cap.Mqes > NVME_ASYNC_CSQ_SIZE) {\r
786 QueueSize = NVME_ASYNC_CSQ_SIZE;\r
787 } else {\r
788 QueueSize = Private->Cap.Mqes;\r
789 }\r
790 }\r
791\r
758ea946 792 CrIoSq.Qid = Index;\r
05bf4747 793 CrIoSq.Qsize = QueueSize;\r
758ea946
HW
794 CrIoSq.Pc = 1;\r
795 CrIoSq.Cqid = Index;\r
796 CrIoSq.Qprio = 0;\r
797 CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));\r
798 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
799\r
800 Status = Private->Passthru.PassThru (\r
801 &Private->Passthru,\r
802 0,\r
803 &CommandPacket,\r
804 NULL\r
805 );\r
806 if (EFI_ERROR (Status)) {\r
807 break;\r
808 }\r
809 }\r
eb290d02
FT
810\r
811 return Status;\r
812}\r
813\r
814/**\r
815 Initialize the Nvm Express controller.\r
816\r
817 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
818\r
819 @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.\r
820 @retval Others A device error occurred while initializing the controller.\r
821\r
822**/\r
823EFI_STATUS\r
824NvmeControllerInit (\r
825 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
826 )\r
827{\r
828 EFI_STATUS Status;\r
829 EFI_PCI_IO_PROTOCOL *PciIo;\r
830 UINT64 Supports;\r
831 NVME_AQA Aqa;\r
832 NVME_ASQ Asq;\r
833 NVME_ACQ Acq;\r
da7c7274
FT
834 UINT8 Sn[21];\r
835 UINT8 Mn[41];\r
eb290d02
FT
836 //\r
837 // Save original PCI attributes and enable this controller.\r
838 //\r
839 PciIo = Private->PciIo;\r
840 Status = PciIo->Attributes (\r
841 PciIo,\r
842 EfiPciIoAttributeOperationGet,\r
843 0,\r
844 &Private->PciAttributes\r
845 );\r
846\r
847 if (EFI_ERROR (Status)) {\r
848 return Status;\r
849 }\r
850\r
851 Status = PciIo->Attributes (\r
852 PciIo,\r
853 EfiPciIoAttributeOperationSupported,\r
854 0,\r
855 &Supports\r
856 );\r
857\r
858 if (!EFI_ERROR (Status)) {\r
6e1e5405 859 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
eb290d02
FT
860 Status = PciIo->Attributes (\r
861 PciIo,\r
862 EfiPciIoAttributeOperationEnable,\r
863 Supports,\r
864 NULL\r
865 );\r
866 }\r
867\r
868 if (EFI_ERROR (Status)) {\r
869 DEBUG ((EFI_D_INFO, "NvmeControllerInit: failed to enable controller\n"));\r
870 return Status;\r
871 }\r
872\r
4e28ea2c
AB
873 //\r
874 // Enable 64-bit DMA support in the PCI layer.\r
875 //\r
876 Status = PciIo->Attributes (\r
877 PciIo,\r
878 EfiPciIoAttributeOperationEnable,\r
879 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
880 NULL\r
881 );\r
882 if (EFI_ERROR (Status)) {\r
883 DEBUG ((EFI_D_WARN, "NvmeControllerInit: failed to enable 64-bit DMA (%r)\n", Status));\r
884 }\r
885\r
eb290d02
FT
886 //\r
887 // Read the Controller Capabilities register and verify that the NVM command set is supported\r
888 //\r
889 Status = ReadNvmeControllerCapabilities (Private, &Private->Cap);\r
890 if (EFI_ERROR (Status)) {\r
891 return Status;\r
892 }\r
893\r
894 if (Private->Cap.Css != 0x01) {\r
895 DEBUG ((EFI_D_INFO, "NvmeControllerInit: the controller doesn't support NVMe command set\n"));\r
896 return EFI_UNSUPPORTED;\r
897 }\r
898\r
899 //\r
900 // Currently the driver only supports 4k page size.\r
901 //\r
902 ASSERT ((Private->Cap.Mpsmin + 12) <= EFI_PAGE_SHIFT);\r
903\r
904 Private->Cid[0] = 0;\r
905 Private->Cid[1] = 0;\r
758ea946 906 Private->Cid[2] = 0;\r
6523ae8b
TF
907 Private->Pt[0] = 0;\r
908 Private->Pt[1] = 0;\r
758ea946 909 Private->Pt[2] = 0;\r
6523ae8b
TF
910 Private->SqTdbl[0].Sqt = 0;\r
911 Private->SqTdbl[1].Sqt = 0;\r
758ea946 912 Private->SqTdbl[2].Sqt = 0;\r
6523ae8b
TF
913 Private->CqHdbl[0].Cqh = 0;\r
914 Private->CqHdbl[1].Cqh = 0;\r
758ea946
HW
915 Private->CqHdbl[2].Cqh = 0;\r
916 Private->AsyncSqHead = 0;\r
eb290d02
FT
917\r
918 Status = NvmeDisableController (Private);\r
919\r
920 if (EFI_ERROR(Status)) {\r
921 return Status;\r
922 }\r
923\r
924 //\r
925 // set number of entries admin submission & completion queues.\r
926 //\r
d45c8c30
FT
927 Aqa.Asqs = NVME_ASQ_SIZE;\r
928 Aqa.Rsvd1 = 0;\r
929 Aqa.Acqs = NVME_ACQ_SIZE;\r
930 Aqa.Rsvd2 = 0;\r
eb290d02
FT
931\r
932 //\r
933 // Address of admin submission queue.\r
934 //\r
c5921812 935 Asq = (UINT64)(UINTN)(Private->BufferPciAddr) & ~0xFFF;\r
eb290d02
FT
936\r
937 //\r
938 // Address of admin completion queue.\r
939 //\r
c5921812 940 Acq = (UINT64)(UINTN)(Private->BufferPciAddr + EFI_PAGE_SIZE) & ~0xFFF;\r
eb290d02
FT
941\r
942 //\r
943 // Address of I/O submission & completion queue.\r
944 //\r
758ea946 945 ZeroMem (Private->Buffer, EFI_PAGES_TO_SIZE (6));\r
eb290d02
FT
946 Private->SqBuffer[0] = (NVME_SQ *)(UINTN)(Private->Buffer);\r
947 Private->SqBufferPciAddr[0] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr);\r
948 Private->CqBuffer[0] = (NVME_CQ *)(UINTN)(Private->Buffer + 1 * EFI_PAGE_SIZE);\r
949 Private->CqBufferPciAddr[0] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 1 * EFI_PAGE_SIZE);\r
950 Private->SqBuffer[1] = (NVME_SQ *)(UINTN)(Private->Buffer + 2 * EFI_PAGE_SIZE);\r
951 Private->SqBufferPciAddr[1] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 2 * EFI_PAGE_SIZE);\r
952 Private->CqBuffer[1] = (NVME_CQ *)(UINTN)(Private->Buffer + 3 * EFI_PAGE_SIZE);\r
953 Private->CqBufferPciAddr[1] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 3 * EFI_PAGE_SIZE);\r
758ea946
HW
954 Private->SqBuffer[2] = (NVME_SQ *)(UINTN)(Private->Buffer + 4 * EFI_PAGE_SIZE);\r
955 Private->SqBufferPciAddr[2] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 4 * EFI_PAGE_SIZE);\r
956 Private->CqBuffer[2] = (NVME_CQ *)(UINTN)(Private->Buffer + 5 * EFI_PAGE_SIZE);\r
957 Private->CqBufferPciAddr[2] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 5 * EFI_PAGE_SIZE);\r
eb290d02
FT
958\r
959 DEBUG ((EFI_D_INFO, "Private->Buffer = [%016X]\n", (UINT64)(UINTN)Private->Buffer));\r
758ea946
HW
960 DEBUG ((EFI_D_INFO, "Admin Submission Queue size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));\r
961 DEBUG ((EFI_D_INFO, "Admin Completion Queue size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));\r
962 DEBUG ((EFI_D_INFO, "Admin Submission Queue (SqBuffer[0]) = [%016X]\n", Private->SqBuffer[0]));\r
963 DEBUG ((EFI_D_INFO, "Admin Completion Queue (CqBuffer[0]) = [%016X]\n", Private->CqBuffer[0]));\r
964 DEBUG ((EFI_D_INFO, "Sync I/O Submission Queue (SqBuffer[1]) = [%016X]\n", Private->SqBuffer[1]));\r
965 DEBUG ((EFI_D_INFO, "Sync I/O Completion Queue (CqBuffer[1]) = [%016X]\n", Private->CqBuffer[1]));\r
966 DEBUG ((EFI_D_INFO, "Async I/O Submission Queue (SqBuffer[2]) = [%016X]\n", Private->SqBuffer[2]));\r
967 DEBUG ((EFI_D_INFO, "Async I/O Completion Queue (CqBuffer[2]) = [%016X]\n", Private->CqBuffer[2]));\r
eb290d02
FT
968\r
969 //\r
970 // Program admin queue attributes.\r
971 //\r
972 Status = WriteNvmeAdminQueueAttributes (Private, &Aqa);\r
973\r
974 if (EFI_ERROR(Status)) {\r
975 return Status;\r
976 }\r
977\r
978 //\r
979 // Program admin submission queue address.\r
980 //\r
981 Status = WriteNvmeAdminSubmissionQueueBaseAddress (Private, &Asq);\r
982\r
983 if (EFI_ERROR(Status)) {\r
984 return Status;\r
985 }\r
986\r
987 //\r
988 // Program admin completion queue address.\r
989 //\r
990 Status = WriteNvmeAdminCompletionQueueBaseAddress (Private, &Acq);\r
991\r
992 if (EFI_ERROR(Status)) {\r
993 return Status;\r
994 }\r
995\r
996 Status = NvmeEnableController (Private);\r
997 if (EFI_ERROR(Status)) {\r
998 return Status;\r
999 }\r
1000\r
eb290d02
FT
1001 //\r
1002 // Allocate buffer for Identify Controller data\r
1003 //\r
eb290d02 1004 if (Private->ControllerData == NULL) {\r
6523ae8b 1005 Private->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)AllocateZeroPool (sizeof(NVME_ADMIN_CONTROLLER_DATA));\r
d1102dba 1006\r
6523ae8b
TF
1007 if (Private->ControllerData == NULL) {\r
1008 return EFI_OUT_OF_RESOURCES;\r
1009 }\r
eb290d02
FT
1010 }\r
1011\r
1012 //\r
1013 // Get current Identify Controller Data\r
1014 //\r
1015 Status = NvmeIdentifyController (Private, Private->ControllerData);\r
1016\r
1017 if (EFI_ERROR(Status)) {\r
1018 FreePool(Private->ControllerData);\r
1019 Private->ControllerData = NULL;\r
1020 return EFI_NOT_FOUND;\r
1021 }\r
7b8883c6
FT
1022\r
1023 //\r
1024 // Dump NvmExpress Identify Controller Data\r
1025 //\r
da7c7274
FT
1026 CopyMem (Sn, Private->ControllerData->Sn, sizeof (Private->ControllerData->Sn));\r
1027 Sn[20] = 0;\r
1028 CopyMem (Mn, Private->ControllerData->Mn, sizeof (Private->ControllerData->Mn));\r
1029 Mn[40] = 0;\r
7b8883c6
FT
1030 DEBUG ((EFI_D_INFO, " == NVME IDENTIFY CONTROLLER DATA ==\n"));\r
1031 DEBUG ((EFI_D_INFO, " PCI VID : 0x%x\n", Private->ControllerData->Vid));\r
1032 DEBUG ((EFI_D_INFO, " PCI SSVID : 0x%x\n", Private->ControllerData->Ssvid));\r
da7c7274
FT
1033 DEBUG ((EFI_D_INFO, " SN : %a\n", Sn));\r
1034 DEBUG ((EFI_D_INFO, " MN : %a\n", Mn));\r
7b8883c6
FT
1035 DEBUG ((EFI_D_INFO, " FR : 0x%x\n", *((UINT64*)Private->ControllerData->Fr)));\r
1036 DEBUG ((EFI_D_INFO, " RAB : 0x%x\n", Private->ControllerData->Rab));\r
4ab4497c 1037 DEBUG ((EFI_D_INFO, " IEEE : 0x%x\n", *(UINT32*)Private->ControllerData->Ieee_oui));\r
7b8883c6
FT
1038 DEBUG ((EFI_D_INFO, " AERL : 0x%x\n", Private->ControllerData->Aerl));\r
1039 DEBUG ((EFI_D_INFO, " SQES : 0x%x\n", Private->ControllerData->Sqes));\r
1040 DEBUG ((EFI_D_INFO, " CQES : 0x%x\n", Private->ControllerData->Cqes));\r
1041 DEBUG ((EFI_D_INFO, " NN : 0x%x\n", Private->ControllerData->Nn));\r
1042\r
d6c55989 1043 //\r
758ea946
HW
1044 // Create two I/O completion queues.\r
1045 // One for blocking I/O, one for non-blocking I/O.\r
d6c55989
FT
1046 //\r
1047 Status = NvmeCreateIoCompletionQueue (Private);\r
1048 if (EFI_ERROR(Status)) {\r
1049 return Status;\r
1050 }\r
1051\r
1052 //\r
758ea946
HW
1053 // Create two I/O Submission queues.\r
1054 // One for blocking I/O, one for non-blocking I/O.\r
d6c55989
FT
1055 //\r
1056 Status = NvmeCreateIoSubmissionQueue (Private);\r
d6c55989 1057\r
eb290d02
FT
1058 return Status;\r
1059}\r
1060\r
7111e46f
RN
1061/**\r
1062 This routine is called to properly shutdown the Nvm Express controller per NVMe spec.\r
1063\r
1064 @param[in] ResetType The type of reset to perform.\r
1065 @param[in] ResetStatus The status code for the reset.\r
1066 @param[in] DataSize The size, in bytes, of ResetData.\r
1067 @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or\r
1068 EfiResetShutdown the data buffer starts with a Null-terminated\r
1069 string, optionally followed by additional binary data.\r
1070 The string is a description that the caller may use to further\r
1071 indicate the reason for the system reset. ResetData is only\r
1072 valid if ResetStatus is something other than EFI_SUCCESS\r
1073 unless the ResetType is EfiResetPlatformSpecific\r
1074 where a minimum amount of ResetData is always required.\r
1075 For a ResetType of EfiResetPlatformSpecific the data buffer\r
1076 also starts with a Null-terminated string that is followed\r
1077 by an EFI_GUID that describes the specific type of reset to perform.\r
1078**/\r
1079VOID\r
1080EFIAPI\r
1081NvmeShutdownAllControllers (\r
1082 IN EFI_RESET_TYPE ResetType,\r
1083 IN EFI_STATUS ResetStatus,\r
1084 IN UINTN DataSize,\r
1085 IN VOID *ResetData OPTIONAL\r
1086 )\r
1087{\r
1088 EFI_STATUS Status;\r
1089 EFI_HANDLE *Handles;\r
1090 UINTN HandleCount;\r
1091 UINTN HandleIndex;\r
1092 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfos;\r
1093 UINTN OpenInfoCount;\r
1094 UINTN OpenInfoIndex;\r
1095 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmePassThru;\r
1096 NVME_CC Cc;\r
1097 NVME_CSTS Csts;\r
1098 UINTN Index;\r
1099 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
1100\r
1101 Status = gBS->LocateHandleBuffer (\r
1102 ByProtocol,\r
1103 &gEfiPciIoProtocolGuid,\r
1104 NULL,\r
1105 &HandleCount,\r
1106 &Handles\r
1107 );\r
1108 if (EFI_ERROR (Status)) {\r
1109 HandleCount = 0;\r
1110 }\r
1111\r
1112 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
1113 Status = gBS->OpenProtocolInformation (\r
1114 Handles[HandleIndex],\r
1115 &gEfiPciIoProtocolGuid,\r
1116 &OpenInfos,\r
1117 &OpenInfoCount\r
1118 );\r
1119 if (EFI_ERROR (Status)) {\r
1120 continue;\r
1121 }\r
1122\r
1123 for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {\r
1124 //\r
1125 // Find all the NVME controller managed by this driver.\r
1126 // gImageHandle equals to DriverBinding handle for this driver.\r
1127 //\r
1128 if (((OpenInfos[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) &&\r
1129 (OpenInfos[OpenInfoIndex].AgentHandle == gImageHandle)) {\r
1130 Status = gBS->OpenProtocol (\r
1131 OpenInfos[OpenInfoIndex].ControllerHandle,\r
1132 &gEfiNvmExpressPassThruProtocolGuid,\r
1133 (VOID **) &NvmePassThru,\r
1134 NULL,\r
1135 NULL,\r
1136 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1137 );\r
1138 if (EFI_ERROR (Status)) {\r
1139 continue;\r
1140 }\r
1141 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (NvmePassThru);\r
1142\r
1143 //\r
1144 // Read Controller Configuration Register.\r
1145 //\r
1146 Status = ReadNvmeControllerConfiguration (Private, &Cc);\r
1147 if (EFI_ERROR(Status)) {\r
1148 continue;\r
1149 }\r
1150 //\r
1151 // The host should set the Shutdown Notification (CC.SHN) field to 01b\r
1152 // to indicate a normal shutdown operation.\r
1153 //\r
1154 Cc.Shn = NVME_CC_SHN_NORMAL_SHUTDOWN;\r
1155 Status = WriteNvmeControllerConfiguration (Private, &Cc);\r
1156 if (EFI_ERROR(Status)) {\r
1157 continue;\r
1158 }\r
1159\r
1160 //\r
1161 // The controller indicates when shutdown processing is completed by updating the\r
1162 // Shutdown Status (CSTS.SHST) field to 10b.\r
1163 // Wait up to 45 seconds (break down to 4500 x 10ms) for the shutdown to complete.\r
1164 //\r
1165 for (Index = 0; Index < NVME_SHUTDOWN_PROCESS_TIMEOUT * 100; Index++) {\r
1166 Status = ReadNvmeControllerStatus (Private, &Csts);\r
1167 if (!EFI_ERROR(Status) && (Csts.Shst == NVME_CSTS_SHST_SHUTDOWN_COMPLETED)) {\r
1168 DEBUG((DEBUG_INFO, "NvmeShutdownController: shutdown processing is completed after %dms.\n", Index * 10));\r
1169 break;\r
1170 }\r
1171 //\r
1172 // Stall for 10ms\r
1173 //\r
1174 gBS->Stall (10 * 1000);\r
1175 }\r
1176\r
1177 if (Index == NVME_SHUTDOWN_PROCESS_TIMEOUT * 100) {\r
1178 DEBUG((DEBUG_ERROR, "NvmeShutdownController: shutdown processing is timed out\n"));\r
1179 }\r
1180 }\r
1181 }\r
1182 }\r
1183}\r
1184\r
1185/**\r
1186 Register the shutdown notification through the ResetNotification protocol.\r
1187\r
1188 Register the shutdown notification when mNvmeControllerNumber increased from 0 to 1.\r
1189**/\r
1190VOID\r
1191NvmeRegisterShutdownNotification (\r
1192 VOID\r
1193 )\r
1194{\r
1195 EFI_STATUS Status;\r
1196 EFI_RESET_NOTIFICATION_PROTOCOL *ResetNotify;\r
1197\r
1198 mNvmeControllerNumber++;\r
1199 if (mNvmeControllerNumber == 1) {\r
1200 Status = gBS->LocateProtocol (&gEfiResetNotificationProtocolGuid, NULL, (VOID **) &ResetNotify);\r
1201 if (!EFI_ERROR (Status)) {\r
1202 Status = ResetNotify->RegisterResetNotify (ResetNotify, NvmeShutdownAllControllers);\r
1203 ASSERT_EFI_ERROR (Status);\r
1204 } else {\r
1205 DEBUG ((DEBUG_WARN, "NVME: ResetNotification absent! Shutdown notification cannot be performed!\n"));\r
1206 }\r
1207 }\r
1208}\r
1209\r
1210/**\r
1211 Unregister the shutdown notification through the ResetNotification protocol.\r
1212\r
1213 Unregister the shutdown notification when mNvmeControllerNumber decreased from 1 to 0.\r
1214**/\r
1215VOID\r
1216NvmeUnregisterShutdownNotification (\r
1217 VOID\r
1218 )\r
1219{\r
1220 EFI_STATUS Status;\r
1221 EFI_RESET_NOTIFICATION_PROTOCOL *ResetNotify;\r
1222\r
1223 mNvmeControllerNumber--;\r
1224 if (mNvmeControllerNumber == 0) {\r
1225 Status = gBS->LocateProtocol (&gEfiResetNotificationProtocolGuid, NULL, (VOID **) &ResetNotify);\r
1226 if (!EFI_ERROR (Status)) {\r
1227 Status = ResetNotify->UnregisterResetNotify (ResetNotify, NvmeShutdownAllControllers);\r
1228 ASSERT_EFI_ERROR (Status);\r
1229 }\r
1230 }\r
1231}\r