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