]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c
MdeModulePkg/NvmExpressDxe: fix check for Cap.Css
[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 730 //\r
b1b89f90 731 // Enable this controller.\r
eb290d02
FT
732 //\r
733 PciIo = Private->PciIo;\r
eb290d02
FT
734 Status = PciIo->Attributes (\r
735 PciIo,\r
736 EfiPciIoAttributeOperationSupported,\r
737 0,\r
738 &Supports\r
739 );\r
740\r
741 if (!EFI_ERROR (Status)) {\r
6e1e5405 742 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
eb290d02
FT
743 Status = PciIo->Attributes (\r
744 PciIo,\r
745 EfiPciIoAttributeOperationEnable,\r
746 Supports,\r
747 NULL\r
748 );\r
749 }\r
750\r
751 if (EFI_ERROR (Status)) {\r
87000d77 752 DEBUG ((DEBUG_INFO, "NvmeControllerInit: failed to enable controller\n"));\r
eb290d02
FT
753 return Status;\r
754 }\r
755\r
756 //\r
757 // Read the Controller Capabilities register and verify that the NVM command set is supported\r
758 //\r
759 Status = ReadNvmeControllerCapabilities (Private, &Private->Cap);\r
760 if (EFI_ERROR (Status)) {\r
761 return Status;\r
762 }\r
763\r
5d8d8b51 764 if ((Private->Cap.Css & BIT0) == 0) {\r
87000d77 765 DEBUG ((DEBUG_INFO, "NvmeControllerInit: the controller doesn't support NVMe command set\n"));\r
eb290d02
FT
766 return EFI_UNSUPPORTED;\r
767 }\r
768\r
769 //\r
770 // Currently the driver only supports 4k page size.\r
771 //\r
772 ASSERT ((Private->Cap.Mpsmin + 12) <= EFI_PAGE_SHIFT);\r
773\r
1436aea4
MK
774 Private->Cid[0] = 0;\r
775 Private->Cid[1] = 0;\r
776 Private->Cid[2] = 0;\r
777 Private->Pt[0] = 0;\r
778 Private->Pt[1] = 0;\r
779 Private->Pt[2] = 0;\r
6523ae8b
TF
780 Private->SqTdbl[0].Sqt = 0;\r
781 Private->SqTdbl[1].Sqt = 0;\r
758ea946 782 Private->SqTdbl[2].Sqt = 0;\r
6523ae8b
TF
783 Private->CqHdbl[0].Cqh = 0;\r
784 Private->CqHdbl[1].Cqh = 0;\r
758ea946
HW
785 Private->CqHdbl[2].Cqh = 0;\r
786 Private->AsyncSqHead = 0;\r
eb290d02
FT
787\r
788 Status = NvmeDisableController (Private);\r
789\r
1436aea4 790 if (EFI_ERROR (Status)) {\r
eb290d02
FT
791 return Status;\r
792 }\r
793\r
794 //\r
795 // set number of entries admin submission & completion queues.\r
796 //\r
d45c8c30
FT
797 Aqa.Asqs = NVME_ASQ_SIZE;\r
798 Aqa.Rsvd1 = 0;\r
799 Aqa.Acqs = NVME_ACQ_SIZE;\r
800 Aqa.Rsvd2 = 0;\r
eb290d02
FT
801\r
802 //\r
803 // Address of admin submission queue.\r
804 //\r
c5921812 805 Asq = (UINT64)(UINTN)(Private->BufferPciAddr) & ~0xFFF;\r
eb290d02
FT
806\r
807 //\r
808 // Address of admin completion queue.\r
809 //\r
c5921812 810 Acq = (UINT64)(UINTN)(Private->BufferPciAddr + EFI_PAGE_SIZE) & ~0xFFF;\r
eb290d02
FT
811\r
812 //\r
813 // Address of I/O submission & completion queue.\r
814 //\r
758ea946 815 ZeroMem (Private->Buffer, EFI_PAGES_TO_SIZE (6));\r
eb290d02
FT
816 Private->SqBuffer[0] = (NVME_SQ *)(UINTN)(Private->Buffer);\r
817 Private->SqBufferPciAddr[0] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr);\r
818 Private->CqBuffer[0] = (NVME_CQ *)(UINTN)(Private->Buffer + 1 * EFI_PAGE_SIZE);\r
819 Private->CqBufferPciAddr[0] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 1 * EFI_PAGE_SIZE);\r
820 Private->SqBuffer[1] = (NVME_SQ *)(UINTN)(Private->Buffer + 2 * EFI_PAGE_SIZE);\r
821 Private->SqBufferPciAddr[1] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 2 * EFI_PAGE_SIZE);\r
822 Private->CqBuffer[1] = (NVME_CQ *)(UINTN)(Private->Buffer + 3 * EFI_PAGE_SIZE);\r
823 Private->CqBufferPciAddr[1] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 3 * EFI_PAGE_SIZE);\r
758ea946
HW
824 Private->SqBuffer[2] = (NVME_SQ *)(UINTN)(Private->Buffer + 4 * EFI_PAGE_SIZE);\r
825 Private->SqBufferPciAddr[2] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 4 * EFI_PAGE_SIZE);\r
826 Private->CqBuffer[2] = (NVME_CQ *)(UINTN)(Private->Buffer + 5 * EFI_PAGE_SIZE);\r
827 Private->CqBufferPciAddr[2] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 5 * EFI_PAGE_SIZE);\r
eb290d02 828\r
87000d77
MK
829 DEBUG ((DEBUG_INFO, "Private->Buffer = [%016X]\n", (UINT64)(UINTN)Private->Buffer));\r
830 DEBUG ((DEBUG_INFO, "Admin Submission Queue size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));\r
831 DEBUG ((DEBUG_INFO, "Admin Completion Queue size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));\r
832 DEBUG ((DEBUG_INFO, "Admin Submission Queue (SqBuffer[0]) = [%016X]\n", Private->SqBuffer[0]));\r
833 DEBUG ((DEBUG_INFO, "Admin Completion Queue (CqBuffer[0]) = [%016X]\n", Private->CqBuffer[0]));\r
834 DEBUG ((DEBUG_INFO, "Sync I/O Submission Queue (SqBuffer[1]) = [%016X]\n", Private->SqBuffer[1]));\r
835 DEBUG ((DEBUG_INFO, "Sync I/O Completion Queue (CqBuffer[1]) = [%016X]\n", Private->CqBuffer[1]));\r
836 DEBUG ((DEBUG_INFO, "Async I/O Submission Queue (SqBuffer[2]) = [%016X]\n", Private->SqBuffer[2]));\r
837 DEBUG ((DEBUG_INFO, "Async I/O Completion Queue (CqBuffer[2]) = [%016X]\n", Private->CqBuffer[2]));\r
eb290d02
FT
838\r
839 //\r
840 // Program admin queue attributes.\r
841 //\r
842 Status = WriteNvmeAdminQueueAttributes (Private, &Aqa);\r
843\r
1436aea4 844 if (EFI_ERROR (Status)) {\r
eb290d02
FT
845 return Status;\r
846 }\r
847\r
848 //\r
849 // Program admin submission queue address.\r
850 //\r
851 Status = WriteNvmeAdminSubmissionQueueBaseAddress (Private, &Asq);\r
852\r
1436aea4 853 if (EFI_ERROR (Status)) {\r
eb290d02
FT
854 return Status;\r
855 }\r
856\r
857 //\r
858 // Program admin completion queue address.\r
859 //\r
860 Status = WriteNvmeAdminCompletionQueueBaseAddress (Private, &Acq);\r
861\r
1436aea4 862 if (EFI_ERROR (Status)) {\r
eb290d02
FT
863 return Status;\r
864 }\r
865\r
866 Status = NvmeEnableController (Private);\r
1436aea4 867 if (EFI_ERROR (Status)) {\r
eb290d02
FT
868 return Status;\r
869 }\r
870\r
eb290d02
FT
871 //\r
872 // Allocate buffer for Identify Controller data\r
873 //\r
eb290d02 874 if (Private->ControllerData == NULL) {\r
1436aea4 875 Private->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_CONTROLLER_DATA));\r
d1102dba 876\r
6523ae8b
TF
877 if (Private->ControllerData == NULL) {\r
878 return EFI_OUT_OF_RESOURCES;\r
879 }\r
eb290d02
FT
880 }\r
881\r
882 //\r
883 // Get current Identify Controller Data\r
884 //\r
885 Status = NvmeIdentifyController (Private, Private->ControllerData);\r
886\r
1436aea4
MK
887 if (EFI_ERROR (Status)) {\r
888 FreePool (Private->ControllerData);\r
eb290d02
FT
889 Private->ControllerData = NULL;\r
890 return EFI_NOT_FOUND;\r
891 }\r
7b8883c6
FT
892\r
893 //\r
894 // Dump NvmExpress Identify Controller Data\r
895 //\r
da7c7274
FT
896 CopyMem (Sn, Private->ControllerData->Sn, sizeof (Private->ControllerData->Sn));\r
897 Sn[20] = 0;\r
898 CopyMem (Mn, Private->ControllerData->Mn, sizeof (Private->ControllerData->Mn));\r
899 Mn[40] = 0;\r
87000d77
MK
900 DEBUG ((DEBUG_INFO, " == NVME IDENTIFY CONTROLLER DATA ==\n"));\r
901 DEBUG ((DEBUG_INFO, " PCI VID : 0x%x\n", Private->ControllerData->Vid));\r
902 DEBUG ((DEBUG_INFO, " PCI SSVID : 0x%x\n", Private->ControllerData->Ssvid));\r
1436aea4
MK
903 DEBUG ((DEBUG_INFO, " SN : %a\n", Sn));\r
904 DEBUG ((DEBUG_INFO, " MN : %a\n", Mn));\r
905 DEBUG ((DEBUG_INFO, " FR : 0x%x\n", *((UINT64 *)Private->ControllerData->Fr)));\r
906 DEBUG ((DEBUG_INFO, " TNVMCAP (high 8-byte) : 0x%lx\n", *((UINT64 *)(Private->ControllerData->Tnvmcap + 8))));\r
907 DEBUG ((DEBUG_INFO, " TNVMCAP (low 8-byte) : 0x%lx\n", *((UINT64 *)Private->ControllerData->Tnvmcap)));\r
87000d77 908 DEBUG ((DEBUG_INFO, " RAB : 0x%x\n", Private->ControllerData->Rab));\r
1436aea4 909 DEBUG ((DEBUG_INFO, " IEEE : 0x%x\n", *(UINT32 *)Private->ControllerData->Ieee_oui));\r
87000d77
MK
910 DEBUG ((DEBUG_INFO, " AERL : 0x%x\n", Private->ControllerData->Aerl));\r
911 DEBUG ((DEBUG_INFO, " SQES : 0x%x\n", Private->ControllerData->Sqes));\r
912 DEBUG ((DEBUG_INFO, " CQES : 0x%x\n", Private->ControllerData->Cqes));\r
913 DEBUG ((DEBUG_INFO, " NN : 0x%x\n", Private->ControllerData->Nn));\r
7b8883c6 914\r
d6c55989 915 //\r
758ea946
HW
916 // Create two I/O completion queues.\r
917 // One for blocking I/O, one for non-blocking I/O.\r
d6c55989
FT
918 //\r
919 Status = NvmeCreateIoCompletionQueue (Private);\r
1436aea4
MK
920 if (EFI_ERROR (Status)) {\r
921 return Status;\r
d6c55989
FT
922 }\r
923\r
924 //\r
758ea946
HW
925 // Create two I/O Submission queues.\r
926 // One for blocking I/O, one for non-blocking I/O.\r
d6c55989
FT
927 //\r
928 Status = NvmeCreateIoSubmissionQueue (Private);\r
d6c55989 929\r
eb290d02
FT
930 return Status;\r
931}\r
932\r
7111e46f
RN
933/**\r
934 This routine is called to properly shutdown the Nvm Express controller per NVMe spec.\r
935\r
936 @param[in] ResetType The type of reset to perform.\r
937 @param[in] ResetStatus The status code for the reset.\r
938 @param[in] DataSize The size, in bytes, of ResetData.\r
939 @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or\r
940 EfiResetShutdown the data buffer starts with a Null-terminated\r
941 string, optionally followed by additional binary data.\r
942 The string is a description that the caller may use to further\r
c676cf74 943 indicate the reason for the system reset.\r
7111e46f
RN
944 For a ResetType of EfiResetPlatformSpecific the data buffer\r
945 also starts with a Null-terminated string that is followed\r
946 by an EFI_GUID that describes the specific type of reset to perform.\r
947**/\r
948VOID\r
949EFIAPI\r
950NvmeShutdownAllControllers (\r
1436aea4
MK
951 IN EFI_RESET_TYPE ResetType,\r
952 IN EFI_STATUS ResetStatus,\r
953 IN UINTN DataSize,\r
954 IN VOID *ResetData OPTIONAL\r
7111e46f
RN
955 )\r
956{\r
1436aea4
MK
957 EFI_STATUS Status;\r
958 EFI_HANDLE *Handles;\r
959 UINTN HandleCount;\r
960 UINTN HandleIndex;\r
961 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfos;\r
962 UINTN OpenInfoCount;\r
963 UINTN OpenInfoIndex;\r
964 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmePassThru;\r
965 NVME_CC Cc;\r
966 NVME_CSTS Csts;\r
967 UINTN Index;\r
968 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
7111e46f
RN
969\r
970 Status = gBS->LocateHandleBuffer (\r
971 ByProtocol,\r
972 &gEfiPciIoProtocolGuid,\r
973 NULL,\r
974 &HandleCount,\r
975 &Handles\r
976 );\r
977 if (EFI_ERROR (Status)) {\r
978 HandleCount = 0;\r
979 }\r
980\r
981 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
982 Status = gBS->OpenProtocolInformation (\r
983 Handles[HandleIndex],\r
984 &gEfiPciIoProtocolGuid,\r
985 &OpenInfos,\r
986 &OpenInfoCount\r
987 );\r
988 if (EFI_ERROR (Status)) {\r
989 continue;\r
990 }\r
991\r
992 for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {\r
993 //\r
994 // Find all the NVME controller managed by this driver.\r
995 // gImageHandle equals to DriverBinding handle for this driver.\r
996 //\r
997 if (((OpenInfos[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) &&\r
1436aea4
MK
998 (OpenInfos[OpenInfoIndex].AgentHandle == gImageHandle))\r
999 {\r
7111e46f
RN
1000 Status = gBS->OpenProtocol (\r
1001 OpenInfos[OpenInfoIndex].ControllerHandle,\r
1002 &gEfiNvmExpressPassThruProtocolGuid,\r
1436aea4 1003 (VOID **)&NvmePassThru,\r
7111e46f
RN
1004 NULL,\r
1005 NULL,\r
1006 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1007 );\r
1008 if (EFI_ERROR (Status)) {\r
1009 continue;\r
1010 }\r
1436aea4 1011\r
7111e46f
RN
1012 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (NvmePassThru);\r
1013\r
1014 //\r
1015 // Read Controller Configuration Register.\r
1016 //\r
1017 Status = ReadNvmeControllerConfiguration (Private, &Cc);\r
1436aea4 1018 if (EFI_ERROR (Status)) {\r
7111e46f
RN
1019 continue;\r
1020 }\r
1436aea4 1021\r
7111e46f
RN
1022 //\r
1023 // The host should set the Shutdown Notification (CC.SHN) field to 01b\r
1024 // to indicate a normal shutdown operation.\r
1025 //\r
1026 Cc.Shn = NVME_CC_SHN_NORMAL_SHUTDOWN;\r
1027 Status = WriteNvmeControllerConfiguration (Private, &Cc);\r
1436aea4 1028 if (EFI_ERROR (Status)) {\r
7111e46f
RN
1029 continue;\r
1030 }\r
1031\r
1032 //\r
1033 // The controller indicates when shutdown processing is completed by updating the\r
1034 // Shutdown Status (CSTS.SHST) field to 10b.\r
1035 // Wait up to 45 seconds (break down to 4500 x 10ms) for the shutdown to complete.\r
1036 //\r
1037 for (Index = 0; Index < NVME_SHUTDOWN_PROCESS_TIMEOUT * 100; Index++) {\r
1038 Status = ReadNvmeControllerStatus (Private, &Csts);\r
1436aea4
MK
1039 if (!EFI_ERROR (Status) && (Csts.Shst == NVME_CSTS_SHST_SHUTDOWN_COMPLETED)) {\r
1040 DEBUG ((DEBUG_INFO, "NvmeShutdownController: shutdown processing is completed after %dms.\n", Index * 10));\r
7111e46f
RN
1041 break;\r
1042 }\r
1436aea4 1043\r
7111e46f
RN
1044 //\r
1045 // Stall for 10ms\r
1046 //\r
1047 gBS->Stall (10 * 1000);\r
1048 }\r
1049\r
1050 if (Index == NVME_SHUTDOWN_PROCESS_TIMEOUT * 100) {\r
1436aea4 1051 DEBUG ((DEBUG_ERROR, "NvmeShutdownController: shutdown processing is timed out\n"));\r
7111e46f
RN
1052 }\r
1053 }\r
1054 }\r
1055 }\r
1056}\r
1057\r
1058/**\r
1059 Register the shutdown notification through the ResetNotification protocol.\r
1060\r
1061 Register the shutdown notification when mNvmeControllerNumber increased from 0 to 1.\r
1062**/\r
1063VOID\r
1064NvmeRegisterShutdownNotification (\r
1065 VOID\r
1066 )\r
1067{\r
1436aea4
MK
1068 EFI_STATUS Status;\r
1069 EFI_RESET_NOTIFICATION_PROTOCOL *ResetNotify;\r
7111e46f
RN
1070\r
1071 mNvmeControllerNumber++;\r
1072 if (mNvmeControllerNumber == 1) {\r
1436aea4 1073 Status = gBS->LocateProtocol (&gEfiResetNotificationProtocolGuid, NULL, (VOID **)&ResetNotify);\r
7111e46f
RN
1074 if (!EFI_ERROR (Status)) {\r
1075 Status = ResetNotify->RegisterResetNotify (ResetNotify, NvmeShutdownAllControllers);\r
1076 ASSERT_EFI_ERROR (Status);\r
1077 } else {\r
1078 DEBUG ((DEBUG_WARN, "NVME: ResetNotification absent! Shutdown notification cannot be performed!\n"));\r
1079 }\r
1080 }\r
1081}\r
1082\r
1083/**\r
1084 Unregister the shutdown notification through the ResetNotification protocol.\r
1085\r
1086 Unregister the shutdown notification when mNvmeControllerNumber decreased from 1 to 0.\r
1087**/\r
1088VOID\r
1089NvmeUnregisterShutdownNotification (\r
1090 VOID\r
1091 )\r
1092{\r
1436aea4
MK
1093 EFI_STATUS Status;\r
1094 EFI_RESET_NOTIFICATION_PROTOCOL *ResetNotify;\r
7111e46f
RN
1095\r
1096 mNvmeControllerNumber--;\r
1097 if (mNvmeControllerNumber == 0) {\r
1436aea4 1098 Status = gBS->LocateProtocol (&gEfiResetNotificationProtocolGuid, NULL, (VOID **)&ResetNotify);\r
7111e46f
RN
1099 if (!EFI_ERROR (Status)) {\r
1100 Status = ResetNotify->UnregisterResetNotify (ResetNotify, NvmeShutdownAllControllers);\r
1101 ASSERT_EFI_ERROR (Status);\r
1102 }\r
1103 }\r
1104}\r