summaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
authorBenjamin Drung <bdrung@debian.org>2023-06-10 08:55:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-06-10 09:21:49 +0000
commit88837172f69eabc408ae3945d82e0270b8e07440 (patch)
treed6b7fa06694f45d25f54f6ea9ded93c981e51f6f /doc
parentInitial commit. (diff)
downloadnvme-stas-88837172f69eabc408ae3945d82e0270b8e07440.tar.xz
nvme-stas-88837172f69eabc408ae3945d82e0270b8e07440.zip
Adding upstream version 2.2.1.upstream/2.2.1
Signed-off-by: Benjamin Drung <bdrung@debian.org>
Diffstat (limited to '')
-rw-r--r--doc/.gitignore1
-rwxr-xr-xdoc/dbus-idl-to-docbooks.py118
-rwxr-xr-xdoc/genlist-from-docbooks.py36
-rw-r--r--doc/html.xsl63
-rw-r--r--doc/images/Coverage.pngbin0 -> 127403 bytes
-rw-r--r--doc/images/STAF-STAC-libnvme.pngbin0 -> 81541 bytes
-rw-r--r--doc/man.xsl41
-rw-r--r--doc/meson.build126
-rw-r--r--doc/nvme-stas.xml185
-rw-r--r--doc/readthedocs/Makefile22
-rw-r--r--doc/readthedocs/conf.py34
-rw-r--r--doc/readthedocs/environment.txt1
-rw-r--r--doc/readthedocs/index.rst30
-rw-r--r--doc/readthedocs/installation.rst28
-rw-r--r--doc/readthedocs/make.bat35
-rw-r--r--doc/readthedocs/meson.build64
-rw-r--r--doc/readthedocs/nvme-stas.rst5
-rw-r--r--doc/readthedocs/org.nvmexpress.stac.debug.rst7
-rw-r--r--doc/readthedocs/org.nvmexpress.stac.rst7
-rw-r--r--doc/readthedocs/org.nvmexpress.staf.debug.rst7
-rw-r--r--doc/readthedocs/org.nvmexpress.staf.rst7
-rw-r--r--doc/readthedocs/stacctl.rst7
-rw-r--r--doc/readthedocs/stacd-index.rst13
-rw-r--r--doc/readthedocs/stacd.conf.rst7
-rw-r--r--doc/readthedocs/stacd.rst8
-rw-r--r--doc/readthedocs/stacd.service.rst7
-rw-r--r--doc/readthedocs/stafctl.rst7
-rw-r--r--doc/readthedocs/stafd-index.rst13
-rw-r--r--doc/readthedocs/stafd.conf.rst7
-rw-r--r--doc/readthedocs/stafd.rst7
-rw-r--r--doc/readthedocs/stafd.service.rst7
-rw-r--r--doc/readthedocs/stas-config.target.rst7
-rw-r--r--doc/readthedocs/stas-config@.service.rst7
-rw-r--r--doc/readthedocs/stasadm.rst7
-rw-r--r--doc/readthedocs/sys.conf.rst7
-rw-r--r--doc/stacctl.xml223
-rw-r--r--doc/stacd.conf.xml652
-rw-r--r--doc/stacd.service.xml74
-rw-r--r--doc/stacd.xml229
-rw-r--r--doc/stafctl.xml205
-rw-r--r--doc/stafd.conf.xml280
-rw-r--r--doc/stafd.service.xml67
-rw-r--r--doc/stafd.xml237
-rw-r--r--doc/standard-conf.xml562
-rw-r--r--doc/standard-options.xml163
-rw-r--r--doc/stas-config.target.xml73
-rw-r--r--doc/stas-config@.service.xml67
-rw-r--r--doc/stasadm.xml201
-rw-r--r--doc/sys.conf.xml141
-rw-r--r--docker-compose.yml27
50 files changed, 4129 insertions, 0 deletions
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000..186e12e
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1 @@
+*.xml~
diff --git a/doc/dbus-idl-to-docbooks.py b/doc/dbus-idl-to-docbooks.py
new file mode 100755
index 0000000..7865ffb
--- /dev/null
+++ b/doc/dbus-idl-to-docbooks.py
@@ -0,0 +1,118 @@
+#!/usr/bin/python3
+import os
+import sys
+import pathlib
+import tempfile
+import subprocess
+from argparse import ArgumentParser
+from lxml import etree
+
+
+def parse_args():
+ parser = ArgumentParser(description='Generate DocBook documentation from D-Bus IDL.')
+ parser.add_argument(
+ '--idl',
+ action='store',
+ help='IDL file',
+ required=True,
+ type=str,
+ metavar='FILE',
+ )
+ parser.add_argument(
+ '--output-directory',
+ action='store',
+ help='Output directory where DocBook files will be saved',
+ required=True,
+ type=str,
+ metavar='DIR',
+ )
+ parser.add_argument(
+ '--tmp',
+ action='store',
+ help='Temporary directory for intermediate files',
+ required=True,
+ type=str,
+ metavar='DIR',
+ )
+ return parser.parse_args()
+
+
+ARGS = parse_args()
+
+pathlib.Path(ARGS.output_directory).mkdir(parents=True, exist_ok=True)
+
+REF_ENTRY_INFO = '''\
+ <refentryinfo>
+ <title>stafctl</title>
+ <productname>nvme-stas</productname>
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+'''
+
+MANVOLNUM = '<manvolnum>5</manvolnum>'
+PURPOSE = '<refpurpose>DBus interface</refpurpose>'
+
+PARSER = etree.XMLParser(remove_blank_text=True)
+
+
+def add_missing_info(fname, stem):
+ xml = etree.parse(fname, PARSER)
+ root = xml.getroot()
+ if root.tag != 'refentry':
+ return
+
+ if xml.find('refentryinfo'):
+ return
+
+ root.insert(0, etree.fromstring(REF_ENTRY_INFO))
+
+ refmeta = xml.find('refmeta')
+ if refmeta is not None:
+ if refmeta.find('refentrytitle') is None:
+ refmeta.append(etree.fromstring(f'<refentrytitle>{stem}</refentrytitle>'))
+ refmeta.append(etree.fromstring(MANVOLNUM))
+
+ refnamediv = xml.find('refnamediv')
+ if refnamediv is not None:
+ refpurpose = refnamediv.find('refpurpose')
+ if refpurpose is not None:
+ refnamediv.remove(refpurpose)
+
+ refnamediv.append(etree.fromstring(PURPOSE))
+
+ et = etree.ElementTree(root)
+ et.write(fname, pretty_print=True)
+
+
+FILE_PREFIX = 'nvme-stas'
+FINAL_PREFIX = FILE_PREFIX + '-'
+
+
+pathlib.Path(ARGS.tmp).mkdir(parents=True, exist_ok=True)
+with tempfile.TemporaryDirectory(dir=ARGS.tmp) as tmpdirname:
+ try:
+ subprocess.run(['gdbus-codegen', '--output-directory', tmpdirname, '--generate-docbook', FILE_PREFIX, ARGS.idl])
+ except subprocess.CalledProcessError as ex:
+ sys.exit(f'Failed to generate DocBook file. {ex}')
+
+ stems = []
+ with os.scandir(tmpdirname) as it:
+ for entry in it:
+ if entry.is_file() and entry.name.endswith('.xml') and entry.name.startswith(FINAL_PREFIX):
+ fname = entry.name[len(FINAL_PREFIX) :] # Strip prefix
+ stem = fname[0:-4] # Strip '.xml' suffix
+ stems.append(stem)
+ tmp_file = os.path.join(tmpdirname, entry.name)
+ add_missing_info(tmp_file, stem)
+ os.replace(tmp_file, os.path.join(ARGS.output_directory, fname))
+
+ print(';'.join(stems))
diff --git a/doc/genlist-from-docbooks.py b/doc/genlist-from-docbooks.py
new file mode 100755
index 0000000..f094e09
--- /dev/null
+++ b/doc/genlist-from-docbooks.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python3
+import glob
+from lxml import etree
+
+exclude_list = list(glob.glob('standard-*.xml'))
+
+PARSER = etree.XMLParser(remove_blank_text=True)
+
+
+def extract_data(fname):
+ et = etree.parse(fname, PARSER)
+
+ manvolnum = et.find('./refmeta/manvolnum')
+ manvolnum = manvolnum.text if manvolnum is not None else 0
+
+ deps = set()
+ for elem in et.iter():
+ keys = elem.keys()
+ if 'href' in keys and 'xpointer' in keys:
+ dep = elem.values()[0]
+ if dep in exclude_list:
+ deps.add(dep)
+
+ return manvolnum, list(deps)
+
+
+output = list()
+file_list = glob.glob('*.xml')
+for fname in file_list:
+ if fname not in exclude_list:
+ stem = fname[0:-4]
+ manvolnum, deps = extract_data(fname)
+ deps = ':'.join(deps) if deps else 'None'
+ output.append(','.join([stem, manvolnum, fname, deps]))
+
+print(';'.join(output))
diff --git a/doc/html.xsl b/doc/html.xsl
new file mode 100644
index 0000000..9d2097c
--- /dev/null
+++ b/doc/html.xsl
@@ -0,0 +1,63 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
+
+<xsl:template match="citerefentry[not(@project)]">
+ <a>
+ <xsl:attribute name="href">
+ <xsl:value-of select="refentrytitle"/>
+ <xsl:text>.html#</xsl:text>
+ <xsl:value-of select="refentrytitle/@target"/>
+ </xsl:attribute>
+ <xsl:call-template name="inline.charseq"/>
+ </a>
+</xsl:template>
+
+<xsl:template name="user.header.content">
+ <style>
+ a.headerlink {
+ color: #c60f0f;
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+ visibility: hidden;
+ }
+
+ a.headerlink:hover {
+ background-color: #c60f0f;
+ color: white;
+ }
+
+ h1:hover > a.headerlink, h2:hover > a.headerlink, h3:hover > a.headerlink, dt:hover > a.headerlink {
+ visibility: visible;
+ }
+ </style>
+
+
+ <a>
+ <xsl:text xml:space="preserve" white-space="pre"> &#160; </xsl:text>
+ </a>
+
+ <span style="float:right">
+ <xsl:text>nvme-stas </xsl:text>
+ <xsl:value-of select="$nvme-stas.version"/>
+ </span>
+ <hr/>
+</xsl:template>
+
+<xsl:template match="literal">
+ <xsl:text>"</xsl:text>
+ <xsl:call-template name="inline.monoseq"/>
+ <xsl:text>"</xsl:text>
+</xsl:template>
+
+<xsl:output method="html" encoding="UTF-8" indent="no"/>
+
+</xsl:stylesheet>
+
diff --git a/doc/images/Coverage.png b/doc/images/Coverage.png
new file mode 100644
index 0000000..91cd0a2
--- /dev/null
+++ b/doc/images/Coverage.png
Binary files differ
diff --git a/doc/images/STAF-STAC-libnvme.png b/doc/images/STAF-STAC-libnvme.png
new file mode 100644
index 0000000..19a6704
--- /dev/null
+++ b/doc/images/STAF-STAC-libnvme.png
Binary files differ
diff --git a/doc/man.xsl b/doc/man.xsl
new file mode 100644
index 0000000..fb6bb57
--- /dev/null
+++ b/doc/man.xsl
@@ -0,0 +1,41 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:exsl="http://exslt.org/common"
+ extension-element-prefixes="exsl"
+ version="1.0">
+
+<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl"/>
+
+<xsl:template name="TH.title.line">
+ <xsl:param name="title"/>
+ <xsl:param name="section"/>
+
+ <xsl:call-template name="mark.subheading"/>
+ <xsl:text>.TH "</xsl:text>
+
+ <xsl:call-template name="string.upper">
+ <xsl:with-param name="string">
+ <xsl:value-of select="normalize-space($title)"/>
+ </xsl:with-param>
+ </xsl:call-template>
+
+ <xsl:text>" "</xsl:text>
+ <xsl:value-of select="normalize-space($section)"/>
+
+ <xsl:text>" "" "nvme-stas </xsl:text>
+ <xsl:value-of select="$nvme-stas.version"/>
+
+ <xsl:text>" "</xsl:text>
+
+ <xsl:text>"&#10;</xsl:text>
+ <xsl:call-template name="mark.subheading"/>
+
+</xsl:template>
+
+</xsl:stylesheet>
+
diff --git a/doc/meson.build b/doc/meson.build
new file mode 100644
index 0000000..a4b5786
--- /dev/null
+++ b/doc/meson.build
@@ -0,0 +1,126 @@
+# Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+# See the LICENSE file for details.
+#
+# This file is part of NVMe STorage Appliance Services (nvme-stas).
+#
+# Authors: Martin Belanger <Martin.Belanger@dell.com>
+#
+
+
+if want_man or want_html or want_readthedocs
+ docbklst = find_program('genlist-from-docbooks.py')
+ dbus2doc = find_program('dbus-idl-to-docbooks.py')
+ dbusgen = find_program('gdbus-codegen', required: false) # Needed by dbus2doc
+ if not dbusgen.found()
+ error('gdbus-codegen missing: Install libglib2.0-dev (deb) / glib2-devel (rpm)')
+ endif
+
+ # Get the list of DocBook files to process. The result will
+ # be saved to variable docbooks as a list of tuples as follows:
+ # docbooks = [ ['file1', 'manvolnum-from-file1.xml', 'file1.xml'],
+ # ['file2', 'manvolnum-from-file2.xml', 'file2.xml'], ... ]
+ docbooks = []
+ rr = run_command(docbklst, check: true)
+ output = rr.stdout().strip()
+ if output != ''
+ foreach item : output.split(';')
+ items = item.split(',')
+ stem = items[0]
+ manvolnum = items[1]
+ fname = items[2]
+ deps = items[3]
+ if deps == 'None'
+ deps = []
+ else
+ deps = deps.split(':')
+ endif
+ docbooks += [ [stem, manvolnum, fname, deps] ]
+ endforeach
+ endif
+
+ # Generate DocBooks from IDL queried directly from the D-Bus services.
+ out_dir = conf.get('BUILD_DIR') / 'man-tmp'
+ env = environment({'PYTHONPATH': PYTHONPATH})
+ idls = [ 'stafd.idl', 'stacd.idl' ]
+ foreach idl : idls
+ rr = run_command(
+ dbus2doc,
+ '--idl', conf.get('BUILD_DIR') / 'staslib' / idl,
+ '--output-directory', out_dir,
+ '--tmp', meson.current_build_dir(),
+ env: env,
+ check: true)
+ output = rr.stdout().strip()
+ if output != ''
+ foreach stem : output.split(';')
+ docbooks += [ [stem, '5', out_dir / stem + '.xml', []] ]
+ endforeach
+ endif
+ endforeach
+
+
+ xsltproc = find_program('xsltproc')
+ if xsltproc.found()
+ manpage_style = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
+ if run_command(xsltproc, '--nonet', manpage_style, check: false).returncode() != 0
+ error('Docbook style sheet missing: Install docbook-xsl (deb) / docbook-style-xsl (rpm)')
+ endif
+ endif
+
+ xslt_cmd = [
+ xsltproc,
+ '--nonet',
+ '--xinclude',
+ '--stringparam', 'man.output.quietly', '1',
+ '--stringparam', 'funcsynopsis.style', 'ansi',
+ '--stringparam', 'man.th.extra1.suppress', '1',
+ '--stringparam', 'man.authors.section.enabled', '0',
+ '--stringparam', 'man.copyright.section.enabled', '0',
+ '--stringparam', 'nvme-stas.version', '@0@'.format(meson.project_version()),
+ '-o', '@OUTPUT@',
+ ]
+
+ man_xsl = files('man.xsl')
+ html_xsl = files('html.xsl')
+
+
+ html_files = [] # Will be used as input to readthedocs
+ foreach tuple: docbooks
+ stem = tuple[0]
+ sect = tuple[1]
+ file = files(tuple[2])
+ deps = tuple[3]
+
+ if want_man
+ man = stem + '.' + sect
+ custom_target(
+ man,
+ input: file,
+ output: man,
+ depend_files: deps,
+ command: xslt_cmd + [man_xsl, '@INPUT@'],
+ install: true,
+ install_dir: mandir / ('man' + sect)
+ )
+ endif
+
+ if want_html or want_readthedocs
+ html = stem + '.html'
+ html_file = custom_target(
+ html,
+ input: file,
+ output: html,
+ depend_files: deps,
+ command: xslt_cmd + [html_xsl, '@INPUT@'],
+ install: want_html,
+ install_dir: docdir / 'html'
+ )
+ html_files += [ [stem, html_file ] ]
+ endif
+ endforeach
+endif
+
+if want_readthedocs
+ subdir('readthedocs')
+endif
diff --git a/doc/nvme-stas.xml b/doc/nvme-stas.xml
new file mode 100644
index 0000000..1e70c02
--- /dev/null
+++ b/doc/nvme-stas.xml
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+
+<refentry id="nvme-stas">
+
+ <refentryinfo>
+ <title>nvme-stas</title>
+ <productname>nvme-stas</productname>
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>nvme-stas</refentrytitle>
+ <manvolnum>7</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>nvme-stas</refname>
+ <refpurpose>NVMe over Fabrics STorage Appliance Services</refpurpose>
+ </refnamediv>
+
+ <refsect1>
+ <title>Introduction</title>
+
+ <para>
+ This page describes the services provided by the <code>nvme-stas</code> package.
+ </para>
+
+ <para>
+ <code>nvme-stas</code> is composed of two services, <citerefentry><refentrytitle>stafd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ and <citerefentry><refentrytitle>stacd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ running on a host computer (the NVMe Host).
+ </para>
+
+ <refsect2>
+ <title>STorage Appliance Finder (<code>stafd</code>)</title>
+ <para>
+ The tasks performed by <code>stafd</code> include:
+ </para>
+ <itemizedlist mark='opencircle'>
+ <listitem>
+ <para>
+ Register for mDNS service type <parameter>_nvme-disc._tcp</parameter>
+ with Avahi, the service discovery daemon. This allows <code>stafd</code>
+ to automatically locate Central or Direct Discovery
+ Controllers (CDC, DDC) with zero-configuration networking
+ (zeroconf). <code>stafd</code> also allows users to manually enter CDCs
+ and DDCs in a configuration file
+ (<filename>/etc/stas/stafd.conf</filename>) when users
+ prefer not to enable mDNS-based zeroconf.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Connect to discovered or configured CDCs or DDCs.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Retrieve the list of NVMe subsystem IO Controllers or
+ Discovery Controller referrals from the Discovery Log Page
+ using the NVMe command "Get Log Page".
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Maintain a cache of the discovery log pages.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Provide a D-Bus API where other applications can interact
+ with <code>stafd</code>. This API can be used, for example, to retrieve
+ the list of cached discovery log pages.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </refsect2>
+
+ <refsect2>
+ <title>STorage Appliance Connector (<code>stacd</code>)</title>
+ <para>
+ The tasks performed by <code>stacd</code> include:
+ </para>
+ <itemizedlist mark='opencircle'>
+ <listitem>
+ <para>
+ Read the list of storage subsystems (i.e., discovery log pages)
+ from <code>stafd</code> over the D-Bus API.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Similar to <code>stafd</code>, <code>stacd</code> can also read a list of storage
+ subsystems to connect to from a configuration
+ file: (<filename>/etc/stas/stacd.conf</filename>).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Set up the I/O controller connections to each storage subsystem.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Provide a D-Bus API where other applications can interact
+ with <code>stacd</code>. For example, an application could retrieve the
+ list of I/O controllers that <code>stacd</code> connected to.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </refsect2>
+
+ <refsect2>
+ <title>System configuration</title>
+ <para>
+ A host must be provided with a Host NQN and a Host ID. <code>nvme-stas</code>
+ will not run without these two mandatory configuration parameters.
+ To follow in the footsteps of <code>nvme-cli</code> and <code>libnvme</code>,
+ <code>nvme-stas</code> will use the same Host NQN and ID that
+ <code>nvme-cli</code> and <code>libnvme</code> use by default.
+ In other words, <code>nvme-stas</code> will read the Host NQN and ID
+ from these two files by default:
+ </para>
+
+ <itemizedlist mark='opencircle'>
+ <listitem>
+ <para>
+ <filename>/etc/nvme/hostnqn</filename>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <filename>/etc/nvme/hostid</filename>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Using the same configuration files will ensure consistency between
+ <code>nvme-stas</code>, <code>nvme-cli</code>, and <code>libnvme</code>.
+ On the other hand, <code>nvme-stas</code> can operate with a
+ different Host NQN and/or ID. In that case, one can specify them
+ in <filename>/etc/stas/sys.conf</filename>.
+ </para>
+ A new optional configuration parameters introduced in TP8010, the
+ Host Symbolic Name, can also be specified in <filename>/etc/stas/sys.conf</filename>.
+ The documentation for <filename>/etc/stas/sys.conf</filename>
+ can be found <filename>/etc/stas/sys.conf.doc</filename>.
+ <para>
+ </para>
+ </refsect2>
+
+ </refsect1>
+
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>stacctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>stacd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>stacd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>stacd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>stafctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>stafd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>stafd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>stafd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ </para>
+ </refsect1>
+
+</refentry>
diff --git a/doc/readthedocs/Makefile b/doc/readthedocs/Makefile
new file mode 100644
index 0000000..76911e9
--- /dev/null
+++ b/doc/readthedocs/Makefile
@@ -0,0 +1,22 @@
+# Minimal makefile for Sphinx documentation
+#
+.DEFAULT_GOAL := help
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = .
+BUILDDIR = _build
+
+# Put it first so that "make" without argument is like "make help".
+.PHONY: help
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+.PHONY: Makefile
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/doc/readthedocs/conf.py b/doc/readthedocs/conf.py
new file mode 100644
index 0000000..a5b3960
--- /dev/null
+++ b/doc/readthedocs/conf.py
@@ -0,0 +1,34 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+
+# -- Project information -----------------------------------------------------
+
+project = 'nvme-stas'
+copyright = 'Copyright (c) 2022, Dell Inc. or its subsidiaries. All rights reserved.'
+author = 'Martin Belanger <martin.belanger@dell.com>'
+master_doc = 'index'
+
+version = '@VERSION@'
+release = '@VERSION@'
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'sphinx.ext.autosummary',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['Thumbs.db', '.DS_Store']
diff --git a/doc/readthedocs/environment.txt b/doc/readthedocs/environment.txt
new file mode 100644
index 0000000..5388c88
--- /dev/null
+++ b/doc/readthedocs/environment.txt
@@ -0,0 +1 @@
+sphinx==5.3.0
diff --git a/doc/readthedocs/index.rst b/doc/readthedocs/index.rst
new file mode 100644
index 0000000..ad927fe
--- /dev/null
+++ b/doc/readthedocs/index.rst
@@ -0,0 +1,30 @@
+Welcome to nvme-stas's documentation!
+=====================================
+
+What does nvme-stas provide?
+
+* A Central Discovery Controller (CDC) client for Linux
+* Asynchronous Event Notifications (AEN) handling
+* Automated NVMe subsystem connection controls
+* Error handling and reporting
+* Automatic (zeroconf) and Manual configuration
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+ installation.rst
+ nvme-stas.rst
+ stafd-index.rst
+ stacd-index.rst
+ stasadm.rst
+ sys.conf.rst
+ stas-config.target.rst
+ stas-config@.service.rst
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/doc/readthedocs/installation.rst b/doc/readthedocs/installation.rst
new file mode 100644
index 0000000..95750e2
--- /dev/null
+++ b/doc/readthedocs/installation.rst
@@ -0,0 +1,28 @@
+Installation
+============
+
+Debian / Ubuntu:
+----------------
+
+.. code-block:: sh
+
+ $ apt-get install nvme-stas
+
+Fedora / Red Hat:
+-----------------
+
+.. code-block:: sh
+
+ $ dnf install nvme-stas
+
+Python Version
+--------------
+
+The latest Python 3 version is always recommended, since it has all the latest bells and
+whistles. libnvme supports Python 3.6 and above.
+
+Dependencies
+------------
+
+nvme-stas is built on top of libnvme, which is used to interact with the kernel's NVMe driver (i.e. drivers/nvme/host/). To support all the features of nvme-stas, several changes to the Linux kernel are required. nvme-stas can also operate with older kernels, but with limited functionality. Kernel 5.18 provides all the features needed by nvme-stas. nvme-stas can also work with older kernels that include back-ported changes to the NVMe driver.
+
diff --git a/doc/readthedocs/make.bat b/doc/readthedocs/make.bat
new file mode 100644
index 0000000..153be5e
--- /dev/null
+++ b/doc/readthedocs/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.https://www.sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/doc/readthedocs/meson.build b/doc/readthedocs/meson.build
new file mode 100644
index 0000000..a8e2305
--- /dev/null
+++ b/doc/readthedocs/meson.build
@@ -0,0 +1,64 @@
+# Copyright (c) 2022, Dell Inc. or its subsidiaries. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+# See the LICENSE file for details.
+#
+# This file is part of NVMe STorage Appliance Services (nvme-stas).
+#
+# Authors: Martin Belanger <Martin.Belanger@dell.com>
+#
+
+pandoc = find_program('pandoc', required: true)
+
+components = [
+ 'conf.py',
+ 'Makefile',
+ 'make.bat',
+ 'index.rst',
+ 'environment.txt',
+ 'installation.rst',
+ 'nvme-stas.rst',
+ 'org.nvmexpress.stac.debug.rst',
+ 'org.nvmexpress.stac.rst',
+ 'org.nvmexpress.staf.debug.rst',
+ 'org.nvmexpress.staf.rst',
+ 'stacctl.rst',
+ 'stacd-index.rst',
+ 'stacd.conf.rst',
+ 'stacd.rst',
+ 'stacd.service.rst',
+ 'stafctl.rst',
+ 'stafd-index.rst',
+ 'stafd.conf.rst',
+ 'stafd.rst',
+ 'stafd.service.rst',
+ 'stas-config.target.rst',
+ 'stas-config@.service.rst',
+ 'stasadm.rst',
+ 'sys.conf.rst',
+]
+foreach component : components
+ configure_file(
+ input: component,
+ output: component,
+ configuration: conf,
+ )
+endforeach
+
+foreach tuple: html_files
+ stem = tuple[0]
+ html_file = tuple[1]
+ rst = '_' + stem + '.rst'
+ custom_target(
+ rst,
+ input: html_file,
+ output: rst,
+ build_by_default: true,
+ command: [
+ pandoc,
+ '-f', 'html',
+ '-t', 'rst',
+ '-o', '@OUTPUT@',
+ '@INPUT@'
+ ]
+ )
+endforeach
diff --git a/doc/readthedocs/nvme-stas.rst b/doc/readthedocs/nvme-stas.rst
new file mode 100644
index 0000000..e7383f9
--- /dev/null
+++ b/doc/readthedocs/nvme-stas.rst
@@ -0,0 +1,5 @@
+==========================
+STorage Appliance Services
+==========================
+
+.. include:: _nvme-stas.rst
diff --git a/doc/readthedocs/org.nvmexpress.stac.debug.rst b/doc/readthedocs/org.nvmexpress.stac.debug.rst
new file mode 100644
index 0000000..e82f2d7
--- /dev/null
+++ b/doc/readthedocs/org.nvmexpress.stac.debug.rst
@@ -0,0 +1,7 @@
+=========================
+org.nvmexpress.stac.debug
+=========================
+.. module:: org.nvmexpress.stac.debug
+
+.. include:: _org.nvmexpress.stac.debug.rst
+
diff --git a/doc/readthedocs/org.nvmexpress.stac.rst b/doc/readthedocs/org.nvmexpress.stac.rst
new file mode 100644
index 0000000..5132fad
--- /dev/null
+++ b/doc/readthedocs/org.nvmexpress.stac.rst
@@ -0,0 +1,7 @@
+===================
+org.nvmexpress.stac
+===================
+.. module:: org.nvmexpress.stac
+
+.. include:: _org.nvmexpress.stac.rst
+
diff --git a/doc/readthedocs/org.nvmexpress.staf.debug.rst b/doc/readthedocs/org.nvmexpress.staf.debug.rst
new file mode 100644
index 0000000..8161db5
--- /dev/null
+++ b/doc/readthedocs/org.nvmexpress.staf.debug.rst
@@ -0,0 +1,7 @@
+=========================
+org.nvmexpress.staf.debug
+=========================
+.. module:: org.nvmexpress.staf.debug
+
+.. include:: _org.nvmexpress.staf.debug.rst
+
diff --git a/doc/readthedocs/org.nvmexpress.staf.rst b/doc/readthedocs/org.nvmexpress.staf.rst
new file mode 100644
index 0000000..26ef29d
--- /dev/null
+++ b/doc/readthedocs/org.nvmexpress.staf.rst
@@ -0,0 +1,7 @@
+===================
+org.nvmexpress.staf
+===================
+.. module:: org.nvmexpress.staf
+
+.. include:: _org.nvmexpress.staf.rst
+
diff --git a/doc/readthedocs/stacctl.rst b/doc/readthedocs/stacctl.rst
new file mode 100644
index 0000000..60fe075
--- /dev/null
+++ b/doc/readthedocs/stacctl.rst
@@ -0,0 +1,7 @@
+=======
+stacctl
+=======
+.. module:: stacctl
+
+.. include:: _stacctl.rst
+
diff --git a/doc/readthedocs/stacd-index.rst b/doc/readthedocs/stacd-index.rst
new file mode 100644
index 0000000..cebd5f4
--- /dev/null
+++ b/doc/readthedocs/stacd-index.rst
@@ -0,0 +1,13 @@
+STorage Appliance Connector
+===========================
+
+.. toctree::
+ :maxdepth: 1
+
+ stacd.rst
+ stacd.conf.rst
+ stacd.service.rst
+ stacctl.rst
+ org.nvmexpress.stac.rst
+ org.nvmexpress.stac.debug.rst
+
diff --git a/doc/readthedocs/stacd.conf.rst b/doc/readthedocs/stacd.conf.rst
new file mode 100644
index 0000000..2a0cad9
--- /dev/null
+++ b/doc/readthedocs/stacd.conf.rst
@@ -0,0 +1,7 @@
+==========
+stacd.conf
+==========
+.. module:: stacd.conf
+
+.. include:: _stacd.conf.rst
+
diff --git a/doc/readthedocs/stacd.rst b/doc/readthedocs/stacd.rst
new file mode 100644
index 0000000..2cf809b
--- /dev/null
+++ b/doc/readthedocs/stacd.rst
@@ -0,0 +1,8 @@
+=====
+stacd
+=====
+.. module:: stacd
+
+.. include:: _stacd.rst
+
+
diff --git a/doc/readthedocs/stacd.service.rst b/doc/readthedocs/stacd.service.rst
new file mode 100644
index 0000000..7294710
--- /dev/null
+++ b/doc/readthedocs/stacd.service.rst
@@ -0,0 +1,7 @@
+=============
+stacd.service
+=============
+.. module:: stacd.service
+
+.. include:: _stacd.service.rst
+
diff --git a/doc/readthedocs/stafctl.rst b/doc/readthedocs/stafctl.rst
new file mode 100644
index 0000000..849e37c
--- /dev/null
+++ b/doc/readthedocs/stafctl.rst
@@ -0,0 +1,7 @@
+=======
+stafctl
+=======
+.. module:: stafctl
+
+.. include:: _stafctl.rst
+
diff --git a/doc/readthedocs/stafd-index.rst b/doc/readthedocs/stafd-index.rst
new file mode 100644
index 0000000..f4d1292
--- /dev/null
+++ b/doc/readthedocs/stafd-index.rst
@@ -0,0 +1,13 @@
+STorage Appliance Finder
+========================
+
+.. toctree::
+ :maxdepth: 1
+
+ stafd.rst
+ stafd.conf.rst
+ stafd.service.rst
+ stafctl.rst
+ org.nvmexpress.staf.rst
+ org.nvmexpress.staf.debug.rst
+
diff --git a/doc/readthedocs/stafd.conf.rst b/doc/readthedocs/stafd.conf.rst
new file mode 100644
index 0000000..a03d93a
--- /dev/null
+++ b/doc/readthedocs/stafd.conf.rst
@@ -0,0 +1,7 @@
+==========
+stafd.conf
+==========
+.. module:: stafd.conf
+
+.. include:: _stafd.conf.rst
+
diff --git a/doc/readthedocs/stafd.rst b/doc/readthedocs/stafd.rst
new file mode 100644
index 0000000..a12298c
--- /dev/null
+++ b/doc/readthedocs/stafd.rst
@@ -0,0 +1,7 @@
+=====
+stafd
+=====
+.. module:: stafd
+
+.. include:: _stafd.rst
+
diff --git a/doc/readthedocs/stafd.service.rst b/doc/readthedocs/stafd.service.rst
new file mode 100644
index 0000000..771189c
--- /dev/null
+++ b/doc/readthedocs/stafd.service.rst
@@ -0,0 +1,7 @@
+=============
+stafd.service
+=============
+.. module:: stafd.service
+
+.. include:: _stafd.service.rst
+
diff --git a/doc/readthedocs/stas-config.target.rst b/doc/readthedocs/stas-config.target.rst
new file mode 100644
index 0000000..cf88fa9
--- /dev/null
+++ b/doc/readthedocs/stas-config.target.rst
@@ -0,0 +1,7 @@
+==================
+stas-config.target
+==================
+.. module:: stas-config.target
+
+.. include:: _stas-config.target.rst
+
diff --git a/doc/readthedocs/stas-config@.service.rst b/doc/readthedocs/stas-config@.service.rst
new file mode 100644
index 0000000..7af78ed
--- /dev/null
+++ b/doc/readthedocs/stas-config@.service.rst
@@ -0,0 +1,7 @@
+====================
+stas-config@.service
+====================
+.. module:: stas-config@.service
+
+.. include:: _stas-config@.service.rst
+
diff --git a/doc/readthedocs/stasadm.rst b/doc/readthedocs/stasadm.rst
new file mode 100644
index 0000000..54489a8
--- /dev/null
+++ b/doc/readthedocs/stasadm.rst
@@ -0,0 +1,7 @@
+=======
+stasadm
+=======
+.. module:: stasadm
+
+.. include:: _stasadm.rst
+
diff --git a/doc/readthedocs/sys.conf.rst b/doc/readthedocs/sys.conf.rst
new file mode 100644
index 0000000..05ab0f0
--- /dev/null
+++ b/doc/readthedocs/sys.conf.rst
@@ -0,0 +1,7 @@
+========
+sys.conf
+========
+.. module:: sys.conf
+
+.. include:: _sys.conf.rst
+
diff --git a/doc/stacctl.xml b/doc/stacctl.xml
new file mode 100644
index 0000000..1f07276
--- /dev/null
+++ b/doc/stacctl.xml
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+<refentry id="stacctl" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>stacctl</title>
+ <productname>nvme-stas</productname>
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>stacctl</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>stacctl</refname>
+ <refpurpose>STorage Appliance Connector (STAC) utility program</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>stacctl</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="req">COMMAND</arg>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>stacctl</command> is a tool that can be used to communicate
+ with the <citerefentry><refentrytitle>stacd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry> daemon to retrieve
+ operational data.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Commands</title>
+ <para>The following commands are understood:</para>
+
+ <variablelist>
+ <xi:include href="standard-options.xml" xpointer="tron"/>
+ <xi:include href="standard-options.xml" xpointer="troff"/>
+ <xi:include href="standard-options.xml" xpointer="status"/>
+
+ <varlistentry>
+ <term><command>ls</command></term>
+ <listitem>
+ <para>
+ Show the list of I/O controllers. This will list
+ all the I/O controllers configured in
+ <citerefentry>
+ <refentrytitle>stacd.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry> as well as those discovered by the
+ <citerefentry>
+ <refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry> daemon.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+
+ <para>The following options are understood:</para>
+
+ <variablelist>
+ <xi:include href="standard-options.xml" xpointer="help"/>
+ <xi:include href="standard-options.xml" xpointer="version"/>
+ <xi:include href="standard-options.xml" xpointer="detailed"/>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Exit status</title>
+ <para>
+ On success, 0 is returned; otherwise, a non-zero failure code is
+ returned.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>List I/O controllers</title>
+ <programlisting>$ stacctl ls --detailed
+[{'connect attempts': 0,
+ 'device': 'nvme1',
+ 'host-iface': '',
+ 'host-traddr': '',
+ 'hostid': '3e518ec3-72ec-46a5-a603-2510e3140e29',
+ 'hostnqn': 'nqn.2014-08.org.nvmexpress:uuid:13730573-e8d7-446e-81f6-042a497846d5',
+ 'model': 'Linux',
+ 'retry connect timer': '60.0s [off]',
+ 'serial': '8d22fa96da912fb13f5a',
+ 'subsysnqn': 'nqn.1988-11.com.dell:PowerSANxxx:01:20210225100113-454f73093ceb4847a7bdfc6e34aedead',
+ 'traddr': '::1',
+ 'transport': 'tcp',
+ 'trsvcid': '8009'},
+ {'connect attempts': 0,
+ 'device': 'nvme2',
+ 'host-iface': '',
+ 'host-traddr': '',
+ 'hostid': '3e518ec3-72ec-46a5-a603-2510e3140e29',
+ 'hostnqn': 'nqn.2014-08.org.nvmexpress:uuid:13730573-e8d7-446e-81f6-042a497846d5',
+ 'model': 'Linux',
+ 'retry connect timer': '60.0s [off]',
+ 'serial': 'a9987ae2fd173d100fd0',
+ 'subsysnqn': 'nqn.1988-11.com.dell:PowerSANxxx:01:20210225100113-454f73093ceb4847a7bdfc6e34aebeef',
+ 'traddr': '::1',
+ 'transport': 'tcp',
+ 'trsvcid': '8009'},
+ {'connect attempts': 0,
+ 'device': 'nvme3',
+ 'host-iface': '',
+ 'host-traddr': '',
+ 'hostid': '3e518ec3-72ec-46a5-a603-2510e3140e29',
+ 'hostnqn': 'nqn.2014-08.org.nvmexpress:uuid:13730573-e8d7-446e-81f6-042a497846d5',
+ 'model': 'Linux',
+ 'retry connect timer': '60.0s [off]',
+ 'serial': '13e122f1a8122bed5a8d',
+ 'subsysnqn': 'nqn.1988-11.com.dell:PowerSANxxx:01:20210225100113-454f73093ceb4847a7bdfc6e34ae8e28',
+ 'traddr': '::1',
+ 'transport': 'tcp',
+ 'trsvcid': '8009'}]</programlisting>
+ </example>
+
+ <example>
+ <title>Disable tracing</title>
+ <programlisting>$ stacctl troff</programlisting>
+ </example>
+
+ <example>
+ <title>
+ Show <citerefentry><refentrytitle>stacd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry> operational status.
+ </title>
+
+ <programlisting>$ stacctl status
+{'config soak timer': '1.5s [off]',
+ 'controllers': [{'connect attempts': 0,
+ 'device': 'nvme1',
+ 'host-iface': '',
+ 'host-traddr': '',
+ 'hostid': '3e518ec3-72ec-46a5-a603-2510e3140e29',
+ 'hostnqn': 'nqn.2014-08.org.nvmexpress:uuid:13730573-e8d7-446e-81f6-042a497846d5',
+ 'model': 'Linux',
+ 'retry connect timer': '60.0s [off]',
+ 'serial': '8d22fa96da912fb13f5a',
+ 'subsysnqn': 'nqn.1988-11.com.dell:PowerSANxxx:01:20210225100113-454f73093ceb4847a7bdfc6e34aedead',
+ 'traddr': '::1',
+ 'transport': 'tcp',
+ 'trsvcid': '8009'},
+ {'connect attempts': 0,
+ 'device': 'nvme2',
+ 'host-iface': '',
+ 'host-traddr': '',
+ 'hostid': '3e518ec3-72ec-46a5-a603-2510e3140e29',
+ 'hostnqn': 'nqn.2014-08.org.nvmexpress:uuid:13730573-e8d7-446e-81f6-042a497846d5',
+ 'model': 'Linux',
+ 'retry connect timer': '60.0s [off]',
+ 'serial': 'a9987ae2fd173d100fd0',
+ 'subsysnqn': 'nqn.1988-11.com.dell:PowerSANxxx:01:20210225100113-454f73093ceb4847a7bdfc6e34aebeef',
+ 'traddr': '::1',
+ 'transport': 'tcp',
+ 'trsvcid': '8009'},
+ {'connect attempts': 0,
+ 'device': 'nvme3',
+ 'host-iface': '',
+ 'host-traddr': '',
+ 'hostid': '3e518ec3-72ec-46a5-a603-2510e3140e29',
+ 'hostnqn': 'nqn.2014-08.org.nvmexpress:uuid:13730573-e8d7-446e-81f6-042a497846d5',
+ 'model': 'Linux',
+ 'retry connect timer': '60.0s [off]',
+ 'serial': '13e122f1a8122bed5a8d',
+ 'subsysnqn': 'nqn.1988-11.com.dell:PowerSANxxx:01:20210225100113-454f73093ceb4847a7bdfc6e34ae8e28',
+ 'traddr': '::1',
+ 'transport': 'tcp',
+ 'trsvcid': '8009'}],
+ 'log-level': 'DEBUG',
+ 'tron': True}</programlisting>
+ </example>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry>
+ <refentrytitle>stacd.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>stacd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ <citerefentry project="man-pages"/>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/doc/stacd.conf.xml b/doc/stacd.conf.xml
new file mode 100644
index 0000000..e8c6a64
--- /dev/null
+++ b/doc/stacd.conf.xml
@@ -0,0 +1,652 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+<refentry id="stacd.conf" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>stacd.conf</title>
+ <productname>nvme-stas</productname>
+
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>stacd.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>stacd.conf</refname>
+ <refpurpose>
+ <citerefentry project="man-pages">
+ <refentrytitle>stacd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ configuration file
+ </refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para>
+ <filename>/etc/stas/stacd.conf</filename>
+ </para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ When <citerefentry project="man-pages"><refentrytitle>stacd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry> starts up, it reads its
+ configuration from <filename>stacd.conf</filename>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Configuration File Format</title>
+ <para>
+ <filename>stacd.conf</filename> is a plain text file divided into
+ sections, with configuration entries in the style
+ <replaceable>key</replaceable>=<replaceable>value</replaceable>.
+ Spaces immediately before or after the <literal>=</literal> are
+ ignored. Empty lines are ignored as well as lines starting with
+ <literal>#</literal>, which may be used for commenting.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+
+ <refsect2>
+ <title>[Global] section</title>
+ <para>
+ The following options are available in the
+ <literal>[Global]</literal> section:
+ </para>
+
+ <variablelist>
+ <xi:include href="standard-conf.xml" xpointer="tron"/>
+ <xi:include href="standard-conf.xml" xpointer="hdr-digest"/>
+ <xi:include href="standard-conf.xml" xpointer="data-digest"/>
+ <xi:include href="standard-conf.xml" xpointer="kato"/>
+ <xi:include href="standard-conf.xml" xpointer="ip-family"/>
+
+ <varlistentry>
+ <term><varname>nr-io-queues=</varname></term>
+
+ <listitem>
+ <para>
+ Takes a value in the range 1...N. Overrides the
+ default number of I/O queues create by the driver.
+ </para>
+
+ <para>Note: This parameter is identical to that provided by nvme-cli.</para>
+ <para>
+ Default: Depends on kernel and other run
+ time factors (e.g. number of CPUs).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>nr-write-queues=</varname></term>
+
+ <listitem>
+ <para>
+ Takes a value in the range 1...N. Adds additional
+ queues that will be used for write I/O.
+ </para>
+
+ <para>Note: This parameter is identical to that provided by nvme-cli.</para>
+
+ <para>
+ Default: Depends on kernel and other run
+ time factors (e.g. number of CPUs).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>nr-poll-queues=</varname></term>
+
+ <listitem>
+ <para>
+ Takes a value in the range 1...N. Adds additional
+ queues that will be used for polling latency
+ sensitive I/O.
+ </para>
+
+ <para>Note: This parameter is identical to that provided by nvme-cli.</para>
+
+ <para>
+ Default: Depends on kernel and other run
+ time factors (e.g. number of CPUs).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <xi:include href="standard-conf.xml" xpointer="queue-size"/>
+ <xi:include href="standard-conf.xml" xpointer="reconnect-delay"/>
+ <xi:include href="standard-conf.xml" xpointer="ctrl-loss-tmo"/>
+ <xi:include href="standard-conf.xml" xpointer="disable-sqflow"/>
+
+ <varlistentry>
+ <term><varname>ignore-iface=</varname></term>
+ <listitem>
+ <para>
+ Takes a boolean argument. This option controls how
+ connections with I/O Controllers (IOC) are made.
+ </para>
+
+ <para>
+ There is no guarantee that there will be a route to
+ reach that IOC. However, we can use the socket
+ option SO_BINDTODEVICE to force the connection to be
+ made on a specific interface instead of letting the
+ routing tables decide where to make the connection.
+ </para>
+
+ <para>
+ This option determines whether <code>stacd</code> will use
+ SO_BINDTODEVICE to force connections on an interface
+ or just rely on the routing tables. The default is
+ to use SO_BINDTODEVICE, in other words, <code>stacd</code> does
+ not ignore the interface.
+ </para>
+
+ <para>
+ BACKGROUND:
+ By default, <code>stacd</code> will connect to IOCs on the same
+ interface that was used to retrieve the discovery
+ log pages. If stafd discovers a DC on an interface
+ using mDNS, and stafd connects to that DC and
+ retrieves the log pages, it is expected that the
+ storage subsystems listed in the log pages are
+ reachable on the same interface where the DC was
+ discovered.
+ </para>
+
+ <para>
+ For example, let's say a DC is discovered on
+ interface ens102. Then all the subsystems listed in
+ the log pages retrieved from that DC must be
+ reachable on interface ens102. If this doesn't work,
+ for example you cannot "ping -I ens102 [storage-ip]",
+ then the most likely explanation is that proxy arp
+ is not enabled on the switch that the host is
+ connected to on interface ens102. Whatever you do,
+ resist the temptation to manually set up the routing
+ tables or to add alternate routes going over a
+ different interface than the one where the DC is
+ located. That simply won't work. Make sure proxy arp
+ is enabled on the switch first.
+ </para>
+
+ <para>
+ Setting routes won't work because, by default, <code>stacd</code>
+ uses the SO_BINDTODEVICE socket option when it
+ connects to IOCs. This option is used to force a
+ socket connection to be made on a specific interface
+ instead of letting the routing tables decide where
+ to connect the socket. Even if you were to manually
+ configure an alternate route on a different interface,
+ the connections (i.e. host to IOC) will still be
+ made on the interface where the DC was discovered by
+ stafd.
+ </para>
+
+ <para>
+ Defaults to <parameter>false</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>[I/O controller connection management] section</title>
+ <para>
+ Connectivity between hosts and subsystems in a fabric is
+ controlled by Fabric Zoning. Entities that share a common
+ zone (i.e., are zoned together) are allowed to discover each
+ other and establish connections between them. Fabric Zoning is
+ configured on Discovery Controllers (DC). Users can add/remove
+ controllers and/or hosts to/from zones.
+ </para>
+
+ <para>
+ Hosts have no direct knowledge of the Fabric Zoning configuration
+ that is active on a given DC. As a result, if a host is impacted
+ by a Fabric Zoning configuration change, it will be notified of
+ the connectivity configuration change by the DC via Asynchronous
+ Event Notifications (AEN).
+ </para>
+
+ <table frame='all'>
+ <title>List of terms used in this section:</title>
+ <tgroup cols="2" align='left' colsep='1' rowsep='1'>
+ <thead>
+ <row>
+ <entry>Term</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>AEN</entry>
+ <entry>Asynchronous Event Notification. A CQE (Completion Queue Entry) for an Asynchronous Event Request that was previously transmitted by the host to a Discovery Controller. AENs are used by DCs to notify hosts that a change (e.g., a connectivity configuration change) has occurred.</entry>
+ </row>
+
+ <row>
+ <entry>DC</entry>
+ <entry>Discovery Controller.</entry>
+ </row>
+
+ <row>
+ <entry>DLP</entry>
+ <entry>Discovery Log Page. A host will issue a Get Log Page command to retrieve the list of controllers it may connect to.</entry>
+ </row>
+
+ <row>
+ <entry>DLPE</entry>
+ <entry><simpara>
+ Discovery Log Page Entry. The response
+ to a Get Log Page command contains a list of DLPEs identifying
+ each controller that the host is allowed to connect with.
+ </simpara><simpara>
+ Note that DLPEs may contain both I/O Controllers (IOCs)
+ and Discovery Controllers (DCs). DCs listed in DLPEs
+ are called referrals. <code>stacd</code> only deals with IOCs.
+ Referrals (DCs) are handled by <code>stafd</code>.
+ </simpara>
+ </entry>
+ </row>
+
+ <row>
+ <entry>IOC</entry>
+ <entry>I/O Controller.</entry>
+ </row>
+
+ <row>
+ <entry>Manual Config</entry>
+ <entry>Refers to manually adding entries to <filename>stacd.conf</filename> with the <varname>controller=</varname> parameter.</entry>
+ </row>
+
+ <row>
+ <entry>Automatic Config</entry>
+ <entry>Refers to receiving configuration from a DC as DLPEs</entry>
+ </row>
+
+ <row>
+ <entry>External Config</entry>
+ <entry>Refers to configuration done outside of the <code>nvme-stas</code> framework, for example using <code>nvme-cli</code> commands</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+
+ <para>
+ DCs notify hosts of connectivity configuration changes by sending
+ AENs indicating a "Discovery Log" change. The host uses these AENs as
+ a trigger to issue a Get Log Page command. The response to this command
+ is used to update the list of DLPEs containing the controllers
+ the host is allowed to access.
+ Upon reception of the current DLPEs, the host will determine
+ whether DLPEs were added and/or removed, which will trigger the
+ addition and/or removal of controller connections. This happens in real time
+ and may affect active connections to controllers including controllers
+ that support I/O operations (IOCs). A host that was previously
+ connected to an IOC may suddenly be told that it is no longer
+ allowed to connect to that IOC and should disconnect from it.
+ </para>
+
+ <formalpara><title>IOC connection creation</title>
+ <para>
+ There are 3 ways to configure IOC connections on a host:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>
+ Manual Config by adding <varname>controller=</varname> entries
+ to the <literal>[Controllers]</literal> section (see below).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Automatic Config received in the form of
+ DLPEs from a remote DC.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ External Config using <code>nvme-cli</code> (e.g. "<code>nvme connect</code>")
+ </para>
+ </listitem>
+ </orderedlist>
+ </formalpara>
+
+ <formalpara><title>IOC connection removal/prevention</title>
+ <para>
+ There are 3 ways to remove (or prevent) connections to an IOC:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>
+ Manual Config.
+ <orderedlist numeration='lowerroman'>
+ <listitem>
+ <para>
+ by adding <varname>exclude=</varname> entries to
+ the <literal>[Controllers]</literal> section (see below).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ by removing <varname>controller=</varname> entries
+ from the <literal>[Controllers]</literal> section.
+ </para>
+ </listitem>
+ </orderedlist>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Automatic Config. As explained above, a host gets a
+ new list of DLPEs upon connectivity configuration
+ changes. On DLPE removal, the host should remove the
+ connection to the IOC matching that DLPE. This
+ behavior is configurable using the
+ <varname>disconnect-scope=</varname> parameter
+ described below.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ External Config using <code>nvme-cli</code> (e.g. "<code>nvme
+ disconnect</code>" or "<code>nvme disconnect-all</code>")
+ </para>
+ </listitem>
+ </orderedlist>
+ </formalpara>
+
+ <para>
+ The decision by the host to automatically disconnect from an
+ IOC following connectivity configuration changes is controlled
+ by two parameters: <code>disconnect-scope</code>
+ and <code>disconnect-trtypes</code>.
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><varname>disconnect-scope=</varname></term>
+ <listitem>
+ <para>
+ Takes one of: <parameter>only-stas-connections</parameter>,
+ <parameter>all-connections-matching-disconnect-trtypes</parameter>, or <parameter>no-disconnect</parameter>.
+ </para>
+
+ <para>
+ In theory, hosts should only connect to IOCs that have
+ been zoned for them. Connections to IOCs that a host
+ is not zoned to have access to should simply not exist.
+ In practice, however, users may not want hosts to
+ disconnect from all IOCs in reaction to connectivity
+ configuration changes (or at least for some of the IOC
+ connections).
+ </para>
+
+ <para>
+ Some users may prefer for IOC connections to be "sticky"
+ and only be removed manually (<code>nvme-cli</code> or
+ <varname>exclude=</varname>) or removed by a system
+ reboot. Specifically, they don't want IOC connections
+ to be removed unexpectedly on DLPE removal. These users
+ may want to set <varname>disconnect-scope</varname>
+ to <parameter>no-disconnect</parameter>.
+ </para>
+
+ <para>
+ It is important to note that when IOC connections
+ are removed, ongoing I/O transactions will be
+ terminated immediately. There is no way to tell what
+ happens to the data being exchanged when such an abrupt
+ termination happens. If a host was in the middle of writing
+ to a storage subsystem, there is a chance that outstanding
+ I/O operations may not successfully complete.
+ </para>
+
+ <refsect3>
+ <title>Values:</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>only-stas-connections</parameter></term>
+ <listitem>
+ <para>
+ Only remove connections previously made by <code>stacd</code>.
+ </para>
+ <para>
+ In this mode, when a DLPE is removed as a result of
+ connectivity configuration changes, the corresponding
+ IOC connection will be removed by <code>stacd</code>.
+ </para>
+ <para>
+ Connections to IOCs made externally, e.g. using <code>nvme-cli</code>,
+ will not be affected, unless they happen to be duplicates
+ of connections made by <code>stacd</code>. It's simply not
+ possible for <code>stacd</code> to tell that a connection
+ was previously made with <code>nvme-cli</code> (or any other external tool).
+ So, it's good practice to avoid duplicating
+ configuration between <code>stacd</code> and external tools.
+ </para>
+ <para>
+ Users wanting to persist some of their IOC connections
+ regardless of connectivity configuration changes should not use
+ <code>nvme-cli</code> to make those connections. Instead,
+ they should hard-code them in <filename>stacd.conf</filename>
+ with the <varname>controller=</varname> parameter. Using the
+ <varname>controller=</varname> parameter is the only way for a user
+ to tell <code>stacd</code> that a connection must be made and
+ not be deleted "<emphasis>no-matter-what</emphasis>".
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><parameter>all-connections-matching-disconnect-trtypes</parameter></term>
+ <listitem>
+ <para>
+ All connections that match the transport type specified by
+ <varname>disconnect-trtypes=</varname>, whether they were
+ made automatically by <code>stacd</code> or externally
+ (e.g., <code>nvme-cli</code>), will be audited and are
+ subject to removal on DLPE removal.
+ </para>
+ <para>
+ In this mode, as DLPEs are removed as a result of
+ connectivity configuration changes, the corresponding
+ IOC connections will be removed by the host immediately
+ whether they were made by <code>stacd</code>, <code>nvme-cli</code>,
+ or any other way. Basically, <code>stacd</code> audits
+ <emphasis>all</emphasis> IOC connections matching the
+ transport type specified by <varname>disconnect-trtypes=</varname>.
+ </para>
+ <formalpara><title><emphasis>NOTE</emphasis></title>
+ <para>
+ This mode implies that <code>stacd</code> will
+ only allow Manually Configured or Automatically
+ Configured IOC connections to exist. Externally
+ Configured connections using <code>nvme-cli</code>
+ (or other external mechanism)
+ that do not match any Manual Config
+ (<filename>stacd.conf</filename>)
+ or Automatic Config (DLPEs) will get deleted
+ immediately by <code>stacd</code>.
+ </para>
+ </formalpara>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><parameter>no-disconnect</parameter></term>
+ <listitem>
+ <para>
+ <code>stacd</code> does not disconnect from IOCs
+ when a DPLE is removed or a <varname>controller=</varname>
+ entry is removed from <filename>stacd.conf</filename>.
+ All IOC connections are "sticky".
+ </para>
+
+ <para>
+ Instead, users can remove connections
+ by issuing the <code>nvme-cli</code>
+ command "<code>nvme disconnect</code>", add an
+ <varname>exclude=</varname> entry to
+ <filename>stacd.conf</filename>, or wait
+ until the next system reboot at which time all
+ connections will be removed.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect3>
+
+ <para>
+ Defaults to <parameter>only-stas-connections</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>disconnect-trtypes=</varname></term>
+ <listitem>
+ <para>
+ This parameter only applies when <varname>disconnect-scope</varname>
+ is set to <parameter>all-connections-matching-disconnect-trtypes</parameter>.
+ It limits the scope of the audit to specific transport types.
+ </para>
+
+ <para>
+ Can take the values <parameter>tcp</parameter>,
+ <parameter>rdma</parameter>, <parameter>fc</parameter>, or
+ a combination thereof by separating them with a plus (+) sign.
+ For example: <parameter>tcp+fc</parameter>. No spaces
+ are allowed between values and the plus (+) sign.
+ </para>
+
+ <refsect3>
+ <title>Values:</title>
+ <variablelist>
+ <varlistentry>
+ <term><parameter>tcp</parameter></term>
+ <listitem>
+ <para>
+ Audit TCP connections.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>rdma</parameter></term>
+ <listitem>
+ <para>
+ Audit RDMA connections.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>fc</parameter></term>
+ <listitem>
+ <para>
+ Audit Fibre Channel connections.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect3>
+
+ <para>
+ Defaults to <parameter>tcp</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>connect-attempts-on-ncc=</varname></term>
+ <listitem>
+ <para>
+ The NCC bit (Not Connected to CDC) is a bit returned
+ by the CDC in the EFLAGS field of the DLPE. Only CDCs
+ will set the NCC bit. DDCs will always clear NCC to
+ 0. The NCC bit is a way for the CDC to let hosts
+ know that the subsystem is currently not reachable
+ by the CDC. This may indicate that the subsystem is
+ currently down or that there is an outage on the
+ section of the network connecting the CDC to the
+ subsystem.
+ </para>
+
+ <para>
+ If a host is currently failing to connect to an I/O
+ controller and if the NCC bit associated with that
+ I/O controller is asserted, the host can decide to
+ stop trying to connect to that subsystem until
+ connectivity is restored. This will be indicated by
+ the CDC when it clears the NCC bit.
+ </para>
+
+ <para>
+ The parameter <varname>connect-attempts-on-ncc=</varname>
+ controls whether <code>stacd</code> will take the
+ NCC bit into account when attempting to connect to
+ an I/O Controller. Setting <varname>connect-attempts-on-ncc=</varname>
+ to 0 means that <code>stacd</code> will ignore
+ the NCC bit and will keep trying to connect. Setting
+ <varname>connect-attempts-on-ncc=</varname> to a
+ non-zero value indicates the number of connection
+ attempts that will be made before <code>stacd</code>
+ gives up trying. Note that this value should be set
+ to a value greater than 1. In fact, when set to 1,
+ <code>stacd</code> will automatically use 2 instead.
+ The reason for this is simple. It is possible that a
+ first connect attempt may fail.
+ </para>
+
+
+ <para>
+ Defaults to <parameter>0</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <xi:include href="standard-conf.xml" xpointer="controller"/>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>stacd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/doc/stacd.service.xml b/doc/stacd.service.xml
new file mode 100644
index 0000000..17842af
--- /dev/null
+++ b/doc/stacd.service.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+<refentry id="stacd.service">
+ <refentryinfo>
+ <title>stacd.service</title>
+ <productname>nvme-stas</productname>
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>stacd.service</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>stacd.service</refname>
+ <refpurpose>Systemd unit file for the stacd service</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para>
+ <filename>/usr/lib/systemd/system/stacd.service</filename>
+ </para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>stacd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ is a system service used to automatically connect to I/O controllers
+ discovered by <citerefentry>
+ <refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry>
+ <refentrytitle>stacd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>stas-config.target</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/doc/stacd.xml b/doc/stacd.xml
new file mode 100644
index 0000000..493cfef
--- /dev/null
+++ b/doc/stacd.xml
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY daemon "stacd">
+<!ENTITY deamondesc "STorage Appliance Connector">
+<!ENTITY control "stacctl">
+]>
+
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+
+<refentry id="&daemon;" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>&daemon;</title>
+ <productname>nvme-stas</productname>
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>&daemon;</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>&daemon;</refname>
+ <refpurpose>&deamondesc;</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>&daemon;</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>&daemon;</command>
+ is a system daemon that can be used to automatically connect to
+ NVMe-oF I/O Controllers using the discovery log pages collected by
+ <citerefentry>
+ <refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>. It can also be manually configured with
+ <citerefentry>
+ <refentrytitle>&daemon;.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>
+ to connect to I/O Controllers that otherwise cannot be found
+ automatically.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+ <para>The following options are understood:</para>
+
+ <variablelist>
+ <xi:include href="standard-options.xml" xpointer="help"/>
+ <xi:include href="standard-options.xml" xpointer="version"/>
+ </variablelist>
+
+ <varlistentry>
+ <term><option>-fFILE</option></term>
+ <term><option>--conf-file=FILE</option></term>
+ <listitem>
+ <para>
+ Specify a different configuration file than
+ <citerefentry>
+ <refentrytitle>&daemon;.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>
+ (default: <filename>/etc/stas/&daemon;.conf</filename>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-s</option></term>
+ <term><option>--syslog</option></term>
+ <listitem>
+ <para>
+ Send messages to syslog instead of stdout. Use this when
+ running &daemon; as a daemon. (default: <literal>false</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--tron</option></term>
+ <listitem>
+ <para>Trace ON. (default: <literal>false</literal>)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--idl=FILE</option></term>
+ <listitem>
+ <para>Print D-Bus IDL to FILE and exit.</para>
+ </listitem>
+ </varlistentry>
+ </refsect1>
+
+ <refsect1>
+ <title>Exit status</title>
+ <para>
+ On success, 0 is returned, a non-zero failure code otherwise.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Daemonization</title>
+ <para>
+ &daemon; is managed by <code>systemd</code>. The following
+ operations are supported:
+ </para>
+
+ <table align='left' frame='all'>
+ <tgroup cols="2" align='left' colsep='1' rowsep='1'>
+ <thead>
+ <row>
+ <entry>Command</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry><programlisting>$ systemctl start &daemon; </programlisting></entry>
+ <entry>Start daemon.</entry>
+ </row>
+
+ <row>
+ <entry><programlisting>$ systemctl stop &daemon; </programlisting></entry>
+ <entry>Stop daemon. The <code>SIGTERM</code> signal is used to tell the daemon to stop.</entry>
+ </row>
+
+ <row>
+ <entry><programlisting>$ systemctl restart &daemon; </programlisting></entry>
+ <entry>Effectively a <code>stop</code> + <code>start</code>.</entry>
+ </row>
+
+ <row>
+ <entry><programlisting>$ systemctl reload &daemon; </programlisting></entry>
+ <entry>Reload configuration. This is done in real time without restarting the daemon. The <code>SIGHUP</code> signal is used to tell the daemon to reload its configuration file. Note that configuration parameters that affect connections (e.g. <code>kato</code>), will not apply to existing connections. Only connections established after the configuration was changed will utilize the new configuration parameters.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </refsect1>
+
+ <refsect1>
+ <title>Design</title>
+
+ <para>
+ <command>&daemon;</command> use the <code>GLib</code> main loop.
+ The <code>GLib</code> Python module provides several low-level
+ building blocks that <command>&daemon;</command> requires. In
+ addition, many Python modules "play nice" with <code>GLib</code>
+ such as <code>dasbus</code> (D-Bus package) and <code>pyudev</code>
+ (UDev package). <code>GLib</code> also provides additional components
+ such as timers, signal handlers, and much more.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Configuration</title>
+ <para>
+ <command>&daemon;</command> can automatically set up the I/O
+ connections to discovered storage subsystems. However,
+ <command>&daemon;</command> can also operate in a non-automatic
+ mode based on manually entered configuration. In other words,
+ storage subsystems can be entered in a configuration file named
+ <filename>/etc/stas/&daemon;.conf</filename>.
+ This configuration file also provides additional parameters,
+ as log-level attributes used for debugging purposes.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>D-Bus API</title>
+ <para>
+ The interface to <command>&daemon;</command> is D-Bus.
+ This allows other programs, such as <command>&control;</command>,
+ to communicate with <command>&daemon;</command>. The D-Bus address
+ is <code>org.nvmexpress.stac</code>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry>
+ <refentrytitle>&daemon;.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>&daemon;.service</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>stacctl</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>org.nvmexpress.stac</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>.
+ </para>
+ </refsect1>
+</refentry>
diff --git a/doc/stafctl.xml b/doc/stafctl.xml
new file mode 100644
index 0000000..beb8097
--- /dev/null
+++ b/doc/stafctl.xml
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+<refentry id="stafctl" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>stafctl</title>
+ <productname>nvme-stas</productname>
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>stafctl</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>stafctl</refname>
+ <refpurpose>STorage Appliance Finder (STAF) utility program</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>stafctl</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="req">COMMAND</arg>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>stafctl</command> is a tool that can be used to communicate
+ with the <citerefentry><refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry> daemon to retrieve
+ operational data.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Commands</title>
+ <para>The following commands are understood:</para>
+
+ <variablelist>
+ <xi:include href="standard-options.xml" xpointer="tron"/>
+ <xi:include href="standard-options.xml" xpointer="troff"/>
+ <xi:include href="standard-options.xml" xpointer="status"/>
+
+ <varlistentry>
+ <term><command>ls</command></term>
+ <listitem>
+ <para>
+ Show the list of discovery controllers. This will list
+ all the controllers configured in
+ <citerefentry><refentrytitle>stafd.conf</refentrytitle>
+ <manvolnum>5</manvolnum></citerefentry> as well as those
+ discovered with mDNS service discovery.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>dlp</command></term>
+ <listitem>
+ <para>Show discovery log pages.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>adlp</command></term>
+ <listitem>
+ <para>Show all discovery log pages.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+
+ <para>The following options are understood:</para>
+
+ <variablelist>
+ <xi:include href="standard-options.xml" xpointer="help"/>
+ <xi:include href="standard-options.xml" xpointer="version"/>
+ <xi:include href="standard-options.xml" xpointer="detailed"/>
+ <xi:include href="standard-options.xml" xpointer="transport"/>
+ <xi:include href="standard-options.xml" xpointer="traddr"/>
+ <xi:include href="standard-options.xml" xpointer="trsvcid"/>
+ <xi:include href="standard-options.xml" xpointer="host-traddr"/>
+ <xi:include href="standard-options.xml" xpointer="host-iface"/>
+ <xi:include href="standard-options.xml" xpointer="nqn"/>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Values</title>
+
+ <variablelist>
+ <xi:include href="standard-options.xml" xpointer="TRTYPE-value"/>
+ <xi:include href="standard-options.xml" xpointer="TRADDR-value"/>
+ <xi:include href="standard-options.xml" xpointer="TRSVCID-value"/>
+ <xi:include href="standard-options.xml" xpointer="IFACE-value"/>
+ <xi:include href="standard-options.xml" xpointer="NQN-value"/>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Exit status</title>
+ <para>
+ On success, 0 is returned; otherwise, a non-zero failure code is
+ returned.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>List all the discovery controllers</title>
+ <programlisting>$ stafctl ls
+[{'device': 'nvme0',
+ 'host-iface': '',
+ 'host-traddr': '',
+ 'subsysnqn': 'nqn.2014-08.org.nvmexpress.discovery',
+ 'traddr': '::1',
+ 'transport': 'tcp',
+ 'trsvcid': '8009'}]</programlisting>
+ </example>
+
+ <example>
+ <title>Enable tracing</title>
+ <programlisting>$ stafctl tron</programlisting>
+ </example>
+
+ <example>
+ <title>
+ Show discovery log pages from a specific discovery controller
+ </title>
+
+ <programlisting>$ stafctl dlp --transport tcp --traddr ::1 --trsvcid 8009
+[{'adrfam': 'ipv6',
+ 'asqsz': '32',
+ 'cntlid': '65535',
+ 'portid': '1',
+ 'subnqn': 'nqn.1988-11.com.dell:PowerSANxxx:01:20210225100113-454f73093ceb4847a7bdfc6e34ae8e28',
+ 'subtype': 'nvme',
+ 'traddr': '::1',
+ 'treq': 'disable sqflow',
+ 'trsvcid': '8009',
+ 'trtype': 'tcp'},
+ {'adrfam': 'ipv6',
+ 'asqsz': '32',
+ 'cntlid': '65535',
+ 'portid': '1',
+ 'subnqn': 'nqn.1988-11.com.dell:PowerSANxxx:01:20210225100113-454f73093ceb4847a7bdfc6e34aedead',
+ 'subtype': 'nvme',
+ 'traddr': '::1',
+ 'treq': 'disable sqflow',
+ 'trsvcid': '8009',
+ 'trtype': 'tcp'},
+ {'adrfam': 'ipv6',
+ 'asqsz': '32',
+ 'cntlid': '65535',
+ 'portid': '1',
+ 'subnqn': 'nqn.1988-11.com.dell:PowerSANxxx:01:20210225100113-454f73093ceb4847a7bdfc6e34aebeef',
+ 'subtype': 'nvme',
+ 'traddr': '::1',
+ 'treq': 'disable sqflow',
+ 'trsvcid': '8009',
+ 'trtype': 'tcp'}]</programlisting>
+ </example>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry>
+ <refentrytitle>stafd.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ <citerefentry project="man-pages"/>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/doc/stafd.conf.xml b/doc/stafd.conf.xml
new file mode 100644
index 0000000..da0b842
--- /dev/null
+++ b/doc/stafd.conf.xml
@@ -0,0 +1,280 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+<refentry id="stafd.conf" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>stafd.conf</title>
+ <productname>nvme-stas</productname>
+
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>stafd.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>stafd.conf</refname>
+
+ <refpurpose>
+ <citerefentry project="man-pages">
+ <refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ configuration file
+ </refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para>
+ <filename>/etc/stas/stafd.conf</filename>
+ </para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ When <citerefentry project="man-pages"><refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry> starts up, it reads its
+ configuration from <filename>stafd.conf</filename>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Configuration File Format</title>
+ <para>
+ <filename>stafd.conf</filename> is a plain text file divided into
+ sections, with configuration entries in the style
+ <replaceable>key</replaceable>=<replaceable>value</replaceable>.
+ Spaces immediately before or after the <literal>=</literal> are
+ ignored. Empty lines are ignored as well as lines starting with
+ <literal>#</literal>, which may be used for commenting.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+
+ <refsect2>
+ <title>[Global] section</title>
+ <para>
+ The following options are available in the
+ <literal>[Global]</literal> section:
+ </para>
+
+ <variablelist>
+ <xi:include href="standard-conf.xml" xpointer="tron"/>
+ <xi:include href="standard-conf.xml" xpointer="hdr-digest"/>
+ <xi:include href="standard-conf.xml" xpointer="data-digest"/>
+ <xi:include href="standard-conf.xml" xpointer="kato"/>
+ <xi:include href="standard-conf.xml" xpointer="ip-family"/>
+ <xi:include href="standard-conf.xml" xpointer="queue-size"/>
+ <xi:include href="standard-conf.xml" xpointer="reconnect-delay"/>
+ <xi:include href="standard-conf.xml" xpointer="ctrl-loss-tmo"/>
+ <xi:include href="standard-conf.xml" xpointer="disable-sqflow"/>
+
+ <varlistentry>
+ <term><varname>ignore-iface=</varname></term>
+ <listitem>
+ <para>
+ Takes a boolean argument. This option controls how
+ connections with Discovery Controllers (DC) are made.
+ </para>
+
+ <para>
+ DCs are automatically discovered using DNS-SD/mDNS.
+ mDNS provides the DC's IP address and the interface
+ on which the DC was discovered.
+ </para>
+
+ <para>
+ There is no guarantee that there will be a route to
+ reach that DC. However, we can use the socket option
+ SO_BINDTODEVICE to force the connection to be made
+ on a specific interface instead of letting the
+ routing tables decide where to make the connection.
+ </para>
+
+ <para>
+ This option determines whether <code>stafd</code>
+ will use SO_BINDTODEVICE to force connections on an
+ interface or just rely on the routing tables. The
+ default is to use SO_BINDTODEVICE, in other words,
+ <code>stafd</code> does not ignore the interface by
+ default.
+ </para>
+ <para>
+ Defaults to <parameter>false</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>pleo=</varname></term>
+ <listitem>
+ <para>
+ Port Local Entries Only. Takes a string argument
+ <parameter>enabled</parameter> or
+ <parameter>disabled</parameter>. This option is sent in
+ the LSP field (Log SPecific) of the Get Discovery Log
+ Page (DLP) command. It is used by <code>stafd</code> to
+ tell Discovery Controllers (DC) whether the response to
+ a Get DLP command should contain all the NVM subsystems
+ or only those reachable by the host on the interface
+ where the Get DLP command was issued by the host.
+ </para>
+
+ <para>
+ This parameter was introduced in TP8010. When
+ <varname>pleo=</varname><parameter>enabled</parameter>,
+ then the DC shall return records for only NVM subsystem
+ ports that are presented through the same NVM subsystem
+ port that received the Get Log Page command. When
+ <varname>pleo=</varname><parameter>disabled</parameter>,
+ then the DC may return all the NVM subsystem ports
+ that it holds, even those that can only be reached
+ on NVM subsystem ports that did not receive the Get
+ Log Page command. In other words, the host may not
+ even be able to reach those subsystems.
+ </para>
+
+ <para>
+ Defaults to <parameter>enabled</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>[Service Discovery] section</title>
+
+ <para>
+ The following options are available in the
+ <literal>[Service Discovery]</literal> section:
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><varname>zeroconf=</varname></term>
+
+ <listitem>
+ <para>
+ Enable zeroconf provisioning using DNS-SD/mDNS.
+ Takes a string argument <parameter>enabled</parameter> or
+ <parameter>disabled</parameter>.
+ </para>
+ <para>
+ When <parameter>enabled</parameter>, the default,
+ <code>stafd</code> makes a request with the
+ Avahi daemon to locate Discovery Controllers using
+ DNS-SD/mDNS.
+ </para>
+ <para>
+ Discovery Controllers that support zeroconf advertize
+ themselves over mDNS with the service type
+ <literal>_nvme-disc._tcp</literal>.
+ </para>
+ <para>
+ Defaults to <parameter>true</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>[Discovery controller connection management] section</title>
+
+ <para>
+ The following options are available in the
+ <literal>[Discovery controller connection management]</literal> section:
+ </para>
+
+ <varlistentry>
+ <term><varname>persistent-connections=</varname></term>
+ <listitem>
+ <para>
+ Takes a boolean argument. Whether connections to
+ Discovery Controllers (DC) are persistent. When
+ true, connections initiated by stafd will persists
+ even when stafd is stopped. When
+ <parameter>false</parameter>, <code>stafd</code>
+ will disconnect from all DCs it is connected to on
+ exit.
+ </para>
+ <para>
+ Defaults to <parameter>false</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>zeroconf-connections-persistence=</varname></term>
+ <listitem>
+ <para>
+ Takes a unit-less value in seconds, or a time span value
+ such as "72hours" or "5days". A value of 0 means no
+ persistence. In other words, configuration acquired through
+ zeroconf (mDNS service discovery) will be removed
+ immediately when mDNS no longer reports the presence of
+ a Discovery Controller (DC) and connectivity to that DC
+ is lost. A value of -1 means that configuration acquired
+ through zeroconf will persist forever.
+ </para>
+
+ <para>
+ This is used for the case where a DC that was discovered
+ through mDNS service discovery no longer advertises
+ itself through mDNS and can no longer be connected to.
+ For example, the DC had some catastrophic failure
+ (e.g. power surge) and needs to be replaced. In that
+ case, the connection to that DC can never be restored
+ and a replacement DC will be needed. The replacement
+ DC will likely have a different NQN (or IP address).
+ In that scenario, the host won't be able to determine
+ that the old DC is not coming back. It won't know either
+ that a newly discovered DC is really the replacement for
+ the old one. For that reason, the host needs a way to
+ "age" zeroconf-acquired configuration and remove it
+ automatically after a certain amount of time. This is
+ what this parameter is for.
+ </para>
+
+ <para>
+ Defaults to <parameter>72hours</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </refsect2>
+
+ <xi:include href="standard-conf.xml" xpointer="controller"/>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/doc/stafd.service.xml b/doc/stafd.service.xml
new file mode 100644
index 0000000..bc9ba82
--- /dev/null
+++ b/doc/stafd.service.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+<refentry id="stafd.service">
+ <refentryinfo>
+ <title>stafd.service</title>
+ <productname>nvme-stas</productname>
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>stafd.service</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>stafd.service</refname>
+ <refpurpose>Systemd unit file for the stafd service</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para>
+ <filename>/usr/lib/systemd/system/stafd.service</filename>
+ </para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ is a system service used to automatically locate NVMe-oF Discovery
+ Controllers using mDNS service discovery.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry>
+ <refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>stas-config.target</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/doc/stafd.xml b/doc/stafd.xml
new file mode 100644
index 0000000..10e454e
--- /dev/null
+++ b/doc/stafd.xml
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY daemon "stafd">
+<!ENTITY deamondesc "STorage Appliance Finder">
+<!ENTITY control "stafctl">
+]>
+
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+
+<refentry id="&daemon;" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>&daemon;</title>
+ <productname>nvme-stas</productname>
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>&daemon;</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>&daemon;</refname>
+ <refpurpose>&deamondesc;</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>&daemon;</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>&daemon;</command>
+ is a system daemon that can be used to automatically locate and
+ connect to NVMe-oF Discovery Controllers using mDNS service discovery.
+ It can also be manually configured with
+ <citerefentry>
+ <refentrytitle>&daemon;.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>
+ to connect to Discovery Controllers that cannot be located using
+ mDNS.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+ <para>The following options are understood:</para>
+
+ <variablelist>
+ <xi:include href="standard-options.xml" xpointer="help"/>
+ <xi:include href="standard-options.xml" xpointer="version"/>
+ </variablelist>
+
+ <varlistentry>
+ <term><option>-fFILE</option></term>
+ <term><option>--conf-file=FILE</option></term>
+ <listitem>
+ <para>
+ Specify a different configuration file than
+ <citerefentry>
+ <refentrytitle>&daemon;.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>
+ (default: <filename>/etc/stas/&daemon;.conf</filename>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-s</option></term>
+ <term><option>--syslog</option></term>
+ <listitem>
+ <para>
+ Send messages to syslog instead of stdout. Use this when
+ running &daemon; as a daemon. (default: <literal>false</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--tron</option></term>
+ <listitem>
+ <para>Trace ON. (default: <literal>false</literal>)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--idl=FILE</option></term>
+ <listitem>
+ <para>Print D-Bus IDL to FILE and exit.</para>
+ </listitem>
+ </varlistentry>
+ </refsect1>
+
+ <refsect1>
+ <title>Exit status</title>
+ <para>
+ On success, 0 is returned, a non-zero failure code otherwise.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Daemonization</title>
+ <para>
+ &daemon; is managed by <code>systemd</code>. The following
+ operations are supported:
+ </para>
+
+ <table frame='all'>
+ <tgroup cols="2" align='left' colsep='1' rowsep='1'>
+ <thead>
+ <row>
+ <entry>Command</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry><programlisting>$ systemctl start &daemon; </programlisting></entry>
+ <entry>Start daemon.</entry>
+ </row>
+
+ <row>
+ <entry><programlisting>$ systemctl stop &daemon; </programlisting></entry>
+ <entry>Stop daemon. The <code>SIGTERM</code> signal is used to tell the daemon to stop.</entry>
+ </row>
+
+ <row>
+ <entry><programlisting>$ systemctl restart &daemon; </programlisting></entry>
+ <entry>Effectively a <code>stop</code> + <code>start</code>.</entry>
+ </row>
+
+ <row>
+ <entry><programlisting>$ systemctl reload &daemon; </programlisting></entry>
+ <entry>Reload configuration. This is done in real time without restarting the daemon. The <code>SIGHUP</code> signal is used to tell the daemon to reload its configuration file. Note that configuration parameters that affect connections (e.g. <code>kato</code>), will not apply to existing connections. Only connections established after the configuration was changed will utilize the new configuration parameters.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </refsect1>
+
+ <refsect1>
+ <title>Design</title>
+
+ <para>
+ <command>&daemon;</command> use the <code>GLib</code> main loop.
+ The <code>GLib</code> Python module provides several low-level
+ building blocks that <command>&daemon;</command> requires. In
+ addition, many Python modules "play nice" with <code>GLib</code>
+ such as <code>dasbus</code> (D-Bus package) and <code>pyudev</code>
+ (UDev package). <code>GLib</code> also provides additional components
+ such as timers, signal handlers, and much more.
+ </para>
+
+ <para>
+ <command>&daemon;</command> connects to the <code>avahi-daemon</code>
+ using D-Bus. The <code>avahi-daemon</code>, or simply
+ <emphasis>Avahi</emphasis>, is an mDNS discovery service used for
+ zero-configuration networking (zeroconf). <command>&daemon;</command>
+ registers with Avahi to automatically locate Central Discovery
+ Controllers (CDC) and Direct Discovery Controllers (DDC). When Avahi
+ finds Discovery Controllers (DC), it notifies <command>&daemon;</command>
+ which connects to the DC with the help of the <code>libnvme</code> library.
+ Once a connection to a DC is established, <command>&daemon;</command>
+ can retrieve the <emphasis>discovery log pages</emphasis> from
+ that DC and cache them in memory.
+ </para>
+ </refsect1>
+
+
+ <refsect1>
+ <title>Configuration</title>
+ <para>
+ <command>&daemon;</command> can automatically locate discovery
+ controllers (DC) with the help of Avahi and connect to them. However,
+ <command>&daemon;</command> can also operate in a non-automatic
+ mode based on manually entered configuration. In other words,
+ DCs can be entered in a configuration named
+ <filename>/etc/stas/&daemon;.conf</filename>.
+ This configuration file also provides additional parameters, such
+ as log-level attributes used for debugging purposes.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>D-Bus API</title>
+ <para>
+ The interface to <command>&daemon;</command> is D-Bus.
+ This allows other programs, such as <command>&control;</command>,
+ to communicate with <command>&daemon;</command>. The D-Bus address
+ is <code>org.nvmexpress.staf</code>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry>
+ <refentrytitle>&daemon;.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>&daemon;.service</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>stafctl</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>org.nvmexpress.staf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>.
+ </para>
+ </refsect1>
+</refentry>
diff --git a/doc/standard-conf.xml b/doc/standard-conf.xml
new file mode 100644
index 0000000..50d4fe5
--- /dev/null
+++ b/doc/standard-conf.xml
@@ -0,0 +1,562 @@
+<?xml version="1.0"?>
+<!DOCTYPE refsection PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+
+<root>
+
+ <variablelist>
+ <varlistentry id='tron'>
+ <term><varname>tron=</varname></term>
+
+ <listitem id='tron-text'>
+ <para>
+ Trace ON. Takes a boolean argument. If <parameter>true</parameter>,
+ enables full code tracing. The trace will be displayed in
+ the system log such as systemd's journal. Defaults to
+ <parameter>false</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='hdr-digest'>
+ <term><varname>hdr-digest=</varname></term>
+
+ <listitem id='hdr-digest-text'>
+ <para>
+ Enable Protocol Data Unit (PDU) Header Digest. Takes a
+ boolean argument. NVMe/TCP facilitates an optional PDU
+ Header digest. Digests are calculated using the CRC32C
+ algorithm. If <parameter>true</parameter>, Header Digests
+ are inserted in PDUs and checked for errors. Defaults to
+ <parameter>false</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='data-digest'>
+ <term><varname>data-digest=</varname></term>
+
+ <listitem id='data-digest-text'>
+ <para>
+ Enable Protocol Data Unit (PDU) Data Digest. Takes a
+ boolean argument. NVMe/TCP facilitates an optional PDU
+ Data digest. Digests are calculated using the CRC32C
+ algorithm. If <parameter>true</parameter>, Data Digests
+ are inserted in PDUs and checked for errors. Defaults to
+ <parameter>false</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='kato'>
+ <term><varname>kato=</varname></term>
+
+ <listitem id='kato-text'>
+ <para>
+ Keep Alive Timeout (KATO) in seconds. Takes an unsigned
+ integer. This field specifies the timeout value for the Keep
+ Alive feature in seconds. Defaults to 30 seconds for
+ Discovery Controller connections and 120 seconds for I/O
+ Controller connections.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='ip-family'>
+ <term><varname>ip-family=</varname></term>
+
+ <listitem id='ip-family-text'>
+ <para>
+ Takes a string argument. With this you can specify
+ whether IPv4, IPv6, or both are supported when
+ connecting to a Controller. Connections will not be
+ attempted to IP addresses (whether discovered or
+ manually configured with <varname>controller=</varname>)
+ disabled by this option. If an invalid value
+ is entered, then the default (see below) will apply.
+ </para>
+
+ <para>
+ Choices are <parameter>ipv4</parameter>, <parameter>ipv6</parameter>, or <parameter>ipv4+ipv6</parameter>.
+ </para>
+
+ <para>
+ Defaults to <parameter>ipv4+ipv6</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='queue-size'>
+ <term><varname>queue-size=</varname></term>
+
+ <listitem id='queue-size-text'>
+ <para>
+ Takes a value in the range 16...1024.
+ </para>
+
+ <para>
+ Overrides the default number of elements in the I/O queues
+ created by the driver. This option will be ignored for
+ discovery, but will be passed on to the subsequent connect
+ call.
+ </para>
+
+ <para>Note: This parameter is identical to that provided by nvme-cli.</para>
+
+ <para>
+ Defaults to <parameter>128</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='reconnect-delay'>
+ <term><varname>reconnect-delay=</varname></term>
+
+ <listitem id='reconnect-delay-text'>
+ <para>
+ Takes a value in the range 1 to N seconds.
+ </para>
+
+ <para>
+ Overrides the default delay before reconnect is attempted
+ after a connect loss.
+ </para>
+
+ <para>Note: This parameter is identical to that provided by nvme-cli.</para>
+
+ <para>
+ Defaults to <parameter>10</parameter>. Retry to connect every 10 seconds.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='ctrl-loss-tmo'>
+ <term><varname>ctrl-loss-tmo=</varname></term>
+
+ <listitem id='ctrl-loss-tmo-text'>
+ <para>
+ Takes a value in the range -1, 0, ..., N seconds. -1 means
+ retry forever. 0 means do not retry.
+ </para>
+
+ <para>
+ Overrides the default controller loss timeout period (in seconds).
+ </para>
+
+ <para>Note: This parameter is identical to that provided by nvme-cli.</para>
+
+ <para>
+ Defaults to <parameter>600</parameter> seconds (10 minutes).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='disable-sqflow'>
+ <term><varname>disable-sqflow=</varname></term>
+
+ <listitem id='disable-sqflow-text'>
+ <para>
+ Takes a boolean argument. Disables SQ flow control to omit
+ head doorbell update for submission queues when sending nvme
+ completions.
+ </para>
+
+ <para>Note: This parameter is identical to that provided by nvme-cli.</para>
+
+ <para>
+ Defaults to <parameter>false</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <refsect2 id='controller'>
+ <title>[Controllers] section</title>
+
+ <para>The following options are available in the
+ <literal>[Controllers]</literal> section:</para>
+
+ <varlistentry>
+ <term><varname>controller=</varname></term>
+
+ <listitem id='controller-text'>
+ <para>
+ Controllers are specified with the <varname>controller</varname>
+ option. This option may be specified more than once to specify
+ more than one controller. The format is one line per Controller
+ composed of a series of fields separated by semi-colons as follows:
+ </para>
+
+ <programlisting>controller=transport=[trtype];traddr=[traddr];trsvcid=[trsvcid];host-traddr=[traddr],host-iface=[iface];nqn=[nqn]
+ </programlisting>
+
+ <refsect3>
+ <title>Fields</title>
+ <variablelist>
+ <varlistentry id='transport'>
+ <term><varname>transport=</varname></term>
+
+ <listitem id='transport-text'>
+ <para>
+ This is a mandatory field that specifies the
+ network fabric being used for a
+ NVMe-over-Fabrics network. Current
+ <parameter>trtype</parameter> values understood
+ are:
+ </para>
+
+ <table id='transport-types'>
+ <title>Transport type</title>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>trtype</entry>
+ <entry>Definition</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>rdma</entry>
+ <entry>
+ The network fabric is an rdma network (RoCE, iWARP, Infiniband, basic rdma, etc)
+ </entry>
+ </row>
+
+ <row>
+ <entry>fc</entry>
+ <entry>
+ The network fabric is a Fibre Channel network.
+ </entry>
+ </row>
+
+ <row>
+ <entry>tcp</entry>
+ <entry>
+ The network fabric is a TCP/IP network.
+ </entry>
+ </row>
+
+ <row>
+ <entry>loop</entry>
+ <entry>
+ Connect to a NVMe over Fabrics target on the local host
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='tradd'>
+ <term>
+ <varname>traddr=</varname>
+ </term>
+
+ <listitem>
+ <para>
+ This is a mandatory field that specifies the
+ network address of the Controller. For
+ transports using IP addressing (e.g. rdma)
+ this should be an IP-based address (ex.
+ IPv4, IPv6). It could also be a resolvable
+ host name (e.g. localhost).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='trsvcid'>
+ <term>
+ <varname>trsvcid=</varname>
+ </term>
+
+ <listitem>
+ <para>
+ This is an optional field that specifies the
+ transport service id. For transports using
+ IP addressing (e.g. rdma, tcp) this field is
+ the port number.
+ </para>
+
+ <para>
+ Depending on the transport type, this field
+ will default to either 8009 or 4420 as
+ follows.
+ </para>
+
+ <para>
+ UDP port 4420 and TCP port 4420 have been
+ assigned by IANA for use by NVMe over
+ Fabrics. NVMe/RoCEv2 controllers use UDP
+ port 4420 by default. NVMe/iWARP controllers
+ use TCP port 4420 by default.
+ </para>
+
+ <para>
+ TCP port 4420 has been assigned for use by
+ NVMe over Fabrics and TCP port 8009 has been
+ assigned by IANA for use by NVMe over
+ Fabrics discovery. TCP port 8009 is the
+ default TCP port for NVMe/TCP discovery
+ controllers. There is no default TCP port
+ for NVMe/TCP I/O controllers, the Transport
+ Service Identifier (TRSVCID) field in the
+ Discovery Log Entry indicates the TCP port
+ to use.
+ </para>
+
+ <para>
+ The TCP ports that may be used for NVMe/TCP
+ I/O controllers include TCP port 4420, and
+ the Dynamic and/or Private TCP ports (i.e.,
+ ports in the TCP port number range from
+ 49152 to 65535). NVMe/TCP I/O controllers
+ should not use TCP port 8009. TCP port 4420
+ shall not be used for both NVMe/iWARP and
+ NVMe/TCP at the same IP address on the same
+ network.
+ </para>
+
+ <para>
+ Ref:
+ <ulink
+ url="https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=nvme">
+ IANA Service names port numbers
+ </ulink>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='nqn'>
+ <term><varname>nqn=</varname></term>
+ <listitem>
+ <para>
+ This field specifies the Controller's NVMe
+ Qualified Name.
+ </para>
+ <para>
+ This field is mandatory for I/O Controllers, but is optional for
+ Discovery Controllers (DC). For the latter, the NQN will default
+ to the well-known DC NQN: <literal>nqn.2014-08.org.nvmexpress.discovery</literal>
+ if left undefined.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='host-traddr'>
+ <term><varname>host-traddr=</varname></term>
+ <listitem>
+ <para>
+ This is an optional field that specifies the
+ network address used on the host to connect
+ to the Controller. For TCP, this sets the
+ source address on the socket.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='host-iface'>
+ <term><varname>host-iface=</varname></term>
+ <listitem>
+ <para>
+ This is an optional field that specifies the
+ network interface used on the host to
+ connect to the Controller (e.g. IP eth1,
+ enp2s0, enx78e7d1ea46da). This forces the
+ connection to be made on a specific
+ interface instead of letting the system
+ decide.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='dhchap-ctrl-secret'>
+ <term><varname>dhchap-ctrl-secret=</varname></term>
+ <listitem>
+ <para>
+ This is an optional field that specifies the
+ NVMe In-band authentication controller secret
+ (i.e. key) for bi-directional authentication;
+ needs to be in ASCII format as specified in
+ NVMe 2.0 section 8.13.5.8 'Secret representation'.
+ Bi-directional authentication will be attempted
+ when present.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='hdr-digest-override'>
+ <term><varname>hdr-digest=</varname></term>
+ <listitem>
+ <para>
+ See definition in [Global] section. This is
+ an optional field used to override the value
+ specified in the [Global] section.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='data-digest-override'>
+ <term><varname>data-digest=</varname></term>
+ <listitem>
+ <para>
+ See definition in [Global] section. This is
+ an optional field used to override the value
+ specified in the [Global] section.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='nr-io-queues-override'>
+ <term><varname>nr-io-queues=</varname></term>
+ <listitem>
+ <para>
+ See definition in [Global] section. This is
+ an optional field used to override the value
+ specified in the [Global] section.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='nr-write-queues-override'>
+ <term><varname>nr-write-queues=</varname></term>
+ <listitem>
+ <para>
+ See definition in [Global] section. This is
+ an optional field used to override the value
+ specified in the [Global] section.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='nr-poll-queues-override'>
+ <term><varname>nr-poll-queues=</varname></term>
+ <listitem>
+ <para>
+ See definition in [Global] section. This is
+ an optional field used to override the value
+ specified in the [Global] section.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='queue-size-override'>
+ <term><varname>queue-size=</varname></term>
+ <listitem>
+ <para>
+ See definition in [Global] section. This is
+ an optional field used to override the value
+ specified in the [Global] section.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='kato-override'>
+ <term><varname>kato=</varname></term>
+ <listitem>
+ <para>
+ See definition in [Global] section. This is
+ an optional field used to override the value
+ specified in the [Global] section.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='reconnect-delay-override'>
+ <term><varname>reconnect-delay=</varname></term>
+ <listitem>
+ <para>
+ See definition in [Global] section. This is
+ an optional field used to override the value
+ specified in the [Global] section.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='ctrl-loss-tmo-override'>
+ <term><varname>ctrl-loss-tmo=</varname></term>
+ <listitem>
+ <para>
+ See definition in [Global] section. This is
+ an optional field used to override the value
+ specified in the [Global] section.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='disable-sqflow-override'>
+ <term><varname>disable-sqflow=</varname></term>
+ <listitem>
+ <para>
+ See definition in [Global] section. This is
+ an optional field used to override the value
+ specified in the [Global] section.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect3>
+
+ <para>
+ Examples:
+ <programlisting>controller = transport=tcp;traddr=localhost;trsvcid=8009
+controller = transport=tcp;traddr=2001:db8::370:7334;host-iface=enp0s8
+controller = transport=fc;traddr=nn-0x204600a098cbcac6:pn-0x204700a098cbcac6
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>exclude=</varname></term>
+
+ <listitem id='exclude-text'>
+ <para>
+ Controllers that should be excluded can be specified with the
+ <varname>exclude=</varname> option. Using mDNS to
+ automatically discover and connect to controllers, can result
+ in unintentional connections being made. This keyword allows
+ configuring the controllers that should not be connected to.
+ </para>
+
+ <para>
+ The syntax is the same as for "controller", except that only
+ <parameter>transport</parameter>, <parameter>traddr</parameter>,
+ <parameter>trsvcid</parameter>, <parameter>nqn</parameter>, and
+ <parameter>host-iface</parameter> apply. Multiple
+ <varname>exclude=</varname> keywords may appear in the config
+ file to specify more than 1 excluded controller.
+ </para>
+
+ <para>
+ Note 1: A minimal match approach is used to eliminate unwanted
+ controllers. That is, you do not need to specify all the
+ parameters to identify a controller. Just specifying the
+ <parameter>host-iface</parameter>, for example, can be used to
+ exclude all controllers on an interface.
+ </para>
+
+ <para>
+ Note 2: <varname>exclude=</varname> takes precedence over
+ <varname>controller</varname>. A controller specified by the
+ <varname>controller</varname> keyword, can be eliminated by
+ the <varname>exclude=</varname> keyword.
+ </para>
+
+ <para>
+ Examples:
+ <programlisting>exclude = transport=tcp;traddr=fe80::2c6e:dee7:857:26bb # Eliminate a specific address
+exclude = host-iface=enp0s8 # Eliminate everything on this interface
+ </programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </refsect2>
+</root>
diff --git a/doc/standard-options.xml b/doc/standard-options.xml
new file mode 100644
index 0000000..8ae3f8b
--- /dev/null
+++ b/doc/standard-options.xml
@@ -0,0 +1,163 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+
+<variablelist>
+ <varlistentry id='help'>
+ <term><option>-h</option></term>
+ <term><option>--help</option></term>
+
+ <listitem id='help-text'>
+ <para>Print the help text and exit.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry id='version'>
+ <term><option>--version</option></term>
+
+ <listitem id='version-text'>
+ <para>Print the version string and exit.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='tron'>
+ <term><command>tron</command></term>
+ <listitem>
+ <para>Trace ON. Enable code tracing, which is to say that lots of
+ debug information will be printed to the syslog
+ (e.g. systemd-journal).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='troff'>
+ <term><command>troff</command></term>
+ <listitem>
+ <para>Trace OFF. Disable code tracing.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='status'>
+ <term><command>status</command></term>
+ <listitem>
+ <para>Show runtime status information.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='detailed'>
+ <term><option>-d</option></term>
+ <term><option>--detailed</option></term>
+ <listitem>
+ <para>Print additional details.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='transport'>
+ <term><option>-tTRTYPE</option></term>
+ <term><option>--transport=TRTYPE</option></term>
+
+ <listitem>
+ <para>NVMe-over-Fabrics fabric type (default: "tcp").</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='traddr'>
+ <term><option>-aTRADDR</option></term>
+ <term><option>--traddr=TRADDR</option></term>
+ <listitem>
+ <para>Discovery controller's network address.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='trsvcid'>
+ <term><option>-sTRSVCID</option></term>
+ <term><option>--trsvcid=TRSVCID</option></term>
+ <listitem>
+ <para>
+ Transport service id (for IP addressing, e.g. tcp, rdma,
+ this field is the port number).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='host-traddr'>
+ <term><option>-wTRADDR</option></term>
+ <term><option>--host-traddr=TRADDR</option></term>
+ <listitem>
+ <para>
+ Network source address used on the host to connect to
+ the controller.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='host-iface'>
+ <term><option>-fIFACE</option></term>
+ <term><option>--host-iface=IFACE</option></term>
+ <listitem>
+ <para>
+ This field specifies the network interface used on the
+ host to connect to the controller.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='nqn'>
+ <term><option>-nNQN</option></term>
+ <term><option>--nqn=NQN</option></term>
+ <listitem>
+ <para>
+ This field specifies the Controller's NVMe Qualified Name.
+ </para>
+ <para>
+ This field is mandatory for I/O Controllers, but is optional for
+ Discovery Controllers (DC). For the latter, the NQN will default
+ to the well-known DC NQN: <literal>nqn.2014-08.org.nvmexpress.discovery</literal>
+ if left undefined.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='TRTYPE-value'>
+ <term><replaceable>TRTYPE</replaceable></term>
+ <listitem>
+ <para>rdma, fc, tcp, loop.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='TRADDR-value'>
+ <term><replaceable>TRADDR</replaceable></term>
+ <listitem>
+ <para>IP or Fibre Channel address. E.g. 10.10.0.100.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='TRSVCID-value'>
+ <term><replaceable>TRSVCID</replaceable></term>
+ <listitem>
+ <para>E.g., 8009.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='IFACE-value'>
+ <term><replaceable>IFACE</replaceable></term>
+ <listitem>
+ <para>
+ Network interface name. E.g., eth1, enp0s8, wlp0s20f3.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='NQN-value'>
+ <term><replaceable>NQN</replaceable></term>
+ <listitem>
+ <para>
+ NVMe Qualified Name.
+ </para>
+ </listitem>
+ </varlistentry>
+
+</variablelist>
diff --git a/doc/stas-config.target.xml b/doc/stas-config.target.xml
new file mode 100644
index 0000000..1e81845
--- /dev/null
+++ b/doc/stas-config.target.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2022, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+<refentry id="stas-config.target">
+ <refentryinfo>
+ <title>stas-config.target</title>
+ <productname>nvme-stas</productname>
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>stas-config.target</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>stas-config.target</refname>
+ <refpurpose>Used to synchronize the start of nvme-stas processes</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para>
+ <filename>/usr/lib/systemd/system/stas-config.target</filename>
+ </para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+ <para>
+ This target is used as a synchronization point before starting
+ <citerefentry><refentrytitle>stacd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> and
+ <citerefentry><refentrytitle>stafd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ </para>
+
+ <para>
+ It ensures that <filename>/etc/nvme/hostnqn</filename> and
+ <filename>/etc/nvme/hostid</filename> are present before starting
+ <citerefentry><refentrytitle>stacd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> and
+ <citerefentry><refentrytitle>stafd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry>
+ <refentrytitle>stacd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+</refentry>
+
+
diff --git a/doc/stas-config@.service.xml b/doc/stas-config@.service.xml
new file mode 100644
index 0000000..8d05d44
--- /dev/null
+++ b/doc/stas-config@.service.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2022, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+<refentry id="stas-config@.service">
+ <refentryinfo>
+ <title>stas-config@.service</title>
+ <productname>nvme-stas</productname>
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>stas-config@.service</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>stas-config@.service</refname>
+ <refpurpose>Used for auto-generation of nvme-stas configuration files.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para>
+ <filename>/usr/lib/systemd/system/stas-config@.service</filename>
+ </para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+ <para>
+ This service is used for the automatic run-time generation of
+ NVMe configuration located in <filename>/etc/nvme</filename>
+ (e.g. <filename>/etc/nvme/hostnqn</filename>). This is needed by
+ <citerefentry><refentrytitle>stacd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> and
+ <citerefentry><refentrytitle>stafd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry>
+ <refentrytitle>stacd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+</refentry>
+
diff --git a/doc/stasadm.xml b/doc/stasadm.xml
new file mode 100644
index 0000000..576328c
--- /dev/null
+++ b/doc/stasadm.xml
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+<refentry id="stasadm" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>stasadm</title>
+ <productname>nvme-stas</productname>
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>stasadm</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>stasadm</refname>
+ <refpurpose>STorage Appliance Services admin functions</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>stasadm</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="req">COMMAND</arg>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>stasadm</command> is used to configure <code>nvme-stas</code>. The
+ configuration is saved to <filename>/etc/stas/sys.conf</filename>.
+ </para>
+
+ <para>
+ Although <code>nvme-stas</code>' configuration is saved to
+ <filename>/etc/stas/sys.conf</filename>, it's still possible to
+ interoperate with the configuration of <command>nvme-cli</command>
+ and <command>libnvme</command>. <code>nvme-stas</code> allows one to
+ save individual parameters such as the Host NQN and ID outside of
+ <filename>/etc/stas/sys.conf</filename>. This allows, for example,
+ using the same default Host NQN and ID defined by
+ <command>nvme-cli</command> and <command>libnvme</command> in
+ <filename>/etc/nvme/hostnqn</filename> and <filename>/etc/nvme/hostid</filename>
+ respectively. To tell <code>nvme-stas</code> that you want to use the
+ those files, simply use <command>stasadm</command>'s
+ <option>--file=FILE</option> option.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Commands</title>
+ <para>The following commands are understood:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><command>hostnqn</command></term>
+ <listitem>
+ <para>
+ Generate the Host NQN. This is typically used as a post
+ installation step to generate <filename>/etc/nvme/hostnqn</filename>.
+ </para>
+ <para>
+ The NVMe base specifications says: <quote>An NQN is
+ permanent for the lifetime of the host</quote>. For
+ this reason, the host NQN should only be generated
+ if <filename>/etc/nvme/hostnqn</filename> does not exist
+ already.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>hostid</command></term>
+ <listitem>
+ <para>
+ Generate the Host ID. This is typically used as a post
+ installation step to generate <filename>/etc/nvme/hostid</filename>.
+ </para>
+ <para>
+ Although not explicitly specified in the NVMe
+ specifications, the Host ID, like the Host NQN, should
+ be permanent for the lifetime of the host. Only generate
+ the Host ID if <filename>/etc/nvme/hostid</filename>
+ does not exist.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>set-symname [SYMNAME]</command></term>
+ <listitem>
+ <para>
+ Set the host symbolic name.
+ </para>
+
+ <para>
+ The symbolic name is an optional parameter that can be
+ used for explicit registration with a discovery controller.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>clear-symname</command></term>
+ <listitem>
+ <para>
+ Clear the host symbolic name.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+
+ <para>The following options are understood:</para>
+
+ <variablelist>
+ <xi:include href="standard-options.xml" xpointer="help"/>
+ <xi:include href="standard-options.xml" xpointer="version"/>
+
+ <varlistentry>
+ <term><option>-fFILE</option></term>
+ <term><option>--file=FILE</option></term>
+ <listitem>
+ <para>
+ By default, <command>hostnqn</command> and <command>hostid</command>
+ save the values to <filename>/etc/stas/sys.conf</filename>.
+ This option allows saving to a separate file.
+ </para>
+ <para>
+ Traditionally, <command>nvme-cli</command> and
+ <command>libnvme</command> retrieve the default Host NQN
+ and ID from <filename>/etc/nvme/hostnqn</filename> and
+ <filename>/etc/nvme/hostid</filename> respectively. The
+ <option>--file=FILE</option> option can be
+ used to tell <code>nvme-stas</code> that it should
+ use those same configuration files.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Exit status</title>
+ <para>
+ On success, 0 is returned; otherwise, a non-zero failure code is
+ returned.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Generate <filename>/etc/nvme/hostnqn</filename></title>
+ <programlisting>$ stasadm hostnqn --file /etc/nvme/hostnqn</programlisting>
+ </example>
+
+ <example>
+ <title>Generate <filename>/etc/nvme/hostid</filename></title>
+ <programlisting>$ stasadm hostid -f /etc/nvme/hostid</programlisting>
+ </example>
+
+ <example>
+ <title>Configure the host's symbolic name</title>
+ <programlisting>$ stasadm set-symname LukeSkywalker</programlisting>
+ </example>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry>
+ <refentrytitle>nvme-stas</refentrytitle>
+ <manvolnum>7</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/doc/sys.conf.xml b/doc/sys.conf.xml
new file mode 100644
index 0000000..fc6838a
--- /dev/null
+++ b/doc/sys.conf.xml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!--
+ SPDX-License-Identifier: Apache-2.0
+ Copyright (c) 2021, Dell Inc. or its subsidiaries. All rights reserved.
+-->
+<refentry id="sys.conf" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>sys.conf</title>
+ <productname>nvme-stas</productname>
+
+ <author>
+ <personname>
+ <honorific>Mr</honorific>
+ <firstname>Martin</firstname>
+ <surname>Belanger</surname>
+ </personname>
+
+ <affiliation>
+ <orgname>Dell, Inc.</orgname>
+ </affiliation>
+ </author>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sys.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sys.conf</refname>
+
+ <refpurpose>
+ <citerefentry project="man-pages">
+ <refentrytitle>nvme-stas</refentrytitle>
+ <manvolnum>7</manvolnum>
+ </citerefentry>
+ configuration file
+ </refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para>
+ <filename>/etc/stas/sys.conf</filename>
+ </para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ When <citerefentry project="man-pages"><refentrytitle>stafd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry> and
+ <citerefentry project="man-pages"><refentrytitle>stacd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry> start up, they read the
+ system configuration from <filename>sys.conf</filename>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Configuration File Format</title>
+ <para>
+ <filename>sys.conf</filename> is a plain text file divided into
+ sections, with configuration entries in the style
+ <replaceable>key</replaceable>=<replaceable>value</replaceable>.
+ Whitespace immediately before or after the <literal>=</literal> is
+ ignored. Empty lines and lines starting with <literal>#</literal>
+ are ignored, which may be used for commenting.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+
+ <refsect2>
+ <title>[Host] section</title>
+ <para>
+ The following options are available in the
+ <literal>[Host]</literal> section:
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><varname>nqn=</varname></term>
+ <listitem>
+ <para>
+ Takes a string argument identifying the Host NQN.
+ A value starting with <code>file://</code>
+ indicates that the Host NQN can be retrieved from
+ a separate file. This is a mandatory parameter.
+ Defaults to: <literal>file:///etc/nvme/hostnqn</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <variablelist>
+ <varlistentry>
+ <term><varname>id=</varname></term>
+ <listitem>
+ <para>
+ Takes a string argument identifying the Host ID.
+ A value starting with <code>file://</code>
+ indicates that the Host ID can be retrieved from
+ a separate file. This is a mandatory parameter.
+ Defaults to: <literal>file:///etc/nvme/hostid</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <variablelist>
+ <varlistentry>
+ <term><varname>symname=</varname></term>
+ <listitem>
+ <para>
+ Takes a string argument identifying the Host symbolic name.
+ A value starting with <code>file://</code>
+ indicates that the symbolic name can be retrieved from
+ a separate file. This is an optional parameter.
+ There is no default value.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>nvme-stas</refentrytitle>
+ <manvolnum>7</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..4d5b384
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,27 @@
+version: '3.7'
+
+x-stas: &default-stas
+ image: ghcr.io/linux-nvme/nvme-stas:main
+ build:
+ context: .
+ volumes:
+ - /run/dbus:/run/dbus
+ - /etc/nvme:/etc/nvme
+ privileged: true
+ network_mode: host
+
+services:
+ stafd:
+ <<: *default-stas
+ environment:
+ RUNTIME_DIRECTORY: /run/stafd
+ XDG_CACHE_HOME: /var/cache/stafd
+ PYTHONUNBUFFERED: 1
+ command: -u /usr/sbin/stafd
+ stacd:
+ <<: *default-stas
+ environment:
+ RUNTIME_DIRECTORY: /run/stacd
+ XDG_CACHE_HOME: /var/cache/stacd
+ PYTHONUNBUFFERED: 1
+ command: -u /usr/sbin/stacd