NVMe-cli-1.1’s plugin mode

From NVMe-cli-1.1, new operation is added for Developers who want to add a new command or possibily an entirely new plug-in for some special extension outside the spec.

For your more information, URL : Developers of nvme-cli

BUT, You can add VU command outside the spec into nvme-cli-1.1 using nvme-builtin.h

If you want to know how to make VU command using nvme-builtin.h. Please refer to my another blog

BUT, at this time, I will use the another way, that is adding a new plugin.

First, Create a header file to define your plugin.

let’s see an example that is introduced on NVMe-clie’s official site.

the file of example is where you will give your plugin a name, description, and define all the sub-commands your plugin impelements.

FILE: foo-plugin.h

#undef CMD_INC_FILE
#define CMD_INC_FILE foo-plugin

#if !defined(FOO) || defined(CMD_HEADER_MULTI_READ)
#define FOO

#include "cmd.h"

PLUGIN(NAME("foo", "Foo plugin"),
    COMMAND_LIST(
        ENTRY("bar", "foo bar", bar)
        ENTRY("baz", "foo baz", baz)
        ENTRY("qux", "foo quz", qux)
    )
);

#endif

#include "define_cmd.h"

In order to have the complier generate the plugin through the xmacro expansion, you need to include this header in your source file, with pre-defining macro directive to create the commands.

To get started from the above exmple, we just need to define “CREATE_CMD” and include the header :

File:foo-plugin.c

#define CREATE_CMD
#include "foo-plugin.h"

After that, You just need to implement the functions you defined in each ENTRY, then append the object file name to the Makefiles’s “OBJS”

An example of plugin extensions

./nvme –help

Then, let’s see the actual example with nvme-cli-1.1

$ ./nvme --help
nvme-1.1
usage: nvme <command> [<device>] [<args>]

The '<device>' may be either an NVMe character device (ex: /dev/nvme0) or an
nvme block device (ex: /dev/nvme0n1).

The following are all implemented sub-commands:
  list            List all NVMe devices and namespaces on machine
  id-ctrl         Send NVMe Identify Controller
  id-ns           Send NVMe Identify Namespace, display structure
  list-ns         Send NVMe Identify List, display structure
  create-ns       Creates a namespace with the provided parameters
  delete-ns       Deletes a namespace from the controller
  attach-ns       Attaches a namespace to requested controller(s)
  detach-ns       Detaches a namespace from requested controller(s)
  list-ctrl       Send NVMe Identify Controller List, display structure
  get-ns-id       Retrieve the namespace ID of opened block device
  get-log         Generic NVMe get log, returns log in raw format
  fw-log          Retrieve FW Log, show it
  smart-log       Retrieve SMART Log, show it
  error-log       Retrieve Error Log, show it
  get-feature     Get feature and show the resulting value
  set-feature     Set a feature and show the resulting value
  format          Format namespace with new block format
  fw-activate     Activate new firmware slot
  fw-download     Download new firmware
  admin-passthru  Submit arbitrary admin command, return results
  io-passthru     Submit an arbitrary IO command, return results
  security-send   Submit a Security Send command, return results
  security-recv   Submit a Security Receive command, return results
  resv-acquire    Submit a Reservation Acquire, return results
  resv-register   Submit a Reservation Register, return results
  resv-release    Submit a Reservation Release, return results
  resv-report     Submit a Reservation Report, return results
  dsm             Submit a Data Set Management command, return results
  flush           Submit a Flush command, return results
  compare         Submit a Compare command, return results
  read            Submit a read command, return results
  write           Submit a write command, return results
  write-zeroes    Submit a write zeroes command, return results
  write-uncor     Submit a write uncorrectable command, return results
  reset           Resets the controller
  subsystem-reset Resets the controller
  show-regs       Shows the controller registers. Requires admin character device
  discover        Discover NVMeoF subsystems
  connect-all     Discover and Connect to NVMeoF subsystems
  connect         Connect to NVMeoF subsystem
  disconnect      Disconnect from NVMeoF subsystem
  version         Shows the program version
  help            Display this help

See 'nvme help <command>' for more information on a specific command

The following are all installed plugin extensions:
  intel           Intel vendor specific extensions
  lnvm            LightNVM specific extensions
  memblaze        Memblaze vendor specific extensions

See 'nvme <plugin> help' for more information on a plugin

As you can see the above result, in the bottom of the above, there are plugin extensions like this :

The following are all installed plugin extensions:
  intel           Intel vendor specific extensions
  lnvm            LightNVM specific extensions
  memblaze        Memblaze vendor specific extensions

See 'nvme <plugin> help' for more information on a plugin

So I typed ‘nvme <plugin(lnvm)> help

$ ./nvme lnvm help
nvme-1.1
usage: nvme lnvm <command> [<device>] [<args>]

The '<device>' may be either an NVMe character device (ex: /dev/nvme0) or an
nvme block device (ex: /dev/nvme0n1).

