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