LCOV - code coverage report
Current view: top level - spdk/examples/nvme/pmr_persistence - pmr_persistence.c (source / functions) Hit Total Coverage
Test: Combined Lines: 127 193 65.8 %
Date: 2024-07-15 16:50:41 Functions: 8 9 88.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 37 123 30.1 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (c) Samsung Electronics Co., Ltd.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : 
       8                 :            : #include "spdk/env.h"
       9                 :            : #include "spdk/nvme.h"
      10                 :            : #include "spdk/string.h"
      11                 :            : 
      12                 :            : struct nvme_io {
      13                 :            :         struct spdk_nvme_ctrlr *ctrlr;
      14                 :            :         struct spdk_nvme_transport_id trid;
      15                 :            :         struct spdk_nvme_ns *ns;
      16                 :            :         unsigned nsid;
      17                 :            :         unsigned rlba;
      18                 :            :         unsigned nlbas;
      19                 :            :         unsigned wlba;
      20                 :            :         uint32_t lba_size;
      21                 :            :         unsigned done;
      22                 :            : };
      23                 :            : 
      24                 :            : struct config {
      25                 :            :         struct nvme_io pmr_dev;
      26                 :            :         size_t         copy_size;
      27                 :            : };
      28                 :            : 
      29                 :            : static struct config g_config;
      30                 :            : 
      31                 :            : /* Namespaces index from 1. Return 0 to invoke an error */
      32                 :            : static unsigned
      33                 :         22 : get_nsid(const struct spdk_nvme_transport_id *trid)
      34                 :            : {
      35   [ +  -  #  # ]:         22 :         if (!strcmp(trid->traddr, g_config.pmr_dev.trid.traddr)) {
      36                 :         22 :                 return g_config.pmr_dev.nsid;
      37                 :            :         }
      38                 :          0 :         return 0;
      39                 :            : }
      40                 :            : 
      41                 :            : static void
      42                 :         66 : check_io(void *arg, const struct spdk_nvme_cpl *completion)
      43                 :            : {
      44                 :         66 :         g_config.pmr_dev.done = 1;
      45                 :         66 : }
      46                 :            : 
      47                 :            : static int
      48                 :         22 : pmr_persistence(void)
      49                 :            : {
      50                 :         22 :         int rc = 0;
      51                 :            :         void *pmr_buf, *buf;
      52                 :          0 :         size_t sz;
      53                 :            :         struct spdk_nvme_qpair  *qpair;
      54                 :            : 
      55                 :            :         /* Allocate Queue Pair for the Controller with PMR */
      56                 :         22 :         qpair = spdk_nvme_ctrlr_alloc_io_qpair(g_config.pmr_dev.ctrlr, NULL, 0);
      57         [ -  + ]:         22 :         if (qpair == NULL) {
      58                 :          0 :                 printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
      59                 :          0 :                 return -ENOMEM;
      60                 :            :         }
      61                 :            : 
      62                 :            :         /* Enable the PMR */
      63                 :         22 :         rc = spdk_nvme_ctrlr_enable_pmr(g_config.pmr_dev.ctrlr);
      64         [ -  + ]:         22 :         if (rc) {
      65                 :          0 :                 printf("ERROR: Enabling PMR failed\n");
      66                 :          0 :                 printf("Are you sure %s has a valid PMR?\n",
      67                 :            :                        g_config.pmr_dev.trid.traddr);
      68                 :          0 :                 goto free_qpair;
      69                 :            :         }
      70                 :            : 
      71                 :            :         /* Allocate buffer from PMR */
      72                 :         22 :         pmr_buf = spdk_nvme_ctrlr_map_pmr(g_config.pmr_dev.ctrlr, &sz);
      73   [ +  -  -  + ]:         22 :         if (pmr_buf == NULL || sz < g_config.copy_size) {
      74                 :          0 :                 printf("ERROR: PMR buffer allocation failed\n");
      75                 :          0 :                 rc = -ENOMEM;
      76                 :          0 :                 goto disable_pmr;
      77                 :            :         }
      78                 :            : 
      79                 :            :         /* Clear the done flag */
      80                 :         22 :         g_config.pmr_dev.done = 0;
      81                 :            : 
      82                 :            :         /* Do the write to the PMR IO buffer, reading from rlba */
      83                 :         22 :         rc = spdk_nvme_ns_cmd_read(g_config.pmr_dev.ns, qpair, pmr_buf,
      84                 :         22 :                                    g_config.pmr_dev.rlba, g_config.pmr_dev.nlbas,
      85                 :            :                                    check_io, NULL, 0);
      86         [ -  + ]:         22 :         if (rc != 0) {
      87         [ #  # ]:          0 :                 fprintf(stderr, "Read I/O to PMR failed\n");
      88                 :          0 :                 rc = -EIO;
      89                 :          0 :                 goto unmap_pmr;
      90                 :            :         }
      91         [ +  + ]:      61700 :         while (!g_config.pmr_dev.done) {
      92                 :      61678 :                 spdk_nvme_qpair_process_completions(qpair, 0);
      93                 :            :         }
      94                 :            : 
      95                 :            :         /* Clear the done flag */
      96                 :         22 :         g_config.pmr_dev.done = 0;
      97                 :            : 
      98                 :         22 :         pmr_buf = NULL;
      99                 :            : 
     100                 :            :         /* Free PMR buffer */
     101                 :         22 :         rc = spdk_nvme_ctrlr_unmap_pmr(g_config.pmr_dev.ctrlr);
     102         [ -  + ]:         22 :         if (rc) {
     103                 :          0 :                 printf("ERROR: Unmapping PMR failed\n");
     104                 :          0 :                 goto disable_pmr;
     105                 :            :         }
     106                 :            : 
     107                 :            :         /* Disable the PMR */
     108                 :         22 :         rc = spdk_nvme_ctrlr_disable_pmr(g_config.pmr_dev.ctrlr);
     109         [ -  + ]:         22 :         if (rc) {
     110                 :          0 :                 printf("ERROR: Disabling PMR failed\n");
     111                 :          0 :                 goto free_qpair;
     112                 :            :         }
     113                 :            : 
     114                 :            :         /* Free the queue */
     115                 :         22 :         spdk_nvme_ctrlr_free_io_qpair(qpair);
     116                 :            : 
     117                 :         22 :         rc = spdk_nvme_ctrlr_reset(g_config.pmr_dev.ctrlr);
     118         [ -  + ]:         22 :         if (rc) {
     119                 :          0 :                 printf("ERROR: Resetting Controller failed\n");
     120                 :          0 :                 return rc;
     121                 :            :         }
     122                 :            : 
     123                 :            :         /* Allocate Queue Pair for the Controller with PMR */
     124                 :         22 :         qpair = spdk_nvme_ctrlr_alloc_io_qpair(g_config.pmr_dev.ctrlr, NULL, 0);
     125         [ -  + ]:         22 :         if (qpair == NULL) {
     126                 :          0 :                 printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
     127                 :          0 :                 return -ENOMEM;
     128                 :            :         }
     129                 :            : 
     130                 :            :         /* Enable the PMR */
     131                 :         22 :         rc = spdk_nvme_ctrlr_enable_pmr(g_config.pmr_dev.ctrlr);
     132         [ -  + ]:         22 :         if (rc) {
     133                 :          0 :                 printf("ERROR: Enabling PMR failed\n");
     134                 :          0 :                 goto free_qpair;
     135                 :            :         }
     136                 :            : 
     137                 :            :         /* Allocate buffer from PMR */
     138                 :         22 :         pmr_buf = spdk_nvme_ctrlr_map_pmr(g_config.pmr_dev.ctrlr, &sz);
     139   [ +  -  -  + ]:         22 :         if (pmr_buf == NULL || sz < g_config.copy_size) {
     140                 :          0 :                 printf("ERROR: PMR buffer allocation failed\n");
     141                 :          0 :                 rc = -ENOMEM;
     142                 :          0 :                 goto disable_pmr;
     143                 :            :         }
     144                 :            : 
     145                 :            :         /* Do the read from the PMR IO buffer, write to wlba */
     146                 :         22 :         rc = spdk_nvme_ns_cmd_write(g_config.pmr_dev.ns, qpair, pmr_buf,
     147                 :         22 :                                     g_config.pmr_dev.wlba, g_config.pmr_dev.nlbas,
     148                 :            :                                     check_io, NULL, 0);
     149         [ -  + ]:         22 :         if (rc != 0) {
     150         [ #  # ]:          0 :                 fprintf(stderr, "Read I/O from PMR failed\n");
     151                 :          0 :                 rc = -EIO;
     152                 :          0 :                 goto unmap_pmr;
     153                 :            :         }
     154         [ +  + ]:     190681 :         while (!g_config.pmr_dev.done) {
     155                 :     190659 :                 spdk_nvme_qpair_process_completions(qpair, 0);
     156                 :            :         }
     157                 :            : 
     158                 :            :         /* Clear the done flag */
     159                 :         22 :         g_config.pmr_dev.done = 0;
     160                 :            : 
     161                 :         22 :         buf = spdk_zmalloc(g_config.copy_size, 0x1000, NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
     162         [ -  + ]:         22 :         if (buf == NULL) {
     163                 :          0 :                 printf("ERROR: Buffer allocation failed\n");
     164                 :          0 :                 rc = -ENOMEM;
     165                 :          0 :                 goto unmap_pmr;
     166                 :            :         }
     167                 :            : 
     168                 :            :         /* Do the read from wlba to a buffer */
     169                 :         22 :         rc = spdk_nvme_ns_cmd_read(g_config.pmr_dev.ns, qpair, buf,
     170                 :         22 :                                    g_config.pmr_dev.wlba, g_config.pmr_dev.nlbas,
     171                 :            :                                    check_io, NULL, 0);
     172         [ -  + ]:         22 :         if (rc != 0) {
     173         [ #  # ]:          0 :                 fprintf(stderr, "Read I/O from WLBA failed\n");
     174                 :          0 :                 rc = -EIO;
     175                 :          0 :                 goto free_buf;
     176                 :            :         }
     177         [ +  + ]:      17298 :         while (!g_config.pmr_dev.done) {
     178                 :      17276 :                 spdk_nvme_qpair_process_completions(qpair, 0);
     179                 :            :         }
     180                 :            : 
     181                 :            :         /* Clear the done flag */
     182                 :         22 :         g_config.pmr_dev.done = 0;
     183                 :            : 
     184                 :            :         /* Compare the data in the read buffer to the PMR buffer */
     185   [ -  +  #  #  :         22 :         if (memcmp(buf, pmr_buf, g_config.copy_size)) {
                   #  # ]
     186                 :          0 :                 printf("PMR Data Not Persistent, after Controller Reset\n");
     187                 :          0 :                 rc = -EIO;
     188                 :            :         } else {
     189                 :         22 :                 printf("PMR Data is Persistent across Controller Reset\n");
     190                 :            :         }
     191                 :            : 
     192                 :         22 : free_buf:
     193                 :         22 :         spdk_free(buf);
     194                 :            : 
     195                 :         22 : unmap_pmr:
     196                 :            :         /* Free PMR buffer */
     197                 :         22 :         spdk_nvme_ctrlr_unmap_pmr(g_config.pmr_dev.ctrlr);
     198                 :            : 
     199                 :         22 : disable_pmr:
     200                 :            :         /* Disable the PMR */
     201                 :         22 :         spdk_nvme_ctrlr_disable_pmr(g_config.pmr_dev.ctrlr);
     202                 :            : 
     203                 :         22 : free_qpair:
     204                 :            :         /* Free the queue */
     205                 :         22 :         spdk_nvme_ctrlr_free_io_qpair(qpair);
     206                 :            : 
     207                 :         22 :         return rc;
     208                 :            : }
     209                 :            : 
     210                 :            : static bool
     211                 :         44 : probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
     212                 :            :          struct spdk_nvme_ctrlr_opts *opts)
     213                 :            : {
     214                 :            :         /* We will only attach to the Controller specified by the user */
     215         [ +  + ]:         44 :         if (spdk_nvme_transport_id_compare(trid, &g_config.pmr_dev.trid)) {
     216         [ #  # ]:         22 :                 printf("%s - not probed %s!\n", __func__, trid->traddr);
     217                 :         22 :                 return 0;
     218                 :            :         }
     219                 :            : 
     220         [ #  # ]:         22 :         printf("%s - probed %s!\n", __func__, trid->traddr);
     221                 :         22 :         return 1;
     222                 :            : }
     223                 :            : 
     224                 :            : static void
     225                 :         22 : attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
     226                 :            :           struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
     227                 :            : {
     228                 :            :         struct spdk_nvme_ns *ns;
     229                 :            : 
     230                 :         22 :         ns = spdk_nvme_ctrlr_get_ns(ctrlr, get_nsid(trid));
     231         [ -  + ]:         22 :         if (ns == NULL) {
     232   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Could not locate namespace %d on controller %s.\n",
     233                 :          0 :                         get_nsid(trid), trid->traddr);
     234                 :          0 :                 exit(-1);
     235                 :            :         }
     236                 :            : 
     237                 :         22 :         g_config.pmr_dev.ctrlr    = ctrlr;
     238                 :         22 :         g_config.pmr_dev.ns       = ns;
     239                 :         22 :         g_config.pmr_dev.lba_size = spdk_nvme_ns_get_sector_size(ns);
     240                 :            : 
     241         [ #  # ]:         22 :         printf("%s - attached %s!\n", __func__, trid->traddr);
     242                 :         22 : }
     243                 :            : 
     244                 :            : static void
     245                 :          0 : usage(char *program_name)
     246                 :            : {
     247         [ #  # ]:          0 :         printf("%s options (all mandatory)", program_name);
     248                 :          0 :         printf("\n");
     249         [ #  # ]:          0 :         printf("\t[-p PCIe address of the NVMe Device with PMR support]\n");
     250         [ #  # ]:          0 :         printf("\t[-n Namespace ID]\n");
     251         [ #  # ]:          0 :         printf("\t[-r Read LBA]\n");
     252         [ #  # ]:          0 :         printf("\t[-l Number of LBAs to read]\n");
     253         [ #  # ]:          0 :         printf("\t[-w Write LBA]\n");
     254                 :          0 :         printf("\n");
     255                 :          0 : }
     256                 :            : 
     257                 :            : static int
     258                 :         22 : parse_args(int argc, char **argv)
     259                 :            : {
     260                 :            :         int op;
     261                 :         22 :         unsigned num_args = 0;
     262                 :            :         long int val;
     263                 :            : 
     264   [ +  +  #  #  :        132 :         while ((op = getopt(argc, argv, "p:n:r:l:w:")) != -1) {
                   #  # ]
     265      [ +  +  - ]:        110 :                 switch (op) {
     266                 :         22 :                 case 'p':
     267         [ #  # ]:         22 :                         snprintf(&g_config.pmr_dev.trid.traddr[0], SPDK_NVMF_TRADDR_MAX_LEN + 1,
     268                 :            :                                  "%s", optarg);
     269                 :            : 
     270                 :         22 :                         g_config.pmr_dev.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
     271                 :            : 
     272                 :         22 :                         spdk_nvme_transport_id_populate_trstring(&g_config.pmr_dev.trid,
     273                 :            :                                         spdk_nvme_transport_id_trtype_str(g_config.pmr_dev.trid.trtype));
     274                 :            : 
     275                 :         22 :                         num_args++;
     276                 :         22 :                         break;
     277                 :         88 :                 case 'n':
     278                 :            :                 case 'r':
     279                 :            :                 case 'l':
     280                 :            :                 case 'w':
     281                 :         88 :                         val = spdk_strtol(optarg, 10);
     282         [ -  + ]:         88 :                         if (val < 0) {
     283   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "Converting a string to integer failed\n");
     284                 :          0 :                                 return val;
     285                 :            :                         }
     286                 :            :                         switch (op) {
     287                 :         22 :                         case 'n':
     288                 :         22 :                                 g_config.pmr_dev.nsid = (unsigned)val;
     289                 :         22 :                                 num_args++;
     290                 :         22 :                                 break;
     291                 :         22 :                         case 'r':
     292                 :         22 :                                 g_config.pmr_dev.rlba = (unsigned)val;
     293                 :         22 :                                 num_args++;
     294                 :         22 :                                 break;
     295                 :         22 :                         case 'l':
     296                 :         22 :                                 g_config.pmr_dev.nlbas = (unsigned)val;
     297                 :         22 :                                 num_args++;
     298                 :         22 :                                 break;
     299                 :         22 :                         case 'w':
     300                 :         22 :                                 g_config.pmr_dev.wlba = (unsigned)val;
     301                 :         22 :                                 num_args++;
     302                 :         22 :                                 break;
     303                 :            :                         }
     304                 :         88 :                         break;
     305                 :          0 :                 default:
     306                 :          0 :                         usage(argv[0]);
     307                 :          0 :                         return 1;
     308                 :            :                 }
     309                 :            :         }
     310                 :            : 
     311         [ -  + ]:         22 :         if (num_args != 5) {
     312                 :          0 :                 usage(argv[0]);
     313                 :          0 :                 return 1;
     314                 :            :         }
     315                 :            : 
     316                 :         22 :         return 0;
     317                 :            : }
     318                 :            : 
     319                 :            : static void
     320                 :         22 : cleanup(void)
     321                 :            : {
     322                 :         22 :         struct spdk_nvme_detach_ctx *detach_ctx = NULL;
     323                 :            : 
     324                 :         22 :         spdk_nvme_detach_async(g_config.pmr_dev.ctrlr, &detach_ctx);
     325                 :            : 
     326         [ +  - ]:         22 :         if (detach_ctx) {
     327                 :         22 :                 spdk_nvme_detach_poll(detach_ctx);
     328                 :            :         }
     329                 :         22 : }
     330                 :            : 
     331                 :            : int
     332                 :         22 : main(int argc, char **argv)
     333                 :            : {
     334                 :         22 :         int rc = 0;
     335                 :          0 :         struct spdk_env_opts opts;
     336                 :            : 
     337                 :            :         /*
     338                 :            :          * Parse the input arguments. For now we use the following
     339                 :            :          * format list:
     340                 :            :          *
     341                 :            :          * -p <pci id> -n <namespace> -r <Read LBA> -l <number of LBAs> -w <Write LBA>
     342                 :            :          *
     343                 :            :          */
     344                 :         22 :         rc = parse_args(argc, argv);
     345         [ -  + ]:         22 :         if (rc) {
     346   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Error in parse_args(): %d\n", rc);
     347                 :          0 :                 return rc;
     348                 :            :         }
     349                 :            : 
     350                 :            :         /*
     351                 :            :          * SPDK relies on an abstraction around the local environment
     352                 :            :          * named env that handles memory allocation and PCI device operations.
     353                 :            :          * This library must be initialized first.
     354                 :            :          *
     355                 :            :          */
     356                 :         22 :         spdk_env_opts_init(&opts);
     357                 :         22 :         opts.name = "pmr_persistence";
     358                 :         22 :         opts.shm_id = 0;
     359         [ -  + ]:         22 :         if (spdk_env_init(&opts) < 0) {
     360   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to initialize SPDK env\n");
     361                 :          0 :                 return 1;
     362                 :            :         }
     363                 :            : 
     364                 :            :         /*
     365                 :            :          * PMRs only apply to PCIe attached NVMe controllers so we
     366                 :            :          * only probe the PCIe bus. This is the default when we pass
     367                 :            :          * in NULL for the first argument.
     368                 :            :          */
     369                 :            : 
     370                 :         22 :         rc = spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL);
     371         [ -  + ]:         22 :         if (rc) {
     372   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Error in spdk_nvme_probe(): %d\n", rc);
     373                 :          0 :                 cleanup();
     374                 :          0 :                 return rc;
     375                 :            :         }
     376                 :            : 
     377                 :         22 :         g_config.copy_size = g_config.pmr_dev.nlbas * g_config.pmr_dev.lba_size;
     378                 :            : 
     379                 :            :         /*
     380                 :            :          * Call the pmr_persistence() function which performs the data copy
     381                 :            :          * to PMR region, resets the Controller and verifies the data persistence
     382                 :            :          * or returns an error code if it fails.
     383                 :            :          */
     384                 :         22 :         rc = pmr_persistence();
     385         [ -  + ]:         22 :         if (rc) {
     386   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Error in pmr_persistence(): %d\n", rc);
     387                 :            :         }
     388                 :            : 
     389                 :         22 :         cleanup();
     390                 :            : 
     391                 :         22 :         return rc;
     392                 :            : }

Generated by: LCOV version 1.14