LightNVM specific extensions

The following are all implemented sub-commands:
  list            List available LightNVM devices
  info            List general information and available target engines
  id-ns           List geometry for LightNVM device
  init            Initialize media manager on LightNVM device
  create          Create target on top of a LightNVM device
  remove          Remove target from device
  factory         Reset device to factory state
  diag-bbtbl      Diagnose bad block table
  diag-set-bbtbl  Update bad block table
  version         Shows the program version
  help            Display this help

See 'nvme lnvm help <command>' for more information on a specific command

Let’s the actual file of lnvm-nvme.c and lnvm-nvme.h

/nvme-cli-1.1/lnvm-nvme.h

  1 
  2 #undef CMD_INC_FILE
  3 #define CMD_INC_FILE lnvm-nvme
  4 
  5 #if !defined(LNVM_NVME) || defined(CMD_HEADER_MULTI_READ)
  6 #define LNVM_NVME
  7 
  8 #include "cmd.h"
  9 
 10 PLUGIN(NAME("lnvm", "LightNVM specific extensions"),
 11         COMMAND_LIST(
 12                 ENTRY("list", "List available LightNVM devices", lnvm_list)
 13                 ENTRY("info", "List general information and available target engines", lnvm_info)
 14                 ENTRY("id-ns", "List geometry for LightNVM device", lnvm_id_ns)
 15                 ENTRY("init", "Initialize media manager on LightNVM device", lnvm_init)
 16                 ENTRY("create", "Create target on top of a LightNVM device", lnvm_create_tgt)
 17                 ENTRY("remove", "Remove target from device", lnvm_remove_tgt)
 18                 ENTRY("factory", "Reset device to factory state", lnvm_factory_init)
 19                 ENTRY("diag-bbtbl", "Diagnose bad block table", lnvm_get_bbtbl)
 20                 ENTRY("diag-set-bbtbl", "Update bad block table", lnvm_set_bbtbl)
 21         )
 22 );
 23 
 24 #endif
 25 
 26 #include "define_cmd.h"
~                                                                         

As you can see the above code. note several lines.

1 
2 #undef CMD_INC_FILE
3 #define CMD_INC_FILE lnvm-nvme
4 
5 #if !defined(LNVM_NVME) || defined(CMD_HEADER_MULTI_READ)
6 #define LNVM_NVME
7 
8 #include "cmd.h"
9 
10 PLUGIN(NAME("lnvm", "LightNVM specific extensions"),
11         COMMAND_LIST(
12                 ENTRY("list", "List available LightNVM devices", lnvm_list)
21         )
22 );
23 
24 #endif
25 
26 #include "define_cmd.h"

/nvme-cli-1.1/lnvm-nvme.c

even this file is the same part is important.

........
14 #define CREATE_CMD
15 #include "lnvm-nvme.h"
16 
17 static int lnvm_init(int argc, char **argv, struct command *cmd, struct plugin *plugin)
18 {
19         const char *desc = "Initialize LightNVM device. A LightNVM/Open-Channel SSD"\
20                            " must have a media manager associated before it can "\
21                            " be exposed to the user. The default is to initialize"
22                            " the general media manager on top of the device.\n\n"
23                            "Example:"
24                            " lnvm-init -d nvme0n1";
25         const char *devname = "identifier of desired device. e.g. nvme0n1.";
26         const char *mmtype = "media manager to initialize on top of device. Default: gennvm.";
27 
28         struct config
29         {
30                 char *devname;
31                 char *mmtype;
32         };
33 
34         struct config cfg = {
35                 .devname = "",
36                 .mmtype = "gennvm",
37         };
38 
39         const struct argconfig_commandline_options command_line_options[] = {
40                 {"device-name",   'd', "DEVICE", CFG_STRING, &cfg.devname, required_argument, devname},
41                 {"mediamgr-name", 'm', "MM",     CFG_STRING, &cfg.mmtype,  required_argument, mmtype},
42                 {NULL}
43         };
44 
45         argconfig_parse(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
46 
47         if (!strlen(cfg.devname)) {
48                 fprintf(stderr, "device name missing %d\n", (int)strlen(cfg.devname));
49                 return -EINVAL;
50         }
51 
52         return lnvm_do_init(cfg.devname, cfg.mmtype);
53 }
54 
55 static int lnvm_list(int argc, char **argv, struct command *cmd, struct plugin *plugin)
........

Exception situation because of the number of bits in Data type

if you get int128 from firmware and int128 is split into four pieces in uint32. you have to chage int128 to long double type.

that is because it is easy to calculat WAF automatically.

let’s see an example function to change from int128 to long double.


//data variable consists of __u8 * arr[16];

static long double int128_to_double(__u8 *data)
{
        int i;
        long double result = 0;

        for (i = 0; i < 16; i++) {
                result *= 256;
                result += data[15 - i];
        }
        return result;
}