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