2022-06-03 19:15:11 +00:00
|
|
|
/* SPDX-License-Identifier: BSD-3-Clause
|
2022-11-01 20:26:26 +00:00
|
|
|
* Copyright (C) 2016 Intel Corporation. All rights reserved.
|
2019-10-09 06:40:31 +00:00
|
|
|
* Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
|
2021-12-30 05:15:20 +00:00
|
|
|
* Copyright (c) 2021, 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
nvme: Added support for TP-8009, Auto-discovery of Discovery controllers for NVME initiator using mDNS using Avahi
Approach:
Avahi Daemon needs to be running to provide the mDNS server service. In the SPDK, Avahi-client library based client API is implemented.
The client API will connect to the Avahi-daemon and receive events for new discovery and removal of an existing discovery entry.
Following sets on new RPCs have been introduced.
scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
User shall initiate an mDNS based discovery using this RPC. This will start a Avahi-client based poller
looking for new discovery events from the Avahi server. On a new discovery of the discovery controller,
the existing bdev_nvme_start_discovery API will be invoked with the trid of the discovery controller learnt.
This will enable automatic connection of the initiator to the subsystems discovered from the discovery controller.
Multiple mdns discovery instances can be run by specifying a unique bdev-prefix and a unique servicename to discover as parameters.
scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
This will stop the Avahi poller that was started for the specified service.Internally bdev_nvme_stop_discovery
API will be invoked for each of the discovery controllers learnt automatically by this instance of mdns discovery service.
This will result in termination of connections to all the subsystems learnt by this mdns discovery instance.
scripts/rpc.py bdev_nvme_get_mdns_discovery_info
This RPC will display the list of mdns discovery instances running and the trid of the controllers discovered by these instances.
Test Result:
root@ubuntu-pm-18-226:~/param-spdk/spdk/build/bin# ./nvmf_tgt -i 1 -s 2048 -m 0xF
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[
{
"name": "cdc_auto",
"svcname": "_nvme-disc._tcp",
"referrals": [
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
}
]
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[
{
"name": "cdc_auto02n1",
"aliases": [
"600110d6-1681-1681-0403-000045805c45"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-1681-1681-0403-000045805c45",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T0",
"serial_number": "00-681681dc681681dc",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto00n1",
"aliases": [
"600110da-09a6-09a6-0302-00005eeb19b4"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 2048,
"uuid": "600110da-09a6-09a6-0302-00005eeb19b4",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0"
},
"ctrlr_data": {
"cntlid": 1,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P2T0",
"serial_number": "00-ab09a6f5ab09a6f5",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n1",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8c"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8c",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n2",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8d"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8d",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 2,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
Signed-off-by: Parameswaran Krishnamurthy <parameswaran.krishna@dell.com>
Change-Id: Ic2c2e614e2549a655c7f81ae844b80d8505a4f02
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15703
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Boris Glimcher <Boris.Glimcher@emc.com>
Reviewed-by: <qun.wan@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
2022-11-30 20:11:23 +00:00
|
|
|
* Copyright (c) 2022 Dell Inc, or its subsidiaries. All rights reserved.
|
2016-07-20 18:16:23 +00:00
|
|
|
*/
|
|
|
|
|
2017-05-02 18:18:25 +00:00
|
|
|
#include "spdk/stdinc.h"
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2017-07-13 04:08:53 +00:00
|
|
|
#include "bdev_nvme.h"
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2022-08-08 20:31:08 +00:00
|
|
|
#include "spdk/accel.h"
|
2018-09-27 19:38:15 +00:00
|
|
|
#include "spdk/config.h"
|
2016-08-22 22:23:38 +00:00
|
|
|
#include "spdk/endian.h"
|
2016-07-20 18:16:23 +00:00
|
|
|
#include "spdk/bdev.h"
|
2016-11-18 17:22:58 +00:00
|
|
|
#include "spdk/json.h"
|
2021-08-30 18:30:18 +00:00
|
|
|
#include "spdk/likely.h"
|
2016-07-20 18:16:23 +00:00
|
|
|
#include "spdk/nvme.h"
|
2019-03-08 14:28:17 +00:00
|
|
|
#include "spdk/nvme_ocssd.h"
|
2021-03-03 18:38:38 +00:00
|
|
|
#include "spdk/nvme_zns.h"
|
2021-08-30 18:30:18 +00:00
|
|
|
#include "spdk/opal.h"
|
2018-06-11 20:32:15 +00:00
|
|
|
#include "spdk/thread.h"
|
2022-08-11 00:04:56 +00:00
|
|
|
#include "spdk/trace.h"
|
2016-12-05 20:59:39 +00:00
|
|
|
#include "spdk/string.h"
|
2017-09-19 17:59:58 +00:00
|
|
|
#include "spdk/util.h"
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2018-05-23 21:01:03 +00:00
|
|
|
#include "spdk/bdev_module.h"
|
2020-10-06 16:16:26 +00:00
|
|
|
#include "spdk/log.h"
|
2016-11-07 22:10:28 +00:00
|
|
|
|
2021-12-06 10:57:02 +00:00
|
|
|
#include "spdk_internal/usdt.h"
|
2022-08-11 00:04:56 +00:00
|
|
|
#include "spdk_internal/trace_defs.h"
|
2021-12-06 10:57:02 +00:00
|
|
|
|
2019-11-18 16:59:36 +00:00
|
|
|
#define SPDK_BDEV_NVME_DEFAULT_DELAY_CMD_SUBMIT true
|
2020-11-27 16:10:36 +00:00
|
|
|
#define SPDK_BDEV_NVME_DEFAULT_KEEP_ALIVE_TIMEOUT_IN_MS (10000)
|
2019-11-18 16:59:36 +00:00
|
|
|
|
2022-10-24 12:53:22 +00:00
|
|
|
#define NSID_STR_LEN 10
|
|
|
|
|
2018-04-05 15:43:55 +00:00
|
|
|
static int bdev_nvme_config_json(struct spdk_json_write_ctx *w);
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2017-02-28 17:51:25 +00:00
|
|
|
struct nvme_bdev_io {
|
2016-10-04 14:39:27 +00:00
|
|
|
/** array of iovecs to transfer. */
|
|
|
|
struct iovec *iovs;
|
|
|
|
|
|
|
|
/** Number of iovecs in iovs array. */
|
|
|
|
int iovcnt;
|
|
|
|
|
|
|
|
/** Current iovec position. */
|
|
|
|
int iovpos;
|
|
|
|
|
|
|
|
/** Offset in current iovec. */
|
|
|
|
uint32_t iov_offset;
|
2017-05-13 20:12:13 +00:00
|
|
|
|
2021-10-19 03:54:14 +00:00
|
|
|
/** I/O path the current I/O or admin passthrough is submitted on, or the I/O path
|
|
|
|
* being reset in a reset I/O.
|
2021-09-28 15:34:56 +00:00
|
|
|
*/
|
2021-09-16 11:10:56 +00:00
|
|
|
struct nvme_io_path *io_path;
|
|
|
|
|
2020-01-16 10:10:53 +00:00
|
|
|
/** array of iovecs to transfer. */
|
|
|
|
struct iovec *fused_iovs;
|
|
|
|
|
|
|
|
/** Number of iovecs in iovs array. */
|
|
|
|
int fused_iovcnt;
|
|
|
|
|
|
|
|
/** Current iovec position. */
|
|
|
|
int fused_iovpos;
|
|
|
|
|
|
|
|
/** Offset in current iovec. */
|
|
|
|
uint32_t fused_iov_offset;
|
|
|
|
|
2020-01-15 10:05:18 +00:00
|
|
|
/** Saved status for admin passthru completion event, PI error verification, or intermediate compare-and-write status */
|
2017-05-13 20:12:13 +00:00
|
|
|
struct spdk_nvme_cpl cpl;
|
2021-10-31 07:11:00 +00:00
|
|
|
|
2021-01-09 15:10:18 +00:00
|
|
|
/** Extended IO opts passed by the user to bdev layer and mapped to NVME format */
|
|
|
|
struct spdk_nvme_ns_cmd_ext_io_opts ext_opts;
|
2017-05-13 20:12:13 +00:00
|
|
|
|
2017-06-15 20:51:31 +00:00
|
|
|
/** Originating thread */
|
|
|
|
struct spdk_thread *orig_thread;
|
2019-12-20 11:29:48 +00:00
|
|
|
|
2020-01-15 10:05:18 +00:00
|
|
|
/** Keeps track if first of fused commands was submitted */
|
2019-12-20 11:29:48 +00:00
|
|
|
bool first_fused_submitted;
|
2021-03-03 18:38:38 +00:00
|
|
|
|
2022-04-06 12:43:21 +00:00
|
|
|
/** Keeps track if first of fused commands was completed */
|
|
|
|
bool first_fused_completed;
|
|
|
|
|
2021-03-03 18:38:38 +00:00
|
|
|
/** Temporary pointer to zone report buffer */
|
|
|
|
struct spdk_nvme_zns_zone_report *zone_report_buf;
|
|
|
|
|
|
|
|
/** Keep track of how many zones that have been copied to the spdk_bdev_zone_info struct */
|
|
|
|
uint64_t handled_zones;
|
2021-10-07 22:11:17 +00:00
|
|
|
|
|
|
|
/** Expiration value in ticks to retry the current I/O. */
|
|
|
|
uint64_t retry_ticks;
|
2021-10-25 02:59:46 +00:00
|
|
|
|
|
|
|
/* How many times the current I/O was retried. */
|
|
|
|
int32_t retry_count;
|
2022-09-29 03:52:43 +00:00
|
|
|
|
|
|
|
/* Current tsc at submit time. */
|
|
|
|
uint64_t submit_tsc;
|
2016-07-20 18:16:23 +00:00
|
|
|
};
|
|
|
|
|
2019-02-13 05:08:22 +00:00
|
|
|
struct nvme_probe_skip_entry {
|
|
|
|
struct spdk_nvme_transport_id trid;
|
|
|
|
TAILQ_ENTRY(nvme_probe_skip_entry) tailq;
|
|
|
|
};
|
|
|
|
/* All the controllers deleted by users via RPC are skipped by hotplug monitor */
|
|
|
|
static TAILQ_HEAD(, nvme_probe_skip_entry) g_skipped_nvme_ctrlrs = TAILQ_HEAD_INITIALIZER(
|
|
|
|
g_skipped_nvme_ctrlrs);
|
|
|
|
|
2018-07-09 21:04:33 +00:00
|
|
|
static struct spdk_bdev_nvme_opts g_opts = {
|
|
|
|
.action_on_timeout = SPDK_BDEV_NVME_TIMEOUT_ACTION_NONE,
|
|
|
|
.timeout_us = 0,
|
2021-05-26 20:43:22 +00:00
|
|
|
.timeout_admin_us = 0,
|
2020-11-27 16:10:36 +00:00
|
|
|
.keep_alive_timeout_ms = SPDK_BDEV_NVME_DEFAULT_KEEP_ALIVE_TIMEOUT_IN_MS,
|
2021-10-18 19:33:01 +00:00
|
|
|
.transport_retry_count = 4,
|
2019-09-03 03:48:49 +00:00
|
|
|
.arbitration_burst = 0,
|
|
|
|
.low_priority_weight = 0,
|
|
|
|
.medium_priority_weight = 0,
|
|
|
|
.high_priority_weight = 0,
|
2020-03-20 11:18:05 +00:00
|
|
|
.nvme_adminq_poll_period_us = 10000ULL,
|
2019-03-11 22:26:53 +00:00
|
|
|
.nvme_ioq_poll_period_us = 0,
|
2019-07-10 05:13:31 +00:00
|
|
|
.io_queue_requests = 0,
|
2019-11-18 16:59:36 +00:00
|
|
|
.delay_cmd_submit = SPDK_BDEV_NVME_DEFAULT_DELAY_CMD_SUBMIT,
|
2022-01-13 17:27:37 +00:00
|
|
|
.bdev_retry_count = 3,
|
2022-01-20 12:22:06 +00:00
|
|
|
.transport_ack_timeout = 0,
|
2022-03-09 12:04:14 +00:00
|
|
|
.ctrlr_loss_timeout_sec = 0,
|
|
|
|
.reconnect_delay_sec = 0,
|
|
|
|
.fast_io_fail_timeout_sec = 0,
|
2022-05-02 03:07:02 +00:00
|
|
|
.disable_auto_failback = false,
|
2022-10-24 12:53:22 +00:00
|
|
|
.generate_uuids = false,
|
2022-12-14 20:24:27 +00:00
|
|
|
.transport_tos = 0,
|
bdev/nvme: Count number of NVMe errors per type or code
Error counters for NVMe error was added in the generic bdev layer but
we want to know more detailed information for some use cases.
Add NVMe error counters per type and per code as module specific
statistics.
For status codes, the first idea was to have different named member
for each status code value. However, it was bad and too hard to test,
review, and maintain.
Instead, we have just two dimensional uint32_t arrays, and increment
one of these uint32_t values based on the status code type and status
code. Then, when dump the JSON, we use spdk_nvme_cpl_get_status_string()
and spdk_nvme_cpl_get_status_type_string().
This idea has one potential downside. This idea consumes 4 (types) *
256 (codes) * 4 (counter) = 4KB per NVMe bdev. We can make this smarter
if memory allocation is a problem. Hence we add an option
nvme_error_stat to enable this feature only if the user requests.
Additionally, the string returned by spdk_nvme_cpl_get_status_string()
or spdk_nvme_cpl_get_status_type_string() has uppercases, spaces, and
hyphens. These should not be included in JSON strings. Hence, convert
these via spdk_strcpy_replace().
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I07b07621e777bdf6556b95054abbbb65e5f9ea3e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15370
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
2023-01-05 23:26:33 +00:00
|
|
|
.nvme_error_stat = false,
|
2022-09-29 03:52:43 +00:00
|
|
|
.io_path_stat = false,
|
2017-03-30 19:49:52 +00:00
|
|
|
};
|
|
|
|
|
2018-07-12 12:26:19 +00:00
|
|
|
#define NVME_HOTPLUG_POLL_PERIOD_MAX 10000000ULL
|
|
|
|
#define NVME_HOTPLUG_POLL_PERIOD_DEFAULT 100000ULL
|
2018-07-09 21:04:33 +00:00
|
|
|
|
2017-03-16 15:33:27 +00:00
|
|
|
static int g_hot_insert_nvme_controller_index = 0;
|
2018-07-12 12:26:19 +00:00
|
|
|
static uint64_t g_nvme_hotplug_poll_period_us = NVME_HOTPLUG_POLL_PERIOD_DEFAULT;
|
2018-07-09 21:04:33 +00:00
|
|
|
static bool g_nvme_hotplug_enabled = false;
|
nvme: Added support for TP-8009, Auto-discovery of Discovery controllers for NVME initiator using mDNS using Avahi
Approach:
Avahi Daemon needs to be running to provide the mDNS server service. In the SPDK, Avahi-client library based client API is implemented.
The client API will connect to the Avahi-daemon and receive events for new discovery and removal of an existing discovery entry.
Following sets on new RPCs have been introduced.
scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
User shall initiate an mDNS based discovery using this RPC. This will start a Avahi-client based poller
looking for new discovery events from the Avahi server. On a new discovery of the discovery controller,
the existing bdev_nvme_start_discovery API will be invoked with the trid of the discovery controller learnt.
This will enable automatic connection of the initiator to the subsystems discovered from the discovery controller.
Multiple mdns discovery instances can be run by specifying a unique bdev-prefix and a unique servicename to discover as parameters.
scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
This will stop the Avahi poller that was started for the specified service.Internally bdev_nvme_stop_discovery
API will be invoked for each of the discovery controllers learnt automatically by this instance of mdns discovery service.
This will result in termination of connections to all the subsystems learnt by this mdns discovery instance.
scripts/rpc.py bdev_nvme_get_mdns_discovery_info
This RPC will display the list of mdns discovery instances running and the trid of the controllers discovered by these instances.
Test Result:
root@ubuntu-pm-18-226:~/param-spdk/spdk/build/bin# ./nvmf_tgt -i 1 -s 2048 -m 0xF
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[
{
"name": "cdc_auto",
"svcname": "_nvme-disc._tcp",
"referrals": [
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
}
]
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[
{
"name": "cdc_auto02n1",
"aliases": [
"600110d6-1681-1681-0403-000045805c45"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-1681-1681-0403-000045805c45",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T0",
"serial_number": "00-681681dc681681dc",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto00n1",
"aliases": [
"600110da-09a6-09a6-0302-00005eeb19b4"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 2048,
"uuid": "600110da-09a6-09a6-0302-00005eeb19b4",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0"
},
"ctrlr_data": {
"cntlid": 1,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P2T0",
"serial_number": "00-ab09a6f5ab09a6f5",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n1",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8c"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8c",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n2",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8d"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8d",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 2,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
Signed-off-by: Parameswaran Krishnamurthy <parameswaran.krishna@dell.com>
Change-Id: Ic2c2e614e2549a655c7f81ae844b80d8505a4f02
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15703
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Boris Glimcher <Boris.Glimcher@emc.com>
Reviewed-by: <qun.wan@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
2022-11-30 20:11:23 +00:00
|
|
|
struct spdk_thread *g_bdev_nvme_init_thread;
|
2017-11-17 21:49:36 +00:00
|
|
|
static struct spdk_poller *g_hotplug_poller;
|
2020-12-18 13:10:56 +00:00
|
|
|
static struct spdk_poller *g_hotplug_probe_poller;
|
2019-03-05 07:32:34 +00:00
|
|
|
static struct spdk_nvme_probe_ctx *g_hotplug_probe_ctx;
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
static void nvme_ctrlr_populate_namespaces(struct nvme_ctrlr *nvme_ctrlr,
|
2019-11-26 16:55:40 +00:00
|
|
|
struct nvme_async_probe_ctx *ctx);
|
2021-07-06 19:42:41 +00:00
|
|
|
static void nvme_ctrlr_populate_namespaces_done(struct nvme_ctrlr *nvme_ctrlr,
|
2021-03-01 22:39:39 +00:00
|
|
|
struct nvme_async_probe_ctx *ctx);
|
2017-07-13 17:36:19 +00:00
|
|
|
static int bdev_nvme_library_init(void);
|
2017-02-28 17:51:25 +00:00
|
|
|
static void bdev_nvme_library_fini(void);
|
bdev/nvme: Retry I/O to the same path if error is I/O error
When an I/O gets an I/O error, the I/O path to which the I/O was
submitted may be still available. In this case, the I/O should be
retried to the same I/O path. However, a new I/O path was always
selected for an I/O retry.
For the active/passive policy, the same I/O path was selected naturally.
However, for the active/active policy, it was very likely that a
different I/O path was selected.
To use the same I/O path for an I/O retry, add a helper function
bdev_nvme_retry_io() into bdev_nvme_retry_ios() and replace
bdev_nvme_submit_request() by bdev_nvme_retry_io(). bdev_nvme_retry_io()
checks if nbdev_io->io_path is not NULL and is available. Then, call
_bdev_nvme_submit_request() if true, or call bdev_nvme_submit_request()
otherwise. For I/O path error, clear nbdev_io->io_path for
clarification. Add unit test to verify this change.
Linux kernel native NVMe multipath already takes this approach. Hence,
this change will be reasonable.
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I7022aafd8b1cdd5830c4f743d64b080aa970cf8d
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16015
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Richael <richael.zhuang@arm.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
2022-12-26 07:31:33 +00:00
|
|
|
static void _bdev_nvme_submit_request(struct nvme_bdev_channel *nbdev_ch,
|
|
|
|
struct spdk_bdev_io *bdev_io);
|
2021-10-07 22:11:17 +00:00
|
|
|
static void bdev_nvme_submit_request(struct spdk_io_channel *ch,
|
|
|
|
struct spdk_bdev_io *bdev_io);
|
2021-09-16 11:10:56 +00:00
|
|
|
static int bdev_nvme_readv(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
|
|
|
|
void *md, uint64_t lba_count, uint64_t lba,
|
2021-08-25 03:18:56 +00:00
|
|
|
uint32_t flags, struct spdk_bdev_ext_io_opts *ext_opts);
|
2021-09-16 11:10:56 +00:00
|
|
|
static int bdev_nvme_no_pi_readv(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
|
|
|
|
void *md, uint64_t lba_count, uint64_t lba);
|
|
|
|
static int bdev_nvme_writev(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
|
|
|
|
void *md, uint64_t lba_count, uint64_t lba,
|
2021-08-25 03:18:56 +00:00
|
|
|
uint32_t flags, struct spdk_bdev_ext_io_opts *ext_opts);
|
2021-09-16 11:10:56 +00:00
|
|
|
static int bdev_nvme_zone_appendv(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
|
|
|
|
void *md, uint64_t lba_count,
|
2021-03-03 18:38:38 +00:00
|
|
|
uint64_t zslba, uint32_t flags);
|
2021-09-16 11:10:56 +00:00
|
|
|
static int bdev_nvme_comparev(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
|
|
|
|
void *md, uint64_t lba_count, uint64_t lba,
|
2020-09-23 20:37:27 +00:00
|
|
|
uint32_t flags);
|
2021-09-16 11:10:56 +00:00
|
|
|
static int bdev_nvme_comparev_and_writev(struct nvme_bdev_io *bio,
|
|
|
|
struct iovec *cmp_iov, int cmp_iovcnt, struct iovec *write_iov,
|
2020-09-23 20:37:27 +00:00
|
|
|
int write_iovcnt, void *md, uint64_t lba_count, uint64_t lba,
|
|
|
|
uint32_t flags);
|
2021-09-16 11:10:56 +00:00
|
|
|
static int bdev_nvme_get_zone_info(struct nvme_bdev_io *bio, uint64_t zone_id,
|
|
|
|
uint32_t num_zones, struct spdk_bdev_zone_info *info);
|
|
|
|
static int bdev_nvme_zone_management(struct nvme_bdev_io *bio, uint64_t zone_id,
|
2021-03-03 18:38:38 +00:00
|
|
|
enum spdk_bdev_zone_action action);
|
2021-10-18 13:15:32 +00:00
|
|
|
static void bdev_nvme_admin_passthru(struct nvme_bdev_channel *nbdev_ch,
|
|
|
|
struct nvme_bdev_io *bio,
|
|
|
|
struct spdk_nvme_cmd *cmd, void *buf, size_t nbytes);
|
2021-09-16 11:10:56 +00:00
|
|
|
static int bdev_nvme_io_passthru(struct nvme_bdev_io *bio, struct spdk_nvme_cmd *cmd,
|
|
|
|
void *buf, size_t nbytes);
|
|
|
|
static int bdev_nvme_io_passthru_md(struct nvme_bdev_io *bio, struct spdk_nvme_cmd *cmd,
|
|
|
|
void *buf, size_t nbytes, void *md_buf, size_t md_len);
|
2021-09-28 05:37:36 +00:00
|
|
|
static void bdev_nvme_abort(struct nvme_bdev_channel *nbdev_ch,
|
|
|
|
struct nvme_bdev_io *bio, struct nvme_bdev_io *bio_to_abort);
|
|
|
|
static void bdev_nvme_reset_io(struct nvme_bdev_channel *nbdev_ch, struct nvme_bdev_io *bio);
|
2021-09-15 04:01:49 +00:00
|
|
|
static int bdev_nvme_reset(struct nvme_ctrlr *nvme_ctrlr);
|
2021-07-06 19:42:41 +00:00
|
|
|
static int bdev_nvme_failover(struct nvme_ctrlr *nvme_ctrlr, bool remove);
|
2020-12-07 15:42:00 +00:00
|
|
|
static void remove_cb(void *cb_ctx, struct spdk_nvme_ctrlr *ctrlr);
|
2022-02-03 22:14:10 +00:00
|
|
|
static int nvme_ctrlr_read_ana_log_page(struct nvme_ctrlr *nvme_ctrlr);
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2023-01-16 06:43:32 +00:00
|
|
|
static struct nvme_ns *nvme_ns_alloc(void);
|
|
|
|
static void nvme_ns_free(struct nvme_ns *ns);
|
|
|
|
|
2021-08-25 16:58:16 +00:00
|
|
|
static int
|
|
|
|
nvme_ns_cmp(struct nvme_ns *ns1, struct nvme_ns *ns2)
|
|
|
|
{
|
2022-03-08 09:02:43 +00:00
|
|
|
return ns1->id < ns2->id ? -1 : ns1->id > ns2->id;
|
2021-08-25 16:58:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RB_GENERATE_STATIC(nvme_ns_tree, nvme_ns, node, nvme_ns_cmp);
|
|
|
|
|
2018-07-05 07:46:48 +00:00
|
|
|
struct spdk_nvme_qpair *
|
2021-07-07 01:02:14 +00:00
|
|
|
bdev_nvme_get_io_qpair(struct spdk_io_channel *ctrlr_io_ch)
|
2018-07-05 07:46:48 +00:00
|
|
|
{
|
2021-07-07 01:02:14 +00:00
|
|
|
struct nvme_ctrlr_channel *ctrlr_ch;
|
2018-07-05 07:46:48 +00:00
|
|
|
|
2021-07-07 01:02:14 +00:00
|
|
|
assert(ctrlr_io_ch != NULL);
|
2021-03-17 01:18:36 +00:00
|
|
|
|
2021-07-07 01:02:14 +00:00
|
|
|
ctrlr_ch = spdk_io_channel_get_ctx(ctrlr_io_ch);
|
2018-07-05 07:46:48 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
return ctrlr_ch->qpair->qpair;
|
2018-07-05 07:46:48 +00:00
|
|
|
}
|
|
|
|
|
2016-07-20 18:16:23 +00:00
|
|
|
static int
|
2017-02-28 17:51:25 +00:00
|
|
|
bdev_nvme_get_ctx_size(void)
|
2016-07-20 18:16:23 +00:00
|
|
|
{
|
2017-02-28 17:51:25 +00:00
|
|
|
return sizeof(struct nvme_bdev_io);
|
2016-07-20 18:16:23 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 22:20:21 +00:00
|
|
|
static struct spdk_bdev_module nvme_if = {
|
2018-03-06 18:52:46 +00:00
|
|
|
.name = "nvme",
|
2020-03-05 10:45:00 +00:00
|
|
|
.async_fini = true,
|
2018-03-06 18:52:46 +00:00
|
|
|
.module_init = bdev_nvme_library_init,
|
|
|
|
.module_fini = bdev_nvme_library_fini,
|
2018-04-05 15:43:55 +00:00
|
|
|
.config_json = bdev_nvme_config_json,
|
2018-03-06 18:52:46 +00:00
|
|
|
.get_ctx_size = bdev_nvme_get_ctx_size,
|
|
|
|
|
|
|
|
};
|
2019-02-05 10:46:48 +00:00
|
|
|
SPDK_BDEV_MODULE_REGISTER(nvme, &nvme_if)
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
struct nvme_bdev_ctrlrs g_nvme_bdev_ctrlrs = TAILQ_HEAD_INITIALIZER(g_nvme_bdev_ctrlrs);
|
2021-08-30 18:30:18 +00:00
|
|
|
pthread_mutex_t g_bdev_nvme_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
bool g_bdev_nvme_module_finish;
|
|
|
|
|
2021-11-10 02:05:00 +00:00
|
|
|
struct nvme_bdev_ctrlr *
|
|
|
|
nvme_bdev_ctrlr_get_by_name(const char *name)
|
2021-09-07 16:13:07 +00:00
|
|
|
{
|
|
|
|
struct nvme_bdev_ctrlr *nbdev_ctrlr;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(nbdev_ctrlr, &g_nvme_bdev_ctrlrs, tailq) {
|
|
|
|
if (strcmp(name, nbdev_ctrlr->name) == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nbdev_ctrlr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct nvme_ctrlr *
|
|
|
|
nvme_bdev_ctrlr_get_ctrlr(struct nvme_bdev_ctrlr *nbdev_ctrlr,
|
|
|
|
const struct spdk_nvme_transport_id *trid)
|
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(nvme_ctrlr, &nbdev_ctrlr->ctrlrs, tailq) {
|
2021-09-21 19:17:12 +00:00
|
|
|
if (spdk_nvme_transport_id_compare(trid, &nvme_ctrlr->active_path_id->trid) == 0) {
|
2021-09-07 16:13:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nvme_ctrlr;
|
|
|
|
}
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
static struct nvme_bdev *
|
|
|
|
nvme_bdev_ctrlr_get_bdev(struct nvme_bdev_ctrlr *nbdev_ctrlr, uint32_t nsid)
|
|
|
|
{
|
|
|
|
struct nvme_bdev *bdev;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&g_bdev_nvme_mutex);
|
|
|
|
TAILQ_FOREACH(bdev, &nbdev_ctrlr->bdevs, tailq) {
|
|
|
|
if (bdev->nsid == nsid) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
|
|
|
|
|
|
|
return bdev;
|
|
|
|
}
|
|
|
|
|
2021-08-30 18:30:18 +00:00
|
|
|
struct nvme_ns *
|
|
|
|
nvme_ctrlr_get_ns(struct nvme_ctrlr *nvme_ctrlr, uint32_t nsid)
|
|
|
|
{
|
2021-08-25 16:58:16 +00:00
|
|
|
struct nvme_ns ns;
|
|
|
|
|
2021-08-30 18:30:18 +00:00
|
|
|
assert(nsid > 0);
|
|
|
|
|
2021-08-25 16:58:16 +00:00
|
|
|
ns.id = nsid;
|
|
|
|
return RB_FIND(nvme_ns_tree, &nvme_ctrlr->namespaces, &ns);
|
2021-08-30 18:30:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct nvme_ns *
|
|
|
|
nvme_ctrlr_get_first_active_ns(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
2021-08-25 16:58:16 +00:00
|
|
|
return RB_MIN(nvme_ns_tree, &nvme_ctrlr->namespaces);
|
2021-08-30 18:30:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct nvme_ns *
|
|
|
|
nvme_ctrlr_get_next_active_ns(struct nvme_ctrlr *nvme_ctrlr, struct nvme_ns *ns)
|
|
|
|
{
|
|
|
|
if (ns == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-08-25 16:58:16 +00:00
|
|
|
return RB_NEXT(nvme_ns_tree, &nvme_ctrlr->namespaces, ns);
|
2021-08-30 18:30:18 +00:00
|
|
|
}
|
|
|
|
|
2021-09-07 16:07:15 +00:00
|
|
|
static struct nvme_ctrlr *
|
2021-08-30 18:30:18 +00:00
|
|
|
nvme_ctrlr_get(const struct spdk_nvme_transport_id *trid)
|
|
|
|
{
|
2021-09-07 16:13:07 +00:00
|
|
|
struct nvme_bdev_ctrlr *nbdev_ctrlr;
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = NULL;
|
2021-08-30 18:30:18 +00:00
|
|
|
|
|
|
|
pthread_mutex_lock(&g_bdev_nvme_mutex);
|
2021-09-07 16:13:07 +00:00
|
|
|
TAILQ_FOREACH(nbdev_ctrlr, &g_nvme_bdev_ctrlrs, tailq) {
|
|
|
|
nvme_ctrlr = nvme_bdev_ctrlr_get_ctrlr(nbdev_ctrlr, trid);
|
|
|
|
if (nvme_ctrlr != NULL) {
|
2021-08-30 18:30:18 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
|
|
|
|
|
|
|
return nvme_ctrlr;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct nvme_ctrlr *
|
|
|
|
nvme_ctrlr_get_by_name(const char *name)
|
|
|
|
{
|
2021-09-07 16:13:07 +00:00
|
|
|
struct nvme_bdev_ctrlr *nbdev_ctrlr;
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = NULL;
|
2021-08-30 18:30:18 +00:00
|
|
|
|
|
|
|
if (name == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_lock(&g_bdev_nvme_mutex);
|
2021-11-10 02:05:00 +00:00
|
|
|
nbdev_ctrlr = nvme_bdev_ctrlr_get_by_name(name);
|
2021-09-07 16:13:07 +00:00
|
|
|
if (nbdev_ctrlr != NULL) {
|
|
|
|
nvme_ctrlr = TAILQ_FIRST(&nbdev_ctrlr->ctrlrs);
|
2021-08-30 18:30:18 +00:00
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
|
|
|
|
|
|
|
return nvme_ctrlr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-11-10 02:05:00 +00:00
|
|
|
nvme_bdev_ctrlr_for_each(nvme_bdev_ctrlr_for_each_fn fn, void *ctx)
|
2021-08-30 18:30:18 +00:00
|
|
|
{
|
2021-09-07 16:13:07 +00:00
|
|
|
struct nvme_bdev_ctrlr *nbdev_ctrlr;
|
2021-08-30 18:30:18 +00:00
|
|
|
|
|
|
|
pthread_mutex_lock(&g_bdev_nvme_mutex);
|
2021-09-07 16:13:07 +00:00
|
|
|
TAILQ_FOREACH(nbdev_ctrlr, &g_nvme_bdev_ctrlrs, tailq) {
|
2021-11-10 02:05:00 +00:00
|
|
|
fn(nbdev_ctrlr, ctx);
|
2021-08-30 18:30:18 +00:00
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nvme_bdev_dump_trid_json(const struct spdk_nvme_transport_id *trid, struct spdk_json_write_ctx *w)
|
|
|
|
{
|
|
|
|
const char *trtype_str;
|
|
|
|
const char *adrfam_str;
|
|
|
|
|
|
|
|
trtype_str = spdk_nvme_transport_id_trtype_str(trid->trtype);
|
|
|
|
if (trtype_str) {
|
|
|
|
spdk_json_write_named_string(w, "trtype", trtype_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
adrfam_str = spdk_nvme_transport_id_adrfam_str(trid->adrfam);
|
|
|
|
if (adrfam_str) {
|
|
|
|
spdk_json_write_named_string(w, "adrfam", adrfam_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trid->traddr[0] != '\0') {
|
|
|
|
spdk_json_write_named_string(w, "traddr", trid->traddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trid->trsvcid[0] != '\0') {
|
|
|
|
spdk_json_write_named_string(w, "trsvcid", trid->trsvcid);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trid->subnqn[0] != '\0') {
|
|
|
|
spdk_json_write_named_string(w, "subnqn", trid->subnqn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
static void
|
|
|
|
nvme_bdev_ctrlr_delete(struct nvme_bdev_ctrlr *nbdev_ctrlr,
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
2021-12-06 10:57:02 +00:00
|
|
|
SPDK_DTRACE_PROBE1(bdev_nvme_ctrlr_delete, nvme_ctrlr->nbdev_ctrlr->name);
|
2021-09-07 16:13:07 +00:00
|
|
|
pthread_mutex_lock(&g_bdev_nvme_mutex);
|
|
|
|
|
|
|
|
TAILQ_REMOVE(&nbdev_ctrlr->ctrlrs, nvme_ctrlr, tailq);
|
|
|
|
if (!TAILQ_EMPTY(&nbdev_ctrlr->ctrlrs)) {
|
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TAILQ_REMOVE(&g_nvme_bdev_ctrlrs, nbdev_ctrlr, tailq);
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
assert(TAILQ_EMPTY(&nbdev_ctrlr->bdevs));
|
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
free(nbdev_ctrlr->name);
|
|
|
|
free(nbdev_ctrlr);
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:07:15 +00:00
|
|
|
static void
|
2021-07-09 08:51:32 +00:00
|
|
|
_nvme_ctrlr_delete(struct nvme_ctrlr *nvme_ctrlr)
|
2021-08-30 18:30:18 +00:00
|
|
|
{
|
2021-09-14 18:26:50 +00:00
|
|
|
struct nvme_path_id *path_id, *tmp_path;
|
2021-08-25 16:58:16 +00:00
|
|
|
struct nvme_ns *ns, *tmp_ns;
|
2021-08-30 18:30:18 +00:00
|
|
|
|
|
|
|
free(nvme_ctrlr->copied_ana_desc);
|
|
|
|
spdk_free(nvme_ctrlr->ana_log_page);
|
|
|
|
|
|
|
|
if (nvme_ctrlr->opal_dev) {
|
|
|
|
spdk_opal_dev_destruct(nvme_ctrlr->opal_dev);
|
|
|
|
nvme_ctrlr->opal_dev = NULL;
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
if (nvme_ctrlr->nbdev_ctrlr) {
|
|
|
|
nvme_bdev_ctrlr_delete(nvme_ctrlr->nbdev_ctrlr, nvme_ctrlr);
|
|
|
|
}
|
|
|
|
|
2021-08-25 16:58:16 +00:00
|
|
|
RB_FOREACH_SAFE(ns, nvme_ns_tree, &nvme_ctrlr->namespaces, tmp_ns) {
|
|
|
|
RB_REMOVE(nvme_ns_tree, &nvme_ctrlr->namespaces, ns);
|
2023-01-16 06:43:32 +00:00
|
|
|
nvme_ns_free(ns);
|
2021-08-30 18:30:18 +00:00
|
|
|
}
|
|
|
|
|
2021-09-14 18:26:50 +00:00
|
|
|
TAILQ_FOREACH_SAFE(path_id, &nvme_ctrlr->trids, link, tmp_path) {
|
|
|
|
TAILQ_REMOVE(&nvme_ctrlr->trids, path_id, link);
|
|
|
|
free(path_id);
|
2021-08-30 18:30:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_destroy(&nvme_ctrlr->mutex);
|
|
|
|
|
|
|
|
free(nvme_ctrlr);
|
|
|
|
|
|
|
|
pthread_mutex_lock(&g_bdev_nvme_mutex);
|
2021-09-07 16:13:07 +00:00
|
|
|
if (g_bdev_nvme_module_finish && TAILQ_EMPTY(&g_nvme_bdev_ctrlrs)) {
|
2021-08-30 18:30:18 +00:00
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
2021-09-07 16:13:07 +00:00
|
|
|
spdk_io_device_unregister(&g_nvme_bdev_ctrlrs, NULL);
|
2021-08-30 18:30:18 +00:00
|
|
|
spdk_bdev_module_fini_done();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
|
|
|
}
|
|
|
|
|
2021-07-09 08:51:32 +00:00
|
|
|
static int
|
|
|
|
nvme_detach_poller(void *arg)
|
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = arg;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = spdk_nvme_detach_poll_async(nvme_ctrlr->detach_ctx);
|
|
|
|
if (rc != -EAGAIN) {
|
|
|
|
spdk_poller_unregister(&nvme_ctrlr->reset_detach_poller);
|
|
|
|
_nvme_ctrlr_delete(nvme_ctrlr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SPDK_POLLER_BUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvme_ctrlr_delete(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
2022-01-13 07:03:36 +00:00
|
|
|
spdk_poller_unregister(&nvme_ctrlr->reconnect_delay_timer);
|
|
|
|
|
2021-07-09 08:51:32 +00:00
|
|
|
/* First, unregister the adminq poller, as the driver will poll adminq if necessary */
|
|
|
|
spdk_poller_unregister(&nvme_ctrlr->adminq_timer_poller);
|
|
|
|
|
|
|
|
/* If we got here, the reset/detach poller cannot be active */
|
|
|
|
assert(nvme_ctrlr->reset_detach_poller == NULL);
|
|
|
|
nvme_ctrlr->reset_detach_poller = SPDK_POLLER_REGISTER(nvme_detach_poller,
|
|
|
|
nvme_ctrlr, 1000);
|
|
|
|
if (nvme_ctrlr->reset_detach_poller == NULL) {
|
|
|
|
SPDK_ERRLOG("Failed to register detach poller\n");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = spdk_nvme_detach_async(nvme_ctrlr->ctrlr, &nvme_ctrlr->detach_ctx);
|
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Failed to detach the NVMe controller\n");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
error:
|
|
|
|
/* We don't have a good way to handle errors here, so just do what we can and delete the
|
|
|
|
* controller without detaching the underlying NVMe device.
|
|
|
|
*/
|
|
|
|
spdk_poller_unregister(&nvme_ctrlr->reset_detach_poller);
|
|
|
|
_nvme_ctrlr_delete(nvme_ctrlr);
|
|
|
|
}
|
|
|
|
|
2021-07-08 11:35:21 +00:00
|
|
|
static void
|
|
|
|
nvme_ctrlr_unregister_cb(void *io_device)
|
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = io_device;
|
|
|
|
|
|
|
|
nvme_ctrlr_delete(nvme_ctrlr);
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:07:15 +00:00
|
|
|
static void
|
2022-03-09 06:48:11 +00:00
|
|
|
nvme_ctrlr_unregister(void *ctx)
|
2021-08-30 18:30:18 +00:00
|
|
|
{
|
2022-03-09 06:48:11 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr = ctx;
|
|
|
|
|
2021-08-30 18:30:18 +00:00
|
|
|
spdk_io_device_unregister(nvme_ctrlr, nvme_ctrlr_unregister_cb);
|
|
|
|
}
|
|
|
|
|
2021-11-25 19:50:57 +00:00
|
|
|
static bool
|
|
|
|
nvme_ctrlr_can_be_unregistered(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
if (!nvme_ctrlr->destruct) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nvme_ctrlr->ref > 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nvme_ctrlr->resetting) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nvme_ctrlr->ana_log_page_updating) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-08-09 01:46:48 +00:00
|
|
|
if (nvme_ctrlr->io_path_cache_clearing) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-11-25 19:50:57 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:07:15 +00:00
|
|
|
static void
|
2021-08-30 18:30:18 +00:00
|
|
|
nvme_ctrlr_release(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
2021-12-06 10:57:02 +00:00
|
|
|
SPDK_DTRACE_PROBE2(bdev_nvme_ctrlr_release, nvme_ctrlr->nbdev_ctrlr->name, nvme_ctrlr->ref);
|
2021-08-30 18:30:18 +00:00
|
|
|
|
|
|
|
assert(nvme_ctrlr->ref > 0);
|
|
|
|
nvme_ctrlr->ref--;
|
|
|
|
|
2021-11-25 19:50:57 +00:00
|
|
|
if (!nvme_ctrlr_can_be_unregistered(nvme_ctrlr)) {
|
2021-08-30 18:30:18 +00:00
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
|
2022-03-09 06:48:11 +00:00
|
|
|
spdk_thread_exec_msg(nvme_ctrlr->thread, nvme_ctrlr_unregister, nvme_ctrlr);
|
2021-08-30 18:30:18 +00:00
|
|
|
}
|
|
|
|
|
2022-11-29 08:44:19 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_clear_current_io_path(struct nvme_bdev_channel *nbdev_ch)
|
|
|
|
{
|
|
|
|
nbdev_ch->current_io_path = NULL;
|
2022-10-31 07:13:30 +00:00
|
|
|
nbdev_ch->rr_counter = 0;
|
2022-11-29 08:44:19 +00:00
|
|
|
}
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
static struct nvme_io_path *
|
|
|
|
_bdev_nvme_get_io_path(struct nvme_bdev_channel *nbdev_ch, struct nvme_ns *nvme_ns)
|
|
|
|
{
|
|
|
|
struct nvme_io_path *io_path;
|
|
|
|
|
|
|
|
STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
|
|
|
|
if (io_path->nvme_ns == nvme_ns) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return io_path;
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:07:15 +00:00
|
|
|
static int
|
2021-09-27 23:15:02 +00:00
|
|
|
_bdev_nvme_add_io_path(struct nvme_bdev_channel *nbdev_ch, struct nvme_ns *nvme_ns)
|
2021-08-30 18:30:18 +00:00
|
|
|
{
|
2021-09-27 23:15:02 +00:00
|
|
|
struct nvme_io_path *io_path;
|
2021-08-30 18:30:18 +00:00
|
|
|
struct spdk_io_channel *ch;
|
2022-03-09 06:44:18 +00:00
|
|
|
struct nvme_ctrlr_channel *ctrlr_ch;
|
|
|
|
struct nvme_qpair *nvme_qpair;
|
2021-08-30 18:30:18 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
io_path = calloc(1, sizeof(*io_path));
|
|
|
|
if (io_path == NULL) {
|
|
|
|
SPDK_ERRLOG("Failed to alloc io_path.\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2021-08-30 18:30:18 +00:00
|
|
|
|
2022-09-29 03:52:43 +00:00
|
|
|
if (g_opts.io_path_stat) {
|
|
|
|
io_path->stat = calloc(1, sizeof(struct spdk_bdev_io_stat));
|
|
|
|
if (io_path->stat == NULL) {
|
|
|
|
free(io_path);
|
|
|
|
SPDK_ERRLOG("Failed to alloc io_path stat.\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
spdk_bdev_reset_io_stat(io_path->stat, BDEV_RESET_STAT_MAXMIN);
|
|
|
|
}
|
|
|
|
|
2022-03-07 01:38:34 +00:00
|
|
|
io_path->nvme_ns = nvme_ns;
|
|
|
|
|
2021-08-30 18:30:18 +00:00
|
|
|
ch = spdk_get_io_channel(nvme_ns->ctrlr);
|
|
|
|
if (ch == NULL) {
|
2022-09-29 03:52:43 +00:00
|
|
|
free(io_path->stat);
|
2021-09-27 23:15:02 +00:00
|
|
|
free(io_path);
|
2021-08-30 18:30:18 +00:00
|
|
|
SPDK_ERRLOG("Failed to alloc io_channel.\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
ctrlr_ch = spdk_io_channel_get_ctx(ch);
|
|
|
|
|
|
|
|
nvme_qpair = ctrlr_ch->qpair;
|
|
|
|
assert(nvme_qpair != NULL);
|
|
|
|
|
|
|
|
io_path->qpair = nvme_qpair;
|
|
|
|
TAILQ_INSERT_TAIL(&nvme_qpair->io_path_list, io_path, tailq);
|
2021-10-15 08:10:42 +00:00
|
|
|
|
|
|
|
io_path->nbdev_ch = nbdev_ch;
|
2021-09-27 23:15:02 +00:00
|
|
|
STAILQ_INSERT_TAIL(&nbdev_ch->io_path_list, io_path, stailq);
|
2021-10-15 08:10:42 +00:00
|
|
|
|
2022-11-29 08:44:19 +00:00
|
|
|
bdev_nvme_clear_current_io_path(nbdev_ch);
|
2021-10-15 10:28:09 +00:00
|
|
|
|
2021-08-30 18:30:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:07:15 +00:00
|
|
|
static void
|
2021-09-27 23:15:02 +00:00
|
|
|
_bdev_nvme_delete_io_path(struct nvme_bdev_channel *nbdev_ch, struct nvme_io_path *io_path)
|
2021-08-30 18:30:18 +00:00
|
|
|
{
|
|
|
|
struct spdk_io_channel *ch;
|
2022-03-09 06:44:18 +00:00
|
|
|
struct nvme_qpair *nvme_qpair;
|
|
|
|
struct nvme_ctrlr_channel *ctrlr_ch;
|
2021-08-30 18:30:18 +00:00
|
|
|
|
2022-11-29 08:44:19 +00:00
|
|
|
bdev_nvme_clear_current_io_path(nbdev_ch);
|
2021-10-15 10:28:09 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
STAILQ_REMOVE(&nbdev_ch->io_path_list, io_path, nvme_io_path, stailq);
|
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_qpair = io_path->qpair;
|
|
|
|
assert(nvme_qpair != NULL);
|
|
|
|
|
|
|
|
TAILQ_REMOVE(&nvme_qpair->io_path_list, io_path, tailq);
|
|
|
|
|
|
|
|
ctrlr_ch = nvme_qpair->ctrlr_ch;
|
|
|
|
assert(ctrlr_ch != NULL);
|
|
|
|
|
|
|
|
ch = spdk_io_channel_from_ctx(ctrlr_ch);
|
2021-08-30 18:30:18 +00:00
|
|
|
spdk_put_io_channel(ch);
|
2021-09-27 23:15:02 +00:00
|
|
|
|
2022-09-29 03:52:43 +00:00
|
|
|
free(io_path->stat);
|
2021-09-27 23:15:02 +00:00
|
|
|
free(io_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_bdev_nvme_delete_io_paths(struct nvme_bdev_channel *nbdev_ch)
|
|
|
|
{
|
|
|
|
struct nvme_io_path *io_path, *tmp_io_path;
|
|
|
|
|
|
|
|
STAILQ_FOREACH_SAFE(io_path, &nbdev_ch->io_path_list, stailq, tmp_io_path) {
|
|
|
|
_bdev_nvme_delete_io_path(nbdev_ch, io_path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bdev_nvme_create_bdev_channel_cb(void *io_device, void *ctx_buf)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_channel *nbdev_ch = ctx_buf;
|
|
|
|
struct nvme_bdev *nbdev = io_device;
|
|
|
|
struct nvme_ns *nvme_ns;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
STAILQ_INIT(&nbdev_ch->io_path_list);
|
2021-10-07 22:11:17 +00:00
|
|
|
TAILQ_INIT(&nbdev_ch->retry_io_list);
|
2021-09-27 23:15:02 +00:00
|
|
|
|
|
|
|
pthread_mutex_lock(&nbdev->mutex);
|
2022-08-26 04:06:48 +00:00
|
|
|
|
|
|
|
nbdev_ch->mp_policy = nbdev->mp_policy;
|
2022-09-20 07:12:47 +00:00
|
|
|
nbdev_ch->mp_selector = nbdev->mp_selector;
|
2022-10-31 07:13:30 +00:00
|
|
|
nbdev_ch->rr_min_io = nbdev->rr_min_io;
|
2022-08-26 04:06:48 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
TAILQ_FOREACH(nvme_ns, &nbdev->nvme_ns_list, tailq) {
|
|
|
|
rc = _bdev_nvme_add_io_path(nbdev_ch, nvme_ns);
|
|
|
|
if (rc != 0) {
|
|
|
|
pthread_mutex_unlock(&nbdev->mutex);
|
|
|
|
|
|
|
|
_bdev_nvme_delete_io_paths(nbdev_ch);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&nbdev->mutex);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-11 00:21:53 +00:00
|
|
|
/* If cpl != NULL, complete the bdev_io with nvme status based on 'cpl'.
|
|
|
|
* If cpl == NULL, complete the bdev_io with bdev status based on 'status'.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
__bdev_nvme_io_complete(struct spdk_bdev_io *bdev_io, enum spdk_bdev_io_status status,
|
|
|
|
const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
2022-08-11 00:04:56 +00:00
|
|
|
spdk_trace_record(TRACE_BDEV_NVME_IO_DONE, 0, 0, (uintptr_t)bdev_io->driver_ctx,
|
|
|
|
(uintptr_t)bdev_io);
|
2022-08-11 00:21:53 +00:00
|
|
|
if (cpl) {
|
|
|
|
spdk_bdev_io_complete_nvme_status(bdev_io, cpl->cdw0, cpl->status.sct, cpl->status.sc);
|
|
|
|
} else {
|
|
|
|
spdk_bdev_io_complete(bdev_io, status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-12 04:08:36 +00:00
|
|
|
static void bdev_nvme_abort_retry_ios(struct nvme_bdev_channel *nbdev_ch);
|
2021-10-07 22:11:17 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_destroy_bdev_channel_cb(void *io_device, void *ctx_buf)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_channel *nbdev_ch = ctx_buf;
|
|
|
|
|
2021-10-07 22:11:17 +00:00
|
|
|
bdev_nvme_abort_retry_ios(nbdev_ch);
|
2021-09-27 23:15:02 +00:00
|
|
|
_bdev_nvme_delete_io_paths(nbdev_ch);
|
2021-08-30 18:30:18 +00:00
|
|
|
}
|
|
|
|
|
2021-09-28 07:43:22 +00:00
|
|
|
static inline bool
|
|
|
|
bdev_nvme_io_type_is_admin(enum spdk_bdev_io_type io_type)
|
|
|
|
{
|
|
|
|
switch (io_type) {
|
|
|
|
case SPDK_BDEV_IO_TYPE_RESET:
|
|
|
|
case SPDK_BDEV_IO_TYPE_NVME_ADMIN:
|
|
|
|
case SPDK_BDEV_IO_TYPE_ABORT:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-09-16 11:10:56 +00:00
|
|
|
static inline bool
|
2021-09-16 16:00:49 +00:00
|
|
|
nvme_ns_is_accessible(struct nvme_ns *nvme_ns)
|
|
|
|
{
|
2021-10-18 22:01:30 +00:00
|
|
|
if (spdk_unlikely(nvme_ns->ana_state_updating)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-09-16 16:00:49 +00:00
|
|
|
switch (nvme_ns->ana_state) {
|
|
|
|
case SPDK_NVME_ANA_OPTIMIZED_STATE:
|
|
|
|
case SPDK_NVME_ANA_NON_OPTIMIZED_STATE:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
nvme_io_path_is_connected(struct nvme_io_path *io_path)
|
2021-09-16 11:10:56 +00:00
|
|
|
{
|
2022-03-09 06:53:15 +00:00
|
|
|
if (spdk_unlikely(io_path->qpair->qpair == NULL)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-03-08 03:04:11 +00:00
|
|
|
if (spdk_unlikely(spdk_nvme_qpair_get_failure_reason(io_path->qpair->qpair) !=
|
|
|
|
SPDK_NVME_QPAIR_FAILURE_NONE)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-03-09 06:53:15 +00:00
|
|
|
if (spdk_unlikely(io_path->qpair->ctrlr_ch->reset_iter != NULL)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-01-27 22:03:05 +00:00
|
|
|
if (spdk_nvme_ctrlr_get_admin_qp_failure_reason(io_path->qpair->ctrlr->ctrlr) !=
|
|
|
|
SPDK_NVME_QPAIR_FAILURE_NONE) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-03-09 06:53:15 +00:00
|
|
|
return true;
|
2021-09-16 11:10:56 +00:00
|
|
|
}
|
|
|
|
|
2021-09-16 16:00:49 +00:00
|
|
|
static inline bool
|
|
|
|
nvme_io_path_is_available(struct nvme_io_path *io_path)
|
|
|
|
{
|
|
|
|
if (spdk_unlikely(!nvme_io_path_is_connected(io_path))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spdk_unlikely(!nvme_ns_is_accessible(io_path->nvme_ns))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-24 02:09:59 +00:00
|
|
|
static inline bool
|
2021-10-07 22:11:17 +00:00
|
|
|
nvme_io_path_is_failed(struct nvme_io_path *io_path)
|
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr;
|
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_ctrlr = io_path->qpair->ctrlr;
|
2021-10-07 22:11:17 +00:00
|
|
|
|
2021-11-24 02:09:59 +00:00
|
|
|
if (nvme_ctrlr->destruct) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-01-14 02:02:31 +00:00
|
|
|
if (nvme_ctrlr->fast_io_fail_timedout) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-24 02:09:59 +00:00
|
|
|
if (nvme_ctrlr->resetting) {
|
2022-03-04 04:51:53 +00:00
|
|
|
if (nvme_ctrlr->opts.reconnect_delay_sec != 0) {
|
2022-01-13 07:03:36 +00:00
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nvme_ctrlr->reconnect_is_delayed) {
|
|
|
|
return false;
|
2021-11-24 02:09:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (spdk_nvme_ctrlr_is_failed(nvme_ctrlr->ctrlr)) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
nvme_ctrlr_is_available(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
if (nvme_ctrlr->destruct) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spdk_nvme_ctrlr_is_failed(nvme_ctrlr->ctrlr)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-01-13 07:03:36 +00:00
|
|
|
if (nvme_ctrlr->resetting || nvme_ctrlr->reconnect_is_delayed) {
|
2021-11-24 02:09:59 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2021-10-07 22:11:17 +00:00
|
|
|
}
|
|
|
|
|
2022-04-29 05:37:35 +00:00
|
|
|
/* Simulate circular linked list. */
|
|
|
|
static inline struct nvme_io_path *
|
|
|
|
nvme_io_path_get_next(struct nvme_bdev_channel *nbdev_ch, struct nvme_io_path *prev_path)
|
|
|
|
{
|
|
|
|
struct nvme_io_path *next_path;
|
|
|
|
|
2023-01-09 12:59:40 +00:00
|
|
|
if (prev_path != NULL) {
|
|
|
|
next_path = STAILQ_NEXT(prev_path, stailq);
|
|
|
|
if (next_path != NULL) {
|
|
|
|
return next_path;
|
2022-04-29 05:37:35 +00:00
|
|
|
}
|
2023-01-09 12:59:40 +00:00
|
|
|
}
|
2022-04-29 05:37:35 +00:00
|
|
|
|
2023-01-09 12:59:40 +00:00
|
|
|
return STAILQ_FIRST(&nbdev_ch->io_path_list);
|
2022-04-29 05:37:35 +00:00
|
|
|
}
|
|
|
|
|
2022-03-16 07:36:49 +00:00
|
|
|
static struct nvme_io_path *
|
|
|
|
_bdev_nvme_find_io_path(struct nvme_bdev_channel *nbdev_ch)
|
2021-06-01 17:10:38 +00:00
|
|
|
{
|
2023-01-09 12:24:13 +00:00
|
|
|
struct nvme_io_path *io_path, *start, *non_optimized = NULL;
|
2021-09-27 23:15:02 +00:00
|
|
|
|
2023-01-09 12:59:40 +00:00
|
|
|
start = nvme_io_path_get_next(nbdev_ch, nbdev_ch->current_io_path);
|
2021-09-27 23:15:02 +00:00
|
|
|
|
2023-01-09 12:24:13 +00:00
|
|
|
io_path = start;
|
|
|
|
do {
|
|
|
|
if (spdk_likely(nvme_io_path_is_connected(io_path) &&
|
|
|
|
!io_path->nvme_ns->ana_state_updating)) {
|
|
|
|
switch (io_path->nvme_ns->ana_state) {
|
|
|
|
case SPDK_NVME_ANA_OPTIMIZED_STATE:
|
|
|
|
nbdev_ch->current_io_path = io_path;
|
|
|
|
return io_path;
|
|
|
|
case SPDK_NVME_ANA_NON_OPTIMIZED_STATE:
|
|
|
|
if (non_optimized == NULL) {
|
|
|
|
non_optimized = io_path;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2021-09-16 16:00:49 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-09 12:24:13 +00:00
|
|
|
io_path = nvme_io_path_get_next(nbdev_ch, io_path);
|
|
|
|
} while (io_path != start);
|
2021-06-01 17:10:38 +00:00
|
|
|
|
2023-01-09 12:59:40 +00:00
|
|
|
if (nbdev_ch->mp_policy == BDEV_NVME_MP_POLICY_ACTIVE_ACTIVE) {
|
|
|
|
/* We come here only if there is no optimized path. Cache even non_optimized
|
|
|
|
* path for load balance across multiple non_optimized paths.
|
|
|
|
*/
|
|
|
|
nbdev_ch->current_io_path = non_optimized;
|
|
|
|
}
|
|
|
|
|
2021-09-16 16:00:49 +00:00
|
|
|
return non_optimized;
|
2021-06-01 17:10:38 +00:00
|
|
|
}
|
|
|
|
|
2022-09-20 07:12:47 +00:00
|
|
|
static struct nvme_io_path *
|
|
|
|
_bdev_nvme_find_io_path_min_qd(struct nvme_bdev_channel *nbdev_ch)
|
|
|
|
{
|
|
|
|
struct nvme_io_path *io_path;
|
|
|
|
struct nvme_io_path *optimized = NULL, *non_optimized = NULL;
|
|
|
|
uint32_t opt_min_qd = UINT32_MAX, non_opt_min_qd = UINT32_MAX;
|
|
|
|
uint32_t num_outstanding_reqs;
|
|
|
|
|
|
|
|
STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
|
|
|
|
if (spdk_unlikely(!nvme_io_path_is_connected(io_path))) {
|
|
|
|
/* The device is currently resetting. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spdk_unlikely(io_path->nvme_ns->ana_state_updating)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_outstanding_reqs = spdk_nvme_qpair_get_num_outstanding_reqs(io_path->qpair->qpair);
|
|
|
|
switch (io_path->nvme_ns->ana_state) {
|
|
|
|
case SPDK_NVME_ANA_OPTIMIZED_STATE:
|
|
|
|
if (num_outstanding_reqs < opt_min_qd) {
|
|
|
|
opt_min_qd = num_outstanding_reqs;
|
|
|
|
optimized = io_path;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPDK_NVME_ANA_NON_OPTIMIZED_STATE:
|
|
|
|
if (num_outstanding_reqs < non_opt_min_qd) {
|
|
|
|
non_opt_min_qd = num_outstanding_reqs;
|
|
|
|
non_optimized = io_path;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* don't cache io path for BDEV_NVME_MP_SELECTOR_QUEUE_DEPTH selector */
|
|
|
|
if (optimized != NULL) {
|
|
|
|
return optimized;
|
|
|
|
}
|
|
|
|
|
|
|
|
return non_optimized;
|
|
|
|
}
|
|
|
|
|
2022-03-16 07:36:49 +00:00
|
|
|
static inline struct nvme_io_path *
|
|
|
|
bdev_nvme_find_io_path(struct nvme_bdev_channel *nbdev_ch)
|
|
|
|
{
|
2022-10-31 07:13:30 +00:00
|
|
|
if (spdk_likely(nbdev_ch->current_io_path != NULL)) {
|
|
|
|
if (nbdev_ch->mp_policy == BDEV_NVME_MP_POLICY_ACTIVE_PASSIVE) {
|
|
|
|
return nbdev_ch->current_io_path;
|
|
|
|
} else if (nbdev_ch->mp_selector == BDEV_NVME_MP_SELECTOR_ROUND_ROBIN) {
|
|
|
|
if (++nbdev_ch->rr_counter < nbdev_ch->rr_min_io) {
|
|
|
|
return nbdev_ch->current_io_path;
|
|
|
|
}
|
|
|
|
nbdev_ch->rr_counter = 0;
|
|
|
|
}
|
2022-04-29 05:37:35 +00:00
|
|
|
}
|
2023-01-09 13:14:58 +00:00
|
|
|
|
2022-09-20 07:12:47 +00:00
|
|
|
if (nbdev_ch->mp_policy == BDEV_NVME_MP_POLICY_ACTIVE_PASSIVE ||
|
|
|
|
nbdev_ch->mp_selector == BDEV_NVME_MP_SELECTOR_ROUND_ROBIN) {
|
|
|
|
return _bdev_nvme_find_io_path(nbdev_ch);
|
|
|
|
} else {
|
|
|
|
return _bdev_nvme_find_io_path_min_qd(nbdev_ch);
|
|
|
|
}
|
2022-03-16 07:36:49 +00:00
|
|
|
}
|
|
|
|
|
2021-10-07 22:11:17 +00:00
|
|
|
/* Return true if there is any io_path whose qpair is active or ctrlr is not failed,
|
|
|
|
* or false otherwise.
|
|
|
|
*
|
|
|
|
* If any io_path has an active qpair but find_io_path() returned NULL, its namespace
|
|
|
|
* is likely to be non-accessible now but may become accessible.
|
|
|
|
*
|
|
|
|
* If any io_path has an unfailed ctrlr but find_io_path() returned NULL, the ctrlr
|
2021-11-25 01:40:58 +00:00
|
|
|
* is likely to be resetting now but the reset may succeed. A ctrlr is set to unfailed
|
2021-10-07 22:11:17 +00:00
|
|
|
* when starting to reset it but it is set to failed when the reset failed. Hence, if
|
|
|
|
* a ctrlr is unfailed, it is likely that it works fine or is resetting.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
any_io_path_may_become_available(struct nvme_bdev_channel *nbdev_ch)
|
|
|
|
{
|
|
|
|
struct nvme_io_path *io_path;
|
|
|
|
|
|
|
|
STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
|
2022-04-07 08:29:05 +00:00
|
|
|
if (io_path->nvme_ns->ana_transition_timedout) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-10-07 22:11:17 +00:00
|
|
|
if (nvme_io_path_is_connected(io_path) ||
|
|
|
|
!nvme_io_path_is_failed(io_path)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
bdev/nvme: Retry I/O to the same path if error is I/O error
When an I/O gets an I/O error, the I/O path to which the I/O was
submitted may be still available. In this case, the I/O should be
retried to the same I/O path. However, a new I/O path was always
selected for an I/O retry.
For the active/passive policy, the same I/O path was selected naturally.
However, for the active/active policy, it was very likely that a
different I/O path was selected.
To use the same I/O path for an I/O retry, add a helper function
bdev_nvme_retry_io() into bdev_nvme_retry_ios() and replace
bdev_nvme_submit_request() by bdev_nvme_retry_io(). bdev_nvme_retry_io()
checks if nbdev_io->io_path is not NULL and is available. Then, call
_bdev_nvme_submit_request() if true, or call bdev_nvme_submit_request()
otherwise. For I/O path error, clear nbdev_io->io_path for
clarification. Add unit test to verify this change.
Linux kernel native NVMe multipath already takes this approach. Hence,
this change will be reasonable.
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I7022aafd8b1cdd5830c4f743d64b080aa970cf8d
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16015
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Richael <richael.zhuang@arm.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
2022-12-26 07:31:33 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_retry_io(struct nvme_bdev_channel *nbdev_ch, struct spdk_bdev_io *bdev_io)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_io *nbdev_io = (struct nvme_bdev_io *)bdev_io->driver_ctx;
|
|
|
|
struct spdk_io_channel *ch;
|
|
|
|
|
|
|
|
if (nbdev_io->io_path != NULL && nvme_io_path_is_available(nbdev_io->io_path)) {
|
|
|
|
_bdev_nvme_submit_request(nbdev_ch, bdev_io);
|
|
|
|
} else {
|
|
|
|
ch = spdk_io_channel_from_ctx(nbdev_ch);
|
|
|
|
bdev_nvme_submit_request(ch, bdev_io);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-07 22:11:17 +00:00
|
|
|
static int
|
|
|
|
bdev_nvme_retry_ios(void *arg)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_channel *nbdev_ch = arg;
|
|
|
|
struct spdk_bdev_io *bdev_io, *tmp_bdev_io;
|
|
|
|
struct nvme_bdev_io *bio;
|
|
|
|
uint64_t now, delay_us;
|
|
|
|
|
|
|
|
now = spdk_get_ticks();
|
|
|
|
|
|
|
|
TAILQ_FOREACH_SAFE(bdev_io, &nbdev_ch->retry_io_list, module_link, tmp_bdev_io) {
|
|
|
|
bio = (struct nvme_bdev_io *)bdev_io->driver_ctx;
|
|
|
|
if (bio->retry_ticks > now) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_REMOVE(&nbdev_ch->retry_io_list, bdev_io, module_link);
|
|
|
|
|
bdev/nvme: Retry I/O to the same path if error is I/O error
When an I/O gets an I/O error, the I/O path to which the I/O was
submitted may be still available. In this case, the I/O should be
retried to the same I/O path. However, a new I/O path was always
selected for an I/O retry.
For the active/passive policy, the same I/O path was selected naturally.
However, for the active/active policy, it was very likely that a
different I/O path was selected.
To use the same I/O path for an I/O retry, add a helper function
bdev_nvme_retry_io() into bdev_nvme_retry_ios() and replace
bdev_nvme_submit_request() by bdev_nvme_retry_io(). bdev_nvme_retry_io()
checks if nbdev_io->io_path is not NULL and is available. Then, call
_bdev_nvme_submit_request() if true, or call bdev_nvme_submit_request()
otherwise. For I/O path error, clear nbdev_io->io_path for
clarification. Add unit test to verify this change.
Linux kernel native NVMe multipath already takes this approach. Hence,
this change will be reasonable.
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I7022aafd8b1cdd5830c4f743d64b080aa970cf8d
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16015
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Richael <richael.zhuang@arm.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
2022-12-26 07:31:33 +00:00
|
|
|
bdev_nvme_retry_io(nbdev_ch, bdev_io);
|
2021-10-07 22:11:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
spdk_poller_unregister(&nbdev_ch->retry_io_poller);
|
|
|
|
|
|
|
|
bdev_io = TAILQ_FIRST(&nbdev_ch->retry_io_list);
|
|
|
|
if (bdev_io != NULL) {
|
|
|
|
bio = (struct nvme_bdev_io *)bdev_io->driver_ctx;
|
|
|
|
|
|
|
|
delay_us = (bio->retry_ticks - now) * SPDK_SEC_TO_USEC / spdk_get_ticks_hz();
|
|
|
|
|
|
|
|
nbdev_ch->retry_io_poller = SPDK_POLLER_REGISTER(bdev_nvme_retry_ios, nbdev_ch,
|
|
|
|
delay_us);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SPDK_POLLER_BUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_queue_retry_io(struct nvme_bdev_channel *nbdev_ch,
|
|
|
|
struct nvme_bdev_io *bio, uint64_t delay_ms)
|
|
|
|
{
|
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
|
|
|
struct spdk_bdev_io *tmp_bdev_io;
|
|
|
|
struct nvme_bdev_io *tmp_bio;
|
|
|
|
|
|
|
|
bio->retry_ticks = spdk_get_ticks() + delay_ms * spdk_get_ticks_hz() / 1000ULL;
|
|
|
|
|
|
|
|
TAILQ_FOREACH_REVERSE(tmp_bdev_io, &nbdev_ch->retry_io_list, retry_io_head, module_link) {
|
|
|
|
tmp_bio = (struct nvme_bdev_io *)tmp_bdev_io->driver_ctx;
|
|
|
|
|
|
|
|
if (tmp_bio->retry_ticks <= bio->retry_ticks) {
|
|
|
|
TAILQ_INSERT_AFTER(&nbdev_ch->retry_io_list, tmp_bdev_io, bdev_io,
|
|
|
|
module_link);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No earlier I/Os were found. This I/O must be the new head. */
|
|
|
|
TAILQ_INSERT_HEAD(&nbdev_ch->retry_io_list, bdev_io, module_link);
|
|
|
|
|
|
|
|
spdk_poller_unregister(&nbdev_ch->retry_io_poller);
|
|
|
|
|
|
|
|
nbdev_ch->retry_io_poller = SPDK_POLLER_REGISTER(bdev_nvme_retry_ios, nbdev_ch,
|
|
|
|
delay_ms * 1000ULL);
|
|
|
|
}
|
|
|
|
|
2023-01-12 04:08:36 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_abort_retry_ios(struct nvme_bdev_channel *nbdev_ch)
|
|
|
|
{
|
|
|
|
struct spdk_bdev_io *bdev_io, *tmp_io;
|
|
|
|
|
|
|
|
TAILQ_FOREACH_SAFE(bdev_io, &nbdev_ch->retry_io_list, module_link, tmp_io) {
|
|
|
|
TAILQ_REMOVE(&nbdev_ch->retry_io_list, bdev_io, module_link);
|
|
|
|
__bdev_nvme_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_ABORTED, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_poller_unregister(&nbdev_ch->retry_io_poller);
|
|
|
|
}
|
|
|
|
|
2023-01-12 04:09:27 +00:00
|
|
|
static int
|
|
|
|
bdev_nvme_abort_retry_io(struct nvme_bdev_channel *nbdev_ch,
|
|
|
|
struct nvme_bdev_io *bio_to_abort)
|
|
|
|
{
|
|
|
|
struct spdk_bdev_io *bdev_io_to_abort;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(bdev_io_to_abort, &nbdev_ch->retry_io_list, module_link) {
|
|
|
|
if ((struct nvme_bdev_io *)bdev_io_to_abort->driver_ctx == bio_to_abort) {
|
|
|
|
TAILQ_REMOVE(&nbdev_ch->retry_io_list, bdev_io_to_abort, module_link);
|
|
|
|
__bdev_nvme_io_complete(bdev_io_to_abort, SPDK_BDEV_IO_STATUS_ABORTED, NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
bdev/nvme: Count number of NVMe errors per type or code
Error counters for NVMe error was added in the generic bdev layer but
we want to know more detailed information for some use cases.
Add NVMe error counters per type and per code as module specific
statistics.
For status codes, the first idea was to have different named member
for each status code value. However, it was bad and too hard to test,
review, and maintain.
Instead, we have just two dimensional uint32_t arrays, and increment
one of these uint32_t values based on the status code type and status
code. Then, when dump the JSON, we use spdk_nvme_cpl_get_status_string()
and spdk_nvme_cpl_get_status_type_string().
This idea has one potential downside. This idea consumes 4 (types) *
256 (codes) * 4 (counter) = 4KB per NVMe bdev. We can make this smarter
if memory allocation is a problem. Hence we add an option
nvme_error_stat to enable this feature only if the user requests.
Additionally, the string returned by spdk_nvme_cpl_get_status_string()
or spdk_nvme_cpl_get_status_type_string() has uppercases, spaces, and
hyphens. These should not be included in JSON strings. Hence, convert
these via spdk_strcpy_replace().
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I07b07621e777bdf6556b95054abbbb65e5f9ea3e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15370
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
2023-01-05 23:26:33 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_update_nvme_error_stat(struct spdk_bdev_io *bdev_io, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
|
|
|
struct nvme_bdev *nbdev;
|
|
|
|
uint16_t sct, sc;
|
|
|
|
|
|
|
|
assert(spdk_nvme_cpl_is_error(cpl));
|
|
|
|
|
|
|
|
nbdev = bdev_io->bdev->ctxt;
|
|
|
|
|
|
|
|
if (nbdev->err_stat == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sct = cpl->status.sct;
|
|
|
|
sc = cpl->status.sc;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&nbdev->mutex);
|
|
|
|
|
|
|
|
nbdev->err_stat->status_type[sct]++;
|
|
|
|
switch (sct) {
|
|
|
|
case SPDK_NVME_SCT_GENERIC:
|
|
|
|
case SPDK_NVME_SCT_COMMAND_SPECIFIC:
|
|
|
|
case SPDK_NVME_SCT_MEDIA_ERROR:
|
|
|
|
case SPDK_NVME_SCT_PATH:
|
|
|
|
nbdev->err_stat->status[sct][sc]++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&nbdev->mutex);
|
|
|
|
}
|
|
|
|
|
2022-09-29 03:52:43 +00:00
|
|
|
static inline void
|
|
|
|
bdev_nvme_update_io_path_stat(struct nvme_bdev_io *bio)
|
|
|
|
{
|
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
|
|
|
uint64_t num_blocks = bdev_io->u.bdev.num_blocks;
|
|
|
|
uint32_t blocklen = bdev_io->bdev->blocklen;
|
|
|
|
struct spdk_bdev_io_stat *stat;
|
|
|
|
uint64_t tsc_diff;
|
|
|
|
|
|
|
|
if (bio->io_path->stat == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
tsc_diff = spdk_get_ticks() - bio->submit_tsc;
|
|
|
|
stat = bio->io_path->stat;
|
|
|
|
|
|
|
|
switch (bdev_io->type) {
|
|
|
|
case SPDK_BDEV_IO_TYPE_READ:
|
|
|
|
stat->bytes_read += num_blocks * blocklen;
|
|
|
|
stat->num_read_ops++;
|
|
|
|
stat->read_latency_ticks += tsc_diff;
|
|
|
|
if (stat->max_read_latency_ticks < tsc_diff) {
|
|
|
|
stat->max_read_latency_ticks = tsc_diff;
|
|
|
|
}
|
|
|
|
if (stat->min_read_latency_ticks > tsc_diff) {
|
|
|
|
stat->min_read_latency_ticks = tsc_diff;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPDK_BDEV_IO_TYPE_WRITE:
|
|
|
|
stat->bytes_written += num_blocks * blocklen;
|
|
|
|
stat->num_write_ops++;
|
|
|
|
stat->write_latency_ticks += tsc_diff;
|
|
|
|
if (stat->max_write_latency_ticks < tsc_diff) {
|
|
|
|
stat->max_write_latency_ticks = tsc_diff;
|
|
|
|
}
|
|
|
|
if (stat->min_write_latency_ticks > tsc_diff) {
|
|
|
|
stat->min_write_latency_ticks = tsc_diff;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPDK_BDEV_IO_TYPE_UNMAP:
|
|
|
|
stat->bytes_unmapped += num_blocks * blocklen;
|
|
|
|
stat->num_unmap_ops++;
|
|
|
|
stat->unmap_latency_ticks += tsc_diff;
|
|
|
|
if (stat->max_unmap_latency_ticks < tsc_diff) {
|
|
|
|
stat->max_unmap_latency_ticks = tsc_diff;
|
|
|
|
}
|
|
|
|
if (stat->min_unmap_latency_ticks > tsc_diff) {
|
|
|
|
stat->min_unmap_latency_ticks = tsc_diff;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPDK_BDEV_IO_TYPE_ZCOPY:
|
|
|
|
/* Track the data in the start phase only */
|
|
|
|
if (!bdev_io->u.bdev.zcopy.start) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (bdev_io->u.bdev.zcopy.populate) {
|
|
|
|
stat->bytes_read += num_blocks * blocklen;
|
|
|
|
stat->num_read_ops++;
|
|
|
|
stat->read_latency_ticks += tsc_diff;
|
|
|
|
if (stat->max_read_latency_ticks < tsc_diff) {
|
|
|
|
stat->max_read_latency_ticks = tsc_diff;
|
|
|
|
}
|
|
|
|
if (stat->min_read_latency_ticks > tsc_diff) {
|
|
|
|
stat->min_read_latency_ticks = tsc_diff;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
stat->bytes_written += num_blocks * blocklen;
|
|
|
|
stat->num_write_ops++;
|
|
|
|
stat->write_latency_ticks += tsc_diff;
|
|
|
|
if (stat->max_write_latency_ticks < tsc_diff) {
|
|
|
|
stat->max_write_latency_ticks = tsc_diff;
|
|
|
|
}
|
|
|
|
if (stat->min_write_latency_ticks > tsc_diff) {
|
|
|
|
stat->min_write_latency_ticks = tsc_diff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPDK_BDEV_IO_TYPE_COPY:
|
|
|
|
stat->bytes_copied += num_blocks * blocklen;
|
|
|
|
stat->num_copy_ops++;
|
|
|
|
stat->copy_latency_ticks += tsc_diff;
|
|
|
|
if (stat->max_copy_latency_ticks < tsc_diff) {
|
|
|
|
stat->max_copy_latency_ticks = tsc_diff;
|
|
|
|
}
|
|
|
|
if (stat->min_copy_latency_ticks > tsc_diff) {
|
|
|
|
stat->min_copy_latency_ticks = tsc_diff;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-12 20:56:42 +00:00
|
|
|
static inline void
|
|
|
|
bdev_nvme_io_complete_nvme_status(struct nvme_bdev_io *bio,
|
|
|
|
const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
2021-10-08 08:55:15 +00:00
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
|
|
|
struct nvme_bdev_channel *nbdev_ch;
|
2023-01-10 06:42:29 +00:00
|
|
|
struct nvme_io_path *io_path;
|
2021-10-25 02:59:46 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr;
|
|
|
|
const struct spdk_nvme_ctrlr_data *cdata;
|
|
|
|
uint64_t delay_ms;
|
2021-10-08 08:55:15 +00:00
|
|
|
|
2021-10-18 13:15:32 +00:00
|
|
|
assert(!bdev_nvme_io_type_is_admin(bdev_io->type));
|
|
|
|
|
2021-10-08 08:55:15 +00:00
|
|
|
if (spdk_likely(spdk_nvme_cpl_is_success(cpl))) {
|
2022-09-29 03:52:43 +00:00
|
|
|
bdev_nvme_update_io_path_stat(bio);
|
2021-10-08 08:55:15 +00:00
|
|
|
goto complete;
|
|
|
|
}
|
|
|
|
|
bdev/nvme: Count number of NVMe errors per type or code
Error counters for NVMe error was added in the generic bdev layer but
we want to know more detailed information for some use cases.
Add NVMe error counters per type and per code as module specific
statistics.
For status codes, the first idea was to have different named member
for each status code value. However, it was bad and too hard to test,
review, and maintain.
Instead, we have just two dimensional uint32_t arrays, and increment
one of these uint32_t values based on the status code type and status
code. Then, when dump the JSON, we use spdk_nvme_cpl_get_status_string()
and spdk_nvme_cpl_get_status_type_string().
This idea has one potential downside. This idea consumes 4 (types) *
256 (codes) * 4 (counter) = 4KB per NVMe bdev. We can make this smarter
if memory allocation is a problem. Hence we add an option
nvme_error_stat to enable this feature only if the user requests.
Additionally, the string returned by spdk_nvme_cpl_get_status_string()
or spdk_nvme_cpl_get_status_type_string() has uppercases, spaces, and
hyphens. These should not be included in JSON strings. Hence, convert
these via spdk_strcpy_replace().
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I07b07621e777bdf6556b95054abbbb65e5f9ea3e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15370
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
2023-01-05 23:26:33 +00:00
|
|
|
/* Update error counts before deciding if retry is needed.
|
|
|
|
* Hence, error counts may be more than the number of I/O errors.
|
|
|
|
*/
|
|
|
|
bdev_nvme_update_nvme_error_stat(bdev_io, cpl);
|
|
|
|
|
2022-08-18 02:00:01 +00:00
|
|
|
if (cpl->status.dnr != 0 || spdk_nvme_cpl_is_aborted_by_request(cpl) ||
|
|
|
|
(g_opts.bdev_retry_count != -1 && bio->retry_count >= g_opts.bdev_retry_count)) {
|
2021-10-08 08:55:15 +00:00
|
|
|
goto complete;
|
|
|
|
}
|
|
|
|
|
|
|
|
nbdev_ch = spdk_io_channel_get_ctx(spdk_bdev_io_get_io_channel(bdev_io));
|
|
|
|
|
2022-12-16 02:39:39 +00:00
|
|
|
assert(bio->io_path != NULL);
|
2023-01-10 06:42:29 +00:00
|
|
|
io_path = bio->io_path;
|
|
|
|
|
|
|
|
nvme_ctrlr = io_path->qpair->ctrlr;
|
2021-10-08 08:55:15 +00:00
|
|
|
|
|
|
|
if (spdk_nvme_cpl_is_path_error(cpl) ||
|
|
|
|
spdk_nvme_cpl_is_aborted_sq_deletion(cpl) ||
|
2023-01-10 06:42:29 +00:00
|
|
|
!nvme_io_path_is_available(io_path) ||
|
2021-11-24 02:09:59 +00:00
|
|
|
!nvme_ctrlr_is_available(nvme_ctrlr)) {
|
2022-11-29 08:44:19 +00:00
|
|
|
bdev_nvme_clear_current_io_path(nbdev_ch);
|
bdev/nvme: Retry I/O to the same path if error is I/O error
When an I/O gets an I/O error, the I/O path to which the I/O was
submitted may be still available. In this case, the I/O should be
retried to the same I/O path. However, a new I/O path was always
selected for an I/O retry.
For the active/passive policy, the same I/O path was selected naturally.
However, for the active/active policy, it was very likely that a
different I/O path was selected.
To use the same I/O path for an I/O retry, add a helper function
bdev_nvme_retry_io() into bdev_nvme_retry_ios() and replace
bdev_nvme_submit_request() by bdev_nvme_retry_io(). bdev_nvme_retry_io()
checks if nbdev_io->io_path is not NULL and is available. Then, call
_bdev_nvme_submit_request() if true, or call bdev_nvme_submit_request()
otherwise. For I/O path error, clear nbdev_io->io_path for
clarification. Add unit test to verify this change.
Linux kernel native NVMe multipath already takes this approach. Hence,
this change will be reasonable.
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I7022aafd8b1cdd5830c4f743d64b080aa970cf8d
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16015
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Richael <richael.zhuang@arm.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
2022-12-26 07:31:33 +00:00
|
|
|
bio->io_path = NULL;
|
2021-10-18 22:01:30 +00:00
|
|
|
if (spdk_nvme_cpl_is_ana_error(cpl)) {
|
2022-02-03 22:14:10 +00:00
|
|
|
if (nvme_ctrlr_read_ana_log_page(nvme_ctrlr) == 0) {
|
2023-01-10 06:42:29 +00:00
|
|
|
io_path->nvme_ns->ana_state_updating = true;
|
2022-02-03 22:14:10 +00:00
|
|
|
}
|
2021-10-18 22:01:30 +00:00
|
|
|
}
|
bdev/nvme: Retry I/O to the same path if error is I/O error
When an I/O gets an I/O error, the I/O path to which the I/O was
submitted may be still available. In this case, the I/O should be
retried to the same I/O path. However, a new I/O path was always
selected for an I/O retry.
For the active/passive policy, the same I/O path was selected naturally.
However, for the active/active policy, it was very likely that a
different I/O path was selected.
To use the same I/O path for an I/O retry, add a helper function
bdev_nvme_retry_io() into bdev_nvme_retry_ios() and replace
bdev_nvme_submit_request() by bdev_nvme_retry_io(). bdev_nvme_retry_io()
checks if nbdev_io->io_path is not NULL and is available. Then, call
_bdev_nvme_submit_request() if true, or call bdev_nvme_submit_request()
otherwise. For I/O path error, clear nbdev_io->io_path for
clarification. Add unit test to verify this change.
Linux kernel native NVMe multipath already takes this approach. Hence,
this change will be reasonable.
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I7022aafd8b1cdd5830c4f743d64b080aa970cf8d
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16015
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Richael <richael.zhuang@arm.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
2022-12-26 07:31:33 +00:00
|
|
|
if (!any_io_path_may_become_available(nbdev_ch)) {
|
|
|
|
goto complete;
|
|
|
|
}
|
2021-10-25 02:59:46 +00:00
|
|
|
delay_ms = 0;
|
|
|
|
} else {
|
|
|
|
bio->retry_count++;
|
|
|
|
|
|
|
|
cdata = spdk_nvme_ctrlr_get_data(nvme_ctrlr->ctrlr);
|
|
|
|
|
|
|
|
if (cpl->status.crd != 0) {
|
|
|
|
delay_ms = cdata->crdt[cpl->status.crd] * 100;
|
|
|
|
} else {
|
|
|
|
delay_ms = 0;
|
2021-10-08 08:55:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
bdev/nvme: Retry I/O to the same path if error is I/O error
When an I/O gets an I/O error, the I/O path to which the I/O was
submitted may be still available. In this case, the I/O should be
retried to the same I/O path. However, a new I/O path was always
selected for an I/O retry.
For the active/passive policy, the same I/O path was selected naturally.
However, for the active/active policy, it was very likely that a
different I/O path was selected.
To use the same I/O path for an I/O retry, add a helper function
bdev_nvme_retry_io() into bdev_nvme_retry_ios() and replace
bdev_nvme_submit_request() by bdev_nvme_retry_io(). bdev_nvme_retry_io()
checks if nbdev_io->io_path is not NULL and is available. Then, call
_bdev_nvme_submit_request() if true, or call bdev_nvme_submit_request()
otherwise. For I/O path error, clear nbdev_io->io_path for
clarification. Add unit test to verify this change.
Linux kernel native NVMe multipath already takes this approach. Hence,
this change will be reasonable.
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I7022aafd8b1cdd5830c4f743d64b080aa970cf8d
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16015
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Richael <richael.zhuang@arm.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
2022-12-26 07:31:33 +00:00
|
|
|
bdev_nvme_queue_retry_io(nbdev_ch, bio, delay_ms);
|
|
|
|
return;
|
2021-10-25 02:59:46 +00:00
|
|
|
|
2021-10-08 08:55:15 +00:00
|
|
|
complete:
|
2021-10-25 02:59:46 +00:00
|
|
|
bio->retry_count = 0;
|
2022-09-29 03:52:43 +00:00
|
|
|
bio->submit_tsc = 0;
|
2022-08-11 00:21:53 +00:00
|
|
|
__bdev_nvme_io_complete(bdev_io, 0, cpl);
|
2021-05-12 20:56:42 +00:00
|
|
|
}
|
|
|
|
|
2021-04-20 22:54:59 +00:00
|
|
|
static inline void
|
|
|
|
bdev_nvme_io_complete(struct nvme_bdev_io *bio, int rc)
|
|
|
|
{
|
2021-10-07 22:11:17 +00:00
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
|
|
|
struct nvme_bdev_channel *nbdev_ch;
|
2021-04-20 22:54:59 +00:00
|
|
|
enum spdk_bdev_io_status io_status;
|
|
|
|
|
2021-10-07 22:11:17 +00:00
|
|
|
switch (rc) {
|
|
|
|
case 0:
|
2021-04-20 22:54:59 +00:00
|
|
|
io_status = SPDK_BDEV_IO_STATUS_SUCCESS;
|
2021-10-07 22:11:17 +00:00
|
|
|
break;
|
|
|
|
case -ENOMEM:
|
2021-04-20 22:54:59 +00:00
|
|
|
io_status = SPDK_BDEV_IO_STATUS_NOMEM;
|
2021-10-07 22:11:17 +00:00
|
|
|
break;
|
|
|
|
case -ENXIO:
|
|
|
|
nbdev_ch = spdk_io_channel_get_ctx(spdk_bdev_io_get_io_channel(bdev_io));
|
|
|
|
|
2022-11-29 08:44:19 +00:00
|
|
|
bdev_nvme_clear_current_io_path(nbdev_ch);
|
bdev/nvme: Retry I/O to the same path if error is I/O error
When an I/O gets an I/O error, the I/O path to which the I/O was
submitted may be still available. In this case, the I/O should be
retried to the same I/O path. However, a new I/O path was always
selected for an I/O retry.
For the active/passive policy, the same I/O path was selected naturally.
However, for the active/active policy, it was very likely that a
different I/O path was selected.
To use the same I/O path for an I/O retry, add a helper function
bdev_nvme_retry_io() into bdev_nvme_retry_ios() and replace
bdev_nvme_submit_request() by bdev_nvme_retry_io(). bdev_nvme_retry_io()
checks if nbdev_io->io_path is not NULL and is available. Then, call
_bdev_nvme_submit_request() if true, or call bdev_nvme_submit_request()
otherwise. For I/O path error, clear nbdev_io->io_path for
clarification. Add unit test to verify this change.
Linux kernel native NVMe multipath already takes this approach. Hence,
this change will be reasonable.
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I7022aafd8b1cdd5830c4f743d64b080aa970cf8d
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16015
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Richael <richael.zhuang@arm.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
2022-12-26 07:31:33 +00:00
|
|
|
bio->io_path = NULL;
|
2021-10-15 10:28:09 +00:00
|
|
|
|
2021-10-18 13:15:32 +00:00
|
|
|
if (any_io_path_may_become_available(nbdev_ch)) {
|
2021-10-07 22:11:17 +00:00
|
|
|
bdev_nvme_queue_retry_io(nbdev_ch, bio, 1000ULL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fallthrough */
|
|
|
|
default:
|
2021-04-20 22:54:59 +00:00
|
|
|
io_status = SPDK_BDEV_IO_STATUS_FAILED;
|
2021-10-07 22:11:17 +00:00
|
|
|
break;
|
2021-04-20 22:54:59 +00:00
|
|
|
}
|
|
|
|
|
2021-10-25 02:59:46 +00:00
|
|
|
bio->retry_count = 0;
|
2022-09-29 03:52:43 +00:00
|
|
|
bio->submit_tsc = 0;
|
2022-08-11 00:21:53 +00:00
|
|
|
__bdev_nvme_io_complete(bdev_io, io_status, NULL);
|
2021-04-20 22:54:59 +00:00
|
|
|
}
|
|
|
|
|
2021-10-18 13:15:32 +00:00
|
|
|
static inline void
|
|
|
|
bdev_nvme_admin_passthru_complete(struct nvme_bdev_io *bio, int rc)
|
|
|
|
{
|
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
|
|
|
enum spdk_bdev_io_status io_status;
|
|
|
|
|
|
|
|
switch (rc) {
|
|
|
|
case 0:
|
|
|
|
io_status = SPDK_BDEV_IO_STATUS_SUCCESS;
|
|
|
|
break;
|
|
|
|
case -ENOMEM:
|
|
|
|
io_status = SPDK_BDEV_IO_STATUS_NOMEM;
|
|
|
|
break;
|
2021-11-18 17:29:28 +00:00
|
|
|
case -ENXIO:
|
|
|
|
/* fallthrough */
|
2021-10-18 13:15:32 +00:00
|
|
|
default:
|
|
|
|
io_status = SPDK_BDEV_IO_STATUS_FAILED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-08-11 00:21:53 +00:00
|
|
|
__bdev_nvme_io_complete(bdev_io, io_status, NULL);
|
2021-10-18 13:15:32 +00:00
|
|
|
}
|
|
|
|
|
2022-08-09 01:24:42 +00:00
|
|
|
static void
|
2022-08-09 01:46:48 +00:00
|
|
|
bdev_nvme_clear_io_path_caches_done(struct spdk_io_channel_iter *i, int status)
|
2022-08-09 01:24:42 +00:00
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = spdk_io_channel_iter_get_io_device(i);
|
|
|
|
|
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
|
|
|
|
2022-08-09 01:46:48 +00:00
|
|
|
assert(nvme_ctrlr->io_path_cache_clearing == true);
|
|
|
|
nvme_ctrlr->io_path_cache_clearing = false;
|
2022-08-09 01:24:42 +00:00
|
|
|
|
|
|
|
if (!nvme_ctrlr_can_be_unregistered(nvme_ctrlr)) {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
|
|
|
|
nvme_ctrlr_unregister(nvme_ctrlr);
|
|
|
|
}
|
|
|
|
|
2021-10-15 10:28:09 +00:00
|
|
|
static void
|
2022-03-09 06:44:18 +00:00
|
|
|
_bdev_nvme_clear_io_path_cache(struct nvme_qpair *nvme_qpair)
|
2021-10-15 10:28:09 +00:00
|
|
|
{
|
|
|
|
struct nvme_io_path *io_path;
|
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
TAILQ_FOREACH(io_path, &nvme_qpair->io_path_list, tailq) {
|
2022-11-29 08:44:19 +00:00
|
|
|
bdev_nvme_clear_current_io_path(io_path->nbdev_ch);
|
2021-10-15 10:28:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-09 06:58:29 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_clear_io_path_cache(struct spdk_io_channel_iter *i)
|
|
|
|
{
|
|
|
|
struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
|
|
|
|
struct nvme_ctrlr_channel *ctrlr_ch = spdk_io_channel_get_ctx(_ch);
|
|
|
|
|
|
|
|
assert(ctrlr_ch->qpair != NULL);
|
|
|
|
|
|
|
|
_bdev_nvme_clear_io_path_cache(ctrlr_ch->qpair);
|
|
|
|
|
|
|
|
spdk_for_each_channel_continue(i, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-08-09 01:46:48 +00:00
|
|
|
bdev_nvme_clear_io_path_caches(struct nvme_ctrlr *nvme_ctrlr)
|
2022-03-09 06:58:29 +00:00
|
|
|
{
|
2022-08-09 01:46:48 +00:00
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
|
|
|
if (!nvme_ctrlr_is_available(nvme_ctrlr) ||
|
|
|
|
nvme_ctrlr->io_path_cache_clearing) {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nvme_ctrlr->io_path_cache_clearing = true;
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
|
2022-03-09 06:58:29 +00:00
|
|
|
spdk_for_each_channel(nvme_ctrlr,
|
|
|
|
bdev_nvme_clear_io_path_cache,
|
|
|
|
NULL,
|
2022-08-09 01:46:48 +00:00
|
|
|
bdev_nvme_clear_io_path_caches_done);
|
2022-03-09 06:58:29 +00:00
|
|
|
}
|
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
static struct nvme_qpair *
|
|
|
|
nvme_poll_group_get_qpair(struct nvme_poll_group *group, struct spdk_nvme_qpair *qpair)
|
2021-09-15 04:01:49 +00:00
|
|
|
{
|
2022-03-09 06:44:18 +00:00
|
|
|
struct nvme_qpair *nvme_qpair;
|
2021-09-15 04:01:49 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
TAILQ_FOREACH(nvme_qpair, &group->qpair_list, tailq) {
|
|
|
|
if (nvme_qpair->qpair == qpair) {
|
2021-09-15 04:01:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
return nvme_qpair;
|
2021-09-15 04:01:49 +00:00
|
|
|
}
|
|
|
|
|
2022-03-09 06:48:11 +00:00
|
|
|
static void nvme_qpair_delete(struct nvme_qpair *nvme_qpair);
|
|
|
|
|
2020-02-07 00:20:35 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_disconnected_qpair_cb(struct spdk_nvme_qpair *qpair, void *poll_group_ctx)
|
|
|
|
{
|
2021-09-15 04:01:49 +00:00
|
|
|
struct nvme_poll_group *group = poll_group_ctx;
|
2022-03-09 06:44:18 +00:00
|
|
|
struct nvme_qpair *nvme_qpair;
|
2022-03-09 06:53:15 +00:00
|
|
|
struct nvme_ctrlr_channel *ctrlr_ch;
|
2020-12-22 11:34:00 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_qpair = nvme_poll_group_get_qpair(group, qpair);
|
2022-03-29 21:02:38 +00:00
|
|
|
if (nvme_qpair == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2022-03-08 22:24:35 +00:00
|
|
|
|
2022-03-29 21:02:38 +00:00
|
|
|
if (nvme_qpair->qpair != NULL) {
|
|
|
|
spdk_nvme_ctrlr_free_io_qpair(nvme_qpair->qpair);
|
|
|
|
nvme_qpair->qpair = NULL;
|
|
|
|
}
|
2021-09-15 04:01:49 +00:00
|
|
|
|
2022-03-29 21:02:38 +00:00
|
|
|
_bdev_nvme_clear_io_path_cache(nvme_qpair);
|
2022-03-09 06:53:15 +00:00
|
|
|
|
2022-03-29 21:02:38 +00:00
|
|
|
ctrlr_ch = nvme_qpair->ctrlr_ch;
|
|
|
|
|
|
|
|
if (ctrlr_ch != NULL) {
|
|
|
|
if (ctrlr_ch->reset_iter != NULL) {
|
|
|
|
/* If we are already in a full reset sequence, we do not have
|
|
|
|
* to restart it. Just move to the next ctrlr_channel.
|
|
|
|
*/
|
|
|
|
SPDK_DEBUGLOG(bdev_nvme, "qpair %p was disconnected and freed in a reset ctrlr sequence.\n",
|
|
|
|
qpair);
|
|
|
|
spdk_for_each_channel_continue(ctrlr_ch->reset_iter, 0);
|
|
|
|
ctrlr_ch->reset_iter = NULL;
|
2022-03-09 06:48:11 +00:00
|
|
|
} else {
|
2022-03-29 21:02:38 +00:00
|
|
|
/* qpair was disconnected unexpectedly. Reset controller for recovery. */
|
|
|
|
SPDK_NOTICELOG("qpair %p was disconnected and freed. reset controller.\n", qpair);
|
2022-04-19 01:27:45 +00:00
|
|
|
bdev_nvme_failover(nvme_qpair->ctrlr, false);
|
2022-03-09 06:48:11 +00:00
|
|
|
}
|
2022-03-29 21:02:38 +00:00
|
|
|
} else {
|
|
|
|
/* In this case, ctrlr_channel is already deleted. */
|
|
|
|
SPDK_DEBUGLOG(bdev_nvme, "qpair %p was disconnected and freed. delete nvme_qpair.\n", qpair);
|
|
|
|
nvme_qpair_delete(nvme_qpair);
|
2020-12-22 11:34:00 +00:00
|
|
|
}
|
2020-02-07 00:20:35 +00:00
|
|
|
}
|
|
|
|
|
2022-03-08 03:04:11 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_check_io_qpairs(struct nvme_poll_group *group)
|
|
|
|
{
|
|
|
|
struct nvme_qpair *nvme_qpair;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(nvme_qpair, &group->qpair_list, tailq) {
|
|
|
|
if (nvme_qpair->qpair == NULL || nvme_qpair->ctrlr_ch == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spdk_nvme_qpair_get_failure_reason(nvme_qpair->qpair) !=
|
|
|
|
SPDK_NVME_QPAIR_FAILURE_NONE) {
|
|
|
|
_bdev_nvme_clear_io_path_cache(nvme_qpair);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-13 00:16:47 +00:00
|
|
|
static int
|
2017-02-28 17:51:25 +00:00
|
|
|
bdev_nvme_poll(void *arg)
|
2016-09-16 19:53:32 +00:00
|
|
|
{
|
2021-07-06 17:20:32 +00:00
|
|
|
struct nvme_poll_group *group = arg;
|
2020-02-07 00:20:35 +00:00
|
|
|
int64_t num_completions;
|
2016-09-16 19:53:32 +00:00
|
|
|
|
2020-02-07 00:20:35 +00:00
|
|
|
if (group->collect_spin_stat && group->start_ticks == 0) {
|
|
|
|
group->start_ticks = spdk_get_ticks();
|
2017-06-15 16:59:02 +00:00
|
|
|
}
|
|
|
|
|
2020-02-07 00:20:35 +00:00
|
|
|
num_completions = spdk_nvme_poll_group_process_completions(group->group, 0,
|
|
|
|
bdev_nvme_disconnected_qpair_cb);
|
|
|
|
if (group->collect_spin_stat) {
|
2017-06-15 16:59:02 +00:00
|
|
|
if (num_completions > 0) {
|
2020-02-07 00:20:35 +00:00
|
|
|
if (group->end_ticks != 0) {
|
|
|
|
group->spin_ticks += (group->end_ticks - group->start_ticks);
|
|
|
|
group->end_ticks = 0;
|
2017-06-15 16:59:02 +00:00
|
|
|
}
|
2020-02-07 00:20:35 +00:00
|
|
|
group->start_ticks = 0;
|
2017-06-15 16:59:02 +00:00
|
|
|
} else {
|
2020-02-07 00:20:35 +00:00
|
|
|
group->end_ticks = spdk_get_ticks();
|
2017-06-15 16:59:02 +00:00
|
|
|
}
|
2017-06-08 18:49:22 +00:00
|
|
|
}
|
2018-03-13 00:16:47 +00:00
|
|
|
|
2022-03-08 03:04:11 +00:00
|
|
|
if (spdk_unlikely(num_completions < 0)) {
|
|
|
|
bdev_nvme_check_io_qpairs(group);
|
|
|
|
}
|
|
|
|
|
2020-05-04 09:51:27 +00:00
|
|
|
return num_completions > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
|
2016-09-16 19:53:32 +00:00
|
|
|
}
|
|
|
|
|
2022-05-11 05:24:28 +00:00
|
|
|
static int bdev_nvme_poll_adminq(void *arg);
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_change_adminq_poll_period(struct nvme_ctrlr *nvme_ctrlr, uint64_t new_period_us)
|
|
|
|
{
|
|
|
|
spdk_poller_unregister(&nvme_ctrlr->adminq_timer_poller);
|
|
|
|
|
|
|
|
nvme_ctrlr->adminq_timer_poller = SPDK_POLLER_REGISTER(bdev_nvme_poll_adminq,
|
|
|
|
nvme_ctrlr, new_period_us);
|
|
|
|
}
|
|
|
|
|
2018-03-13 00:16:47 +00:00
|
|
|
static int
|
2017-02-28 17:51:25 +00:00
|
|
|
bdev_nvme_poll_adminq(void *arg)
|
2017-01-13 19:58:23 +00:00
|
|
|
{
|
2019-11-08 22:22:37 +00:00
|
|
|
int32_t rc;
|
2021-07-06 19:42:41 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr = arg;
|
2022-01-28 00:34:10 +00:00
|
|
|
nvme_ctrlr_disconnected_cb disconnected_cb;
|
2017-01-13 19:58:23 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
assert(nvme_ctrlr != NULL);
|
2019-11-08 22:22:37 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
rc = spdk_nvme_ctrlr_process_admin_completions(nvme_ctrlr->ctrlr);
|
2019-11-08 22:22:37 +00:00
|
|
|
if (rc < 0) {
|
2022-01-28 00:34:10 +00:00
|
|
|
disconnected_cb = nvme_ctrlr->disconnected_cb;
|
|
|
|
nvme_ctrlr->disconnected_cb = NULL;
|
|
|
|
|
|
|
|
if (rc == -ENXIO && disconnected_cb != NULL) {
|
2022-05-11 05:24:28 +00:00
|
|
|
bdev_nvme_change_adminq_poll_period(nvme_ctrlr,
|
|
|
|
g_opts.nvme_adminq_poll_period_us);
|
2022-01-28 00:34:10 +00:00
|
|
|
disconnected_cb(nvme_ctrlr);
|
|
|
|
} else {
|
|
|
|
bdev_nvme_failover(nvme_ctrlr, false);
|
|
|
|
}
|
2022-01-27 22:03:05 +00:00
|
|
|
} else if (spdk_nvme_ctrlr_get_admin_qp_failure_reason(nvme_ctrlr->ctrlr) !=
|
|
|
|
SPDK_NVME_QPAIR_FAILURE_NONE) {
|
2022-08-09 01:46:48 +00:00
|
|
|
bdev_nvme_clear_io_path_caches(nvme_ctrlr);
|
2019-11-08 22:22:37 +00:00
|
|
|
}
|
|
|
|
|
2020-05-04 09:51:27 +00:00
|
|
|
return rc == 0 ? SPDK_POLLER_IDLE : SPDK_POLLER_BUSY;
|
2017-01-13 19:58:23 +00:00
|
|
|
}
|
|
|
|
|
2021-07-06 17:35:01 +00:00
|
|
|
static void
|
|
|
|
_bdev_nvme_unregister_dev_cb(void *io_device)
|
|
|
|
{
|
|
|
|
struct nvme_bdev *nvme_disk = io_device;
|
|
|
|
|
|
|
|
free(nvme_disk->disk.name);
|
bdev/nvme: Count number of NVMe errors per type or code
Error counters for NVMe error was added in the generic bdev layer but
we want to know more detailed information for some use cases.
Add NVMe error counters per type and per code as module specific
statistics.
For status codes, the first idea was to have different named member
for each status code value. However, it was bad and too hard to test,
review, and maintain.
Instead, we have just two dimensional uint32_t arrays, and increment
one of these uint32_t values based on the status code type and status
code. Then, when dump the JSON, we use spdk_nvme_cpl_get_status_string()
and spdk_nvme_cpl_get_status_type_string().
This idea has one potential downside. This idea consumes 4 (types) *
256 (codes) * 4 (counter) = 4KB per NVMe bdev. We can make this smarter
if memory allocation is a problem. Hence we add an option
nvme_error_stat to enable this feature only if the user requests.
Additionally, the string returned by spdk_nvme_cpl_get_status_string()
or spdk_nvme_cpl_get_status_type_string() has uppercases, spaces, and
hyphens. These should not be included in JSON strings. Hence, convert
these via spdk_strcpy_replace().
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I07b07621e777bdf6556b95054abbbb65e5f9ea3e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15370
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
2023-01-05 23:26:33 +00:00
|
|
|
free(nvme_disk->err_stat);
|
2021-07-06 17:35:01 +00:00
|
|
|
free(nvme_disk);
|
|
|
|
}
|
|
|
|
|
2016-07-20 18:16:23 +00:00
|
|
|
static int
|
2017-04-04 21:10:00 +00:00
|
|
|
bdev_nvme_destruct(void *ctx)
|
2016-07-20 18:16:23 +00:00
|
|
|
{
|
2017-04-04 21:10:00 +00:00
|
|
|
struct nvme_bdev *nvme_disk = ctx;
|
2021-09-27 23:15:02 +00:00
|
|
|
struct nvme_ns *nvme_ns, *tmp_nvme_ns;
|
2017-03-01 01:23:53 +00:00
|
|
|
|
2021-12-06 10:57:02 +00:00
|
|
|
SPDK_DTRACE_PROBE2(bdev_nvme_destruct, nvme_disk->nbdev_ctrlr->name, nvme_disk->nsid);
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
TAILQ_FOREACH_SAFE(nvme_ns, &nvme_disk->nvme_ns_list, tailq, tmp_nvme_ns) {
|
|
|
|
pthread_mutex_lock(&nvme_ns->ctrlr->mutex);
|
2021-03-29 14:46:57 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
nvme_ns->bdev = NULL;
|
2021-03-29 15:02:59 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
assert(nvme_ns->id > 0);
|
2021-08-25 22:03:09 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
if (nvme_ctrlr_get_ns(nvme_ns->ctrlr, nvme_ns->id) == NULL) {
|
|
|
|
pthread_mutex_unlock(&nvme_ns->ctrlr->mutex);
|
2021-03-29 14:46:57 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
nvme_ctrlr_release(nvme_ns->ctrlr);
|
2023-01-16 06:43:32 +00:00
|
|
|
nvme_ns_free(nvme_ns);
|
2021-09-27 23:15:02 +00:00
|
|
|
} else {
|
|
|
|
pthread_mutex_unlock(&nvme_ns->ctrlr->mutex);
|
|
|
|
}
|
2021-03-29 14:46:57 +00:00
|
|
|
}
|
2019-10-01 08:18:44 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
pthread_mutex_lock(&g_bdev_nvme_mutex);
|
|
|
|
TAILQ_REMOVE(&nvme_disk->nbdev_ctrlr->bdevs, nvme_disk, tailq);
|
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
|
|
|
|
2021-07-06 17:35:01 +00:00
|
|
|
spdk_io_device_unregister(nvme_disk, _bdev_nvme_unregister_dev_cb);
|
2017-03-01 01:23:53 +00:00
|
|
|
|
2016-07-20 18:16:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-11-13 12:06:52 +00:00
|
|
|
static int
|
2022-03-09 06:44:18 +00:00
|
|
|
bdev_nvme_create_qpair(struct nvme_qpair *nvme_qpair)
|
2020-11-13 12:06:52 +00:00
|
|
|
{
|
2021-08-11 08:11:19 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr;
|
2020-11-13 12:06:52 +00:00
|
|
|
struct spdk_nvme_io_qpair_opts opts;
|
2021-03-24 10:31:43 +00:00
|
|
|
struct spdk_nvme_qpair *qpair;
|
2020-11-13 12:06:52 +00:00
|
|
|
int rc;
|
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_ctrlr = nvme_qpair->ctrlr;
|
2021-08-11 08:11:19 +00:00
|
|
|
|
|
|
|
spdk_nvme_ctrlr_get_default_io_qpair_opts(nvme_ctrlr->ctrlr, &opts, sizeof(opts));
|
2020-11-13 12:06:52 +00:00
|
|
|
opts.delay_cmd_submit = g_opts.delay_cmd_submit;
|
|
|
|
opts.create_only = true;
|
2021-05-14 20:11:33 +00:00
|
|
|
opts.async_mode = true;
|
2020-11-13 12:06:52 +00:00
|
|
|
opts.io_queue_requests = spdk_max(g_opts.io_queue_requests, opts.io_queue_requests);
|
|
|
|
g_opts.io_queue_requests = opts.io_queue_requests;
|
|
|
|
|
2021-08-11 08:11:19 +00:00
|
|
|
qpair = spdk_nvme_ctrlr_alloc_io_qpair(nvme_ctrlr->ctrlr, &opts, sizeof(opts));
|
2021-03-24 10:31:43 +00:00
|
|
|
if (qpair == NULL) {
|
2020-11-13 12:06:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2021-12-06 10:57:02 +00:00
|
|
|
SPDK_DTRACE_PROBE3(bdev_nvme_create_qpair, nvme_ctrlr->nbdev_ctrlr->name,
|
2022-03-08 22:24:35 +00:00
|
|
|
spdk_nvme_qpair_get_id(qpair), spdk_thread_get_id(nvme_ctrlr->thread));
|
2021-12-06 10:57:02 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
assert(nvme_qpair->group != NULL);
|
2020-11-13 12:06:52 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
rc = spdk_nvme_poll_group_add(nvme_qpair->group->group, qpair);
|
2020-11-13 12:06:52 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Unable to begin polling on NVMe Channel.\n");
|
2020-12-22 04:28:01 +00:00
|
|
|
goto err;
|
2020-11-13 12:06:52 +00:00
|
|
|
}
|
|
|
|
|
2021-08-11 08:11:19 +00:00
|
|
|
rc = spdk_nvme_ctrlr_connect_io_qpair(nvme_ctrlr->ctrlr, qpair);
|
2020-11-13 12:06:52 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Unable to connect I/O qpair.\n");
|
2020-12-22 04:28:01 +00:00
|
|
|
goto err;
|
2020-11-13 12:06:52 +00:00
|
|
|
}
|
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_qpair->qpair = qpair;
|
2021-03-24 10:31:43 +00:00
|
|
|
|
2022-05-02 03:07:02 +00:00
|
|
|
if (!g_opts.disable_auto_failback) {
|
|
|
|
_bdev_nvme_clear_io_path_cache(nvme_qpair);
|
|
|
|
}
|
2022-01-09 23:15:50 +00:00
|
|
|
|
2020-11-13 12:06:52 +00:00
|
|
|
return 0;
|
|
|
|
|
2020-12-22 04:28:01 +00:00
|
|
|
err:
|
2021-03-24 10:31:43 +00:00
|
|
|
spdk_nvme_ctrlr_free_io_qpair(qpair);
|
2020-12-08 21:51:00 +00:00
|
|
|
|
2020-11-13 12:06:52 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2019-11-08 21:26:09 +00:00
|
|
|
static void
|
2021-10-06 15:49:49 +00:00
|
|
|
bdev_nvme_complete_pending_resets(struct spdk_io_channel_iter *i)
|
2019-11-08 21:26:09 +00:00
|
|
|
{
|
2021-10-06 15:49:49 +00:00
|
|
|
struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
|
|
|
|
struct nvme_ctrlr_channel *ctrlr_ch = spdk_io_channel_get_ctx(_ch);
|
|
|
|
enum spdk_bdev_io_status status = SPDK_BDEV_IO_STATUS_SUCCESS;
|
2019-11-08 21:26:09 +00:00
|
|
|
struct spdk_bdev_io *bdev_io;
|
|
|
|
|
2021-10-06 15:49:49 +00:00
|
|
|
if (spdk_io_channel_iter_get_ctx(i) != NULL) {
|
|
|
|
status = SPDK_BDEV_IO_STATUS_FAILED;
|
|
|
|
}
|
|
|
|
|
2021-07-07 01:02:14 +00:00
|
|
|
while (!TAILQ_EMPTY(&ctrlr_ch->pending_resets)) {
|
|
|
|
bdev_io = TAILQ_FIRST(&ctrlr_ch->pending_resets);
|
|
|
|
TAILQ_REMOVE(&ctrlr_ch->pending_resets, bdev_io, module_link);
|
2022-08-11 00:21:53 +00:00
|
|
|
__bdev_nvme_io_complete(bdev_io, status, NULL);
|
2019-11-08 21:26:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
spdk_for_each_channel_continue(i, 0);
|
|
|
|
}
|
|
|
|
|
2021-11-25 18:42:49 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_failover_trid(struct nvme_ctrlr *nvme_ctrlr, bool remove)
|
|
|
|
{
|
|
|
|
struct nvme_path_id *path_id, *next_path;
|
|
|
|
int rc __attribute__((unused));
|
|
|
|
|
|
|
|
path_id = TAILQ_FIRST(&nvme_ctrlr->trids);
|
|
|
|
assert(path_id);
|
|
|
|
assert(path_id == nvme_ctrlr->active_path_id);
|
|
|
|
next_path = TAILQ_NEXT(path_id, link);
|
|
|
|
|
|
|
|
path_id->is_failed = true;
|
|
|
|
|
|
|
|
if (next_path) {
|
|
|
|
assert(path_id->trid.trtype != SPDK_NVME_TRANSPORT_PCIE);
|
|
|
|
|
|
|
|
SPDK_NOTICELOG("Start failover from %s:%s to %s:%s\n", path_id->trid.traddr,
|
|
|
|
path_id->trid.trsvcid, next_path->trid.traddr, next_path->trid.trsvcid);
|
|
|
|
|
|
|
|
spdk_nvme_ctrlr_fail(nvme_ctrlr->ctrlr);
|
|
|
|
nvme_ctrlr->active_path_id = next_path;
|
|
|
|
rc = spdk_nvme_ctrlr_set_trid(nvme_ctrlr->ctrlr, &next_path->trid);
|
|
|
|
assert(rc == 0);
|
|
|
|
TAILQ_REMOVE(&nvme_ctrlr->trids, path_id, link);
|
|
|
|
if (!remove) {
|
|
|
|
/** Shuffle the old trid to the end of the list and use the new one.
|
|
|
|
* Allows for round robin through multiple connections.
|
|
|
|
*/
|
|
|
|
TAILQ_INSERT_TAIL(&nvme_ctrlr->trids, path_id, link);
|
|
|
|
} else {
|
|
|
|
free(path_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-13 07:03:36 +00:00
|
|
|
static bool
|
|
|
|
bdev_nvme_check_ctrlr_loss_timeout(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
int32_t elapsed;
|
|
|
|
|
2022-03-04 04:51:53 +00:00
|
|
|
if (nvme_ctrlr->opts.ctrlr_loss_timeout_sec == 0 ||
|
|
|
|
nvme_ctrlr->opts.ctrlr_loss_timeout_sec == -1) {
|
2022-01-13 07:03:36 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
elapsed = (spdk_get_ticks() - nvme_ctrlr->reset_start_tsc) / spdk_get_ticks_hz();
|
2022-03-04 04:51:53 +00:00
|
|
|
if (elapsed >= nvme_ctrlr->opts.ctrlr_loss_timeout_sec) {
|
2022-01-13 07:03:36 +00:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-14 02:02:31 +00:00
|
|
|
static bool
|
|
|
|
bdev_nvme_check_fast_io_fail_timeout(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
uint32_t elapsed;
|
|
|
|
|
2022-03-04 04:51:53 +00:00
|
|
|
if (nvme_ctrlr->opts.fast_io_fail_timeout_sec == 0) {
|
2022-01-14 02:02:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
elapsed = (spdk_get_ticks() - nvme_ctrlr->reset_start_tsc) / spdk_get_ticks_hz();
|
2022-03-04 04:51:53 +00:00
|
|
|
if (elapsed >= nvme_ctrlr->opts.fast_io_fail_timeout_sec) {
|
2022-01-14 02:02:31 +00:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-08 03:19:44 +00:00
|
|
|
static void bdev_nvme_reset_complete(struct nvme_ctrlr *nvme_ctrlr, bool success);
|
|
|
|
|
2022-05-06 07:23:25 +00:00
|
|
|
static void
|
|
|
|
nvme_ctrlr_disconnect(struct nvme_ctrlr *nvme_ctrlr, nvme_ctrlr_disconnected_cb cb_fn)
|
|
|
|
{
|
2022-08-08 03:19:44 +00:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = spdk_nvme_ctrlr_disconnect(nvme_ctrlr->ctrlr);
|
|
|
|
if (rc != 0) {
|
|
|
|
/* Disconnect fails if ctrlr is already resetting or removed. In this case,
|
|
|
|
* fail the reset sequence immediately.
|
|
|
|
*/
|
|
|
|
bdev_nvme_reset_complete(nvme_ctrlr, false);
|
|
|
|
return;
|
|
|
|
}
|
2022-05-06 07:23:25 +00:00
|
|
|
|
|
|
|
/* spdk_nvme_ctrlr_disconnect() may complete asynchronously later by polling adminq.
|
|
|
|
* Set callback here to execute the specified operation after ctrlr is really disconnected.
|
|
|
|
*/
|
|
|
|
assert(nvme_ctrlr->disconnected_cb == NULL);
|
|
|
|
nvme_ctrlr->disconnected_cb = cb_fn;
|
|
|
|
|
2022-05-11 05:24:28 +00:00
|
|
|
/* During disconnection, reduce the period to poll adminq more often. */
|
|
|
|
bdev_nvme_change_adminq_poll_period(nvme_ctrlr, 0);
|
2022-05-06 07:23:25 +00:00
|
|
|
}
|
|
|
|
|
2022-01-13 04:23:51 +00:00
|
|
|
enum bdev_nvme_op_after_reset {
|
|
|
|
OP_NONE,
|
|
|
|
OP_COMPLETE_PENDING_DESTRUCT,
|
2022-01-13 07:03:36 +00:00
|
|
|
OP_DESTRUCT,
|
|
|
|
OP_DELAYED_RECONNECT,
|
2022-01-13 04:23:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef enum bdev_nvme_op_after_reset _bdev_nvme_op_after_reset;
|
|
|
|
|
|
|
|
static _bdev_nvme_op_after_reset
|
|
|
|
bdev_nvme_check_op_after_reset(struct nvme_ctrlr *nvme_ctrlr, bool success)
|
|
|
|
{
|
|
|
|
if (nvme_ctrlr_can_be_unregistered(nvme_ctrlr)) {
|
|
|
|
/* Complete pending destruct after reset completes. */
|
|
|
|
return OP_COMPLETE_PENDING_DESTRUCT;
|
2022-03-04 04:51:53 +00:00
|
|
|
} else if (success || nvme_ctrlr->opts.reconnect_delay_sec == 0) {
|
2022-01-13 07:03:36 +00:00
|
|
|
nvme_ctrlr->reset_start_tsc = 0;
|
|
|
|
return OP_NONE;
|
|
|
|
} else if (bdev_nvme_check_ctrlr_loss_timeout(nvme_ctrlr)) {
|
|
|
|
return OP_DESTRUCT;
|
|
|
|
} else {
|
2022-01-14 02:02:31 +00:00
|
|
|
if (bdev_nvme_check_fast_io_fail_timeout(nvme_ctrlr)) {
|
|
|
|
nvme_ctrlr->fast_io_fail_timedout = true;
|
|
|
|
}
|
2022-01-13 07:03:36 +00:00
|
|
|
bdev_nvme_failover_trid(nvme_ctrlr, false);
|
|
|
|
return OP_DELAYED_RECONNECT;
|
2022-01-13 04:23:51 +00:00
|
|
|
}
|
2022-01-13 07:03:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int _bdev_nvme_delete(struct nvme_ctrlr *nvme_ctrlr, bool hotplug);
|
|
|
|
static void bdev_nvme_reconnect_ctrlr(struct nvme_ctrlr *nvme_ctrlr);
|
|
|
|
|
|
|
|
static int
|
|
|
|
bdev_nvme_reconnect_delay_timer_expired(void *ctx)
|
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = ctx;
|
|
|
|
|
2022-04-06 21:49:06 +00:00
|
|
|
SPDK_DTRACE_PROBE1(bdev_nvme_ctrlr_reconnect_delay, nvme_ctrlr->nbdev_ctrlr->name);
|
2022-01-13 07:03:36 +00:00
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
|
|
|
|
|
|
|
spdk_poller_unregister(&nvme_ctrlr->reconnect_delay_timer);
|
|
|
|
|
|
|
|
assert(nvme_ctrlr->reconnect_is_delayed == true);
|
|
|
|
nvme_ctrlr->reconnect_is_delayed = false;
|
|
|
|
|
|
|
|
if (nvme_ctrlr->destruct) {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
return SPDK_POLLER_BUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(nvme_ctrlr->resetting == false);
|
|
|
|
nvme_ctrlr->resetting = true;
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2022-01-13 04:23:51 +00:00
|
|
|
|
2022-01-13 07:03:36 +00:00
|
|
|
spdk_poller_resume(nvme_ctrlr->adminq_timer_poller);
|
|
|
|
|
|
|
|
bdev_nvme_reconnect_ctrlr(nvme_ctrlr);
|
|
|
|
return SPDK_POLLER_BUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_start_reconnect_delay_timer(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
spdk_poller_pause(nvme_ctrlr->adminq_timer_poller);
|
|
|
|
|
|
|
|
assert(nvme_ctrlr->reconnect_is_delayed == false);
|
|
|
|
nvme_ctrlr->reconnect_is_delayed = true;
|
|
|
|
|
|
|
|
assert(nvme_ctrlr->reconnect_delay_timer == NULL);
|
|
|
|
nvme_ctrlr->reconnect_delay_timer = SPDK_POLLER_REGISTER(bdev_nvme_reconnect_delay_timer_expired,
|
|
|
|
nvme_ctrlr,
|
2022-03-04 04:51:53 +00:00
|
|
|
nvme_ctrlr->opts.reconnect_delay_sec * SPDK_SEC_TO_USEC);
|
2022-01-13 04:23:51 +00:00
|
|
|
}
|
|
|
|
|
2019-11-08 17:56:11 +00:00
|
|
|
static void
|
2021-10-08 04:15:59 +00:00
|
|
|
_bdev_nvme_reset_complete(struct spdk_io_channel_iter *i, int status)
|
2019-11-08 17:56:11 +00:00
|
|
|
{
|
2021-10-08 04:15:59 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr = spdk_io_channel_iter_get_io_device(i);
|
|
|
|
bool success = spdk_io_channel_iter_get_ctx(i) == NULL;
|
2021-09-14 18:26:50 +00:00
|
|
|
struct nvme_path_id *path_id;
|
2021-07-02 01:27:59 +00:00
|
|
|
bdev_nvme_reset_cb reset_cb_fn = nvme_ctrlr->reset_cb_fn;
|
|
|
|
void *reset_cb_arg = nvme_ctrlr->reset_cb_arg;
|
2022-01-13 04:23:51 +00:00
|
|
|
enum bdev_nvme_op_after_reset op_after_reset;
|
2021-04-05 13:11:43 +00:00
|
|
|
|
2021-10-31 10:38:18 +00:00
|
|
|
assert(nvme_ctrlr->thread == spdk_get_thread());
|
|
|
|
|
2021-07-02 01:27:59 +00:00
|
|
|
nvme_ctrlr->reset_cb_fn = NULL;
|
|
|
|
nvme_ctrlr->reset_cb_arg = NULL;
|
2019-11-08 21:26:09 +00:00
|
|
|
|
2021-10-08 04:14:54 +00:00
|
|
|
if (!success) {
|
2019-11-08 17:56:11 +00:00
|
|
|
SPDK_ERRLOG("Resetting controller failed.\n");
|
|
|
|
} else {
|
|
|
|
SPDK_NOTICELOG("Resetting controller successful.\n");
|
|
|
|
}
|
2019-11-08 21:26:09 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
|
|
|
nvme_ctrlr->resetting = false;
|
2020-12-22 12:50:29 +00:00
|
|
|
|
2021-09-14 18:26:50 +00:00
|
|
|
path_id = TAILQ_FIRST(&nvme_ctrlr->trids);
|
|
|
|
assert(path_id != NULL);
|
2021-09-21 19:17:12 +00:00
|
|
|
assert(path_id == nvme_ctrlr->active_path_id);
|
2020-12-22 12:50:29 +00:00
|
|
|
|
2021-10-08 04:14:54 +00:00
|
|
|
path_id->is_failed = !success;
|
2020-12-22 12:50:29 +00:00
|
|
|
|
2022-01-13 04:23:51 +00:00
|
|
|
op_after_reset = bdev_nvme_check_op_after_reset(nvme_ctrlr, success);
|
2020-12-17 09:52:14 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2021-03-03 17:23:21 +00:00
|
|
|
|
2021-07-02 01:27:59 +00:00
|
|
|
if (reset_cb_fn) {
|
2021-10-08 04:14:54 +00:00
|
|
|
reset_cb_fn(reset_cb_arg, success);
|
2021-04-05 13:11:43 +00:00
|
|
|
}
|
2021-07-02 01:02:03 +00:00
|
|
|
|
2022-01-13 04:23:51 +00:00
|
|
|
switch (op_after_reset) {
|
|
|
|
case OP_COMPLETE_PENDING_DESTRUCT:
|
2021-10-31 10:38:18 +00:00
|
|
|
nvme_ctrlr_unregister(nvme_ctrlr);
|
2022-01-13 04:23:51 +00:00
|
|
|
break;
|
2022-01-13 07:03:36 +00:00
|
|
|
case OP_DESTRUCT:
|
|
|
|
_bdev_nvme_delete(nvme_ctrlr, false);
|
|
|
|
break;
|
|
|
|
case OP_DELAYED_RECONNECT:
|
2022-05-06 07:23:25 +00:00
|
|
|
nvme_ctrlr_disconnect(nvme_ctrlr, bdev_nvme_start_reconnect_delay_timer);
|
2022-01-13 07:03:36 +00:00
|
|
|
break;
|
2022-01-13 04:23:51 +00:00
|
|
|
default:
|
|
|
|
break;
|
2021-10-08 04:15:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_reset_complete(struct nvme_ctrlr *nvme_ctrlr, bool success)
|
|
|
|
{
|
2021-07-02 01:02:03 +00:00
|
|
|
/* Make sure we clear any pending resets before returning. */
|
|
|
|
spdk_for_each_channel(nvme_ctrlr,
|
2021-10-06 15:49:49 +00:00
|
|
|
bdev_nvme_complete_pending_resets,
|
|
|
|
success ? NULL : (void *)0x1,
|
2021-10-08 04:15:59 +00:00
|
|
|
_bdev_nvme_reset_complete);
|
2019-11-08 17:56:11 +00:00
|
|
|
}
|
|
|
|
|
2021-11-03 02:44:13 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_reset_create_qpairs_failed(struct spdk_io_channel_iter *i, int status)
|
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = spdk_io_channel_iter_get_io_device(i);
|
|
|
|
|
|
|
|
bdev_nvme_reset_complete(nvme_ctrlr, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_reset_destroy_qpair(struct spdk_io_channel_iter *i)
|
|
|
|
{
|
|
|
|
struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
|
|
|
|
struct nvme_ctrlr_channel *ctrlr_ch = spdk_io_channel_get_ctx(ch);
|
2022-03-09 06:44:18 +00:00
|
|
|
struct nvme_qpair *nvme_qpair;
|
|
|
|
|
|
|
|
nvme_qpair = ctrlr_ch->qpair;
|
|
|
|
assert(nvme_qpair != NULL);
|
2021-11-03 02:44:13 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
_bdev_nvme_clear_io_path_cache(nvme_qpair);
|
2022-03-08 22:24:35 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
if (nvme_qpair->qpair != NULL) {
|
2022-03-09 06:53:15 +00:00
|
|
|
spdk_nvme_ctrlr_disconnect_io_qpair(nvme_qpair->qpair);
|
2021-11-03 02:44:13 +00:00
|
|
|
|
2022-03-09 06:53:15 +00:00
|
|
|
/* The current full reset sequence will move to the next
|
|
|
|
* ctrlr_channel after the qpair is actually disconnected.
|
|
|
|
*/
|
|
|
|
assert(ctrlr_ch->reset_iter == NULL);
|
|
|
|
ctrlr_ch->reset_iter = i;
|
|
|
|
} else {
|
|
|
|
spdk_for_each_channel_continue(i, 0);
|
|
|
|
}
|
2021-11-03 02:44:13 +00:00
|
|
|
}
|
|
|
|
|
2017-06-08 18:49:22 +00:00
|
|
|
static void
|
2021-07-05 11:03:54 +00:00
|
|
|
bdev_nvme_reset_create_qpairs_done(struct spdk_io_channel_iter *i, int status)
|
2017-06-08 18:49:22 +00:00
|
|
|
{
|
2021-07-02 01:07:32 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr = spdk_io_channel_iter_get_io_device(i);
|
2017-12-11 22:14:19 +00:00
|
|
|
|
2021-11-03 02:44:13 +00:00
|
|
|
if (status == 0) {
|
|
|
|
bdev_nvme_reset_complete(nvme_ctrlr, true);
|
|
|
|
} else {
|
|
|
|
/* Delete the added qpairs and quiesce ctrlr to make the states clean. */
|
|
|
|
spdk_for_each_channel(nvme_ctrlr,
|
|
|
|
bdev_nvme_reset_destroy_qpair,
|
|
|
|
NULL,
|
|
|
|
bdev_nvme_reset_create_qpairs_failed);
|
|
|
|
}
|
2017-06-08 18:49:22 +00:00
|
|
|
}
|
|
|
|
|
2017-12-11 22:14:19 +00:00
|
|
|
static void
|
2021-07-05 11:03:54 +00:00
|
|
|
bdev_nvme_reset_create_qpair(struct spdk_io_channel_iter *i)
|
2017-06-08 18:49:22 +00:00
|
|
|
{
|
2017-12-11 22:14:19 +00:00
|
|
|
struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
|
2021-07-07 01:02:14 +00:00
|
|
|
struct nvme_ctrlr_channel *ctrlr_ch = spdk_io_channel_get_ctx(_ch);
|
2020-11-13 12:06:52 +00:00
|
|
|
int rc;
|
2020-02-07 00:20:35 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
rc = bdev_nvme_create_qpair(ctrlr_ch->qpair);
|
2020-02-07 00:20:35 +00:00
|
|
|
|
2020-11-13 12:06:52 +00:00
|
|
|
spdk_for_each_channel_continue(i, rc);
|
2017-06-08 18:49:22 +00:00
|
|
|
}
|
|
|
|
|
2021-06-15 17:39:21 +00:00
|
|
|
static int
|
2021-12-30 05:15:20 +00:00
|
|
|
bdev_nvme_reconnect_ctrlr_poll(void *arg)
|
2021-06-15 17:39:21 +00:00
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = arg;
|
2022-01-13 07:03:36 +00:00
|
|
|
int rc = -ETIMEDOUT;
|
2021-06-15 17:39:21 +00:00
|
|
|
|
2022-01-13 07:03:36 +00:00
|
|
|
if (!bdev_nvme_check_ctrlr_loss_timeout(nvme_ctrlr)) {
|
|
|
|
rc = spdk_nvme_ctrlr_reconnect_poll_async(nvme_ctrlr->ctrlr);
|
|
|
|
if (rc == -EAGAIN) {
|
|
|
|
return SPDK_POLLER_BUSY;
|
|
|
|
}
|
2021-06-15 17:39:21 +00:00
|
|
|
}
|
|
|
|
|
2021-07-09 08:51:32 +00:00
|
|
|
spdk_poller_unregister(&nvme_ctrlr->reset_detach_poller);
|
2021-06-15 17:39:21 +00:00
|
|
|
if (rc == 0) {
|
|
|
|
/* Recreate all of the I/O queue pairs */
|
|
|
|
spdk_for_each_channel(nvme_ctrlr,
|
|
|
|
bdev_nvme_reset_create_qpair,
|
|
|
|
NULL,
|
|
|
|
bdev_nvme_reset_create_qpairs_done);
|
|
|
|
} else {
|
2021-10-08 04:14:54 +00:00
|
|
|
bdev_nvme_reset_complete(nvme_ctrlr, false);
|
2021-06-15 17:39:21 +00:00
|
|
|
}
|
|
|
|
return SPDK_POLLER_BUSY;
|
|
|
|
}
|
|
|
|
|
2021-12-30 05:15:20 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_reconnect_ctrlr(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
spdk_nvme_ctrlr_reconnect_async(nvme_ctrlr->ctrlr);
|
|
|
|
|
2022-04-06 21:49:06 +00:00
|
|
|
SPDK_DTRACE_PROBE1(bdev_nvme_ctrlr_reconnect, nvme_ctrlr->nbdev_ctrlr->name);
|
2021-12-30 05:15:20 +00:00
|
|
|
assert(nvme_ctrlr->reset_detach_poller == NULL);
|
|
|
|
nvme_ctrlr->reset_detach_poller = SPDK_POLLER_REGISTER(bdev_nvme_reconnect_ctrlr_poll,
|
|
|
|
nvme_ctrlr, 0);
|
|
|
|
}
|
|
|
|
|
2017-06-08 18:49:22 +00:00
|
|
|
static void
|
2021-07-05 11:03:54 +00:00
|
|
|
bdev_nvme_reset_ctrlr(struct spdk_io_channel_iter *i, int status)
|
2016-07-20 18:16:23 +00:00
|
|
|
{
|
2021-07-02 01:07:32 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr = spdk_io_channel_iter_get_io_device(i);
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2022-04-06 21:49:06 +00:00
|
|
|
SPDK_DTRACE_PROBE1(bdev_nvme_ctrlr_reset, nvme_ctrlr->nbdev_ctrlr->name);
|
2021-10-31 11:28:00 +00:00
|
|
|
assert(status == 0);
|
2017-11-16 07:42:37 +00:00
|
|
|
|
2022-05-09 06:48:57 +00:00
|
|
|
if (!spdk_nvme_ctrlr_is_fabrics(nvme_ctrlr->ctrlr)) {
|
|
|
|
bdev_nvme_reconnect_ctrlr(nvme_ctrlr);
|
|
|
|
} else {
|
|
|
|
nvme_ctrlr_disconnect(nvme_ctrlr, bdev_nvme_reconnect_ctrlr);
|
|
|
|
}
|
2017-06-08 18:49:22 +00:00
|
|
|
}
|
|
|
|
|
2022-05-06 04:38:18 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_reset_destroy_qpairs(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
spdk_for_each_channel(nvme_ctrlr,
|
|
|
|
bdev_nvme_reset_destroy_qpair,
|
|
|
|
NULL,
|
|
|
|
bdev_nvme_reset_ctrlr);
|
|
|
|
}
|
|
|
|
|
2021-10-31 10:38:18 +00:00
|
|
|
static void
|
|
|
|
_bdev_nvme_reset(void *ctx)
|
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = ctx;
|
|
|
|
|
|
|
|
assert(nvme_ctrlr->resetting == true);
|
|
|
|
assert(nvme_ctrlr->thread == spdk_get_thread());
|
|
|
|
|
2022-05-09 06:48:57 +00:00
|
|
|
if (!spdk_nvme_ctrlr_is_fabrics(nvme_ctrlr->ctrlr)) {
|
|
|
|
nvme_ctrlr_disconnect(nvme_ctrlr, bdev_nvme_reset_destroy_qpairs);
|
|
|
|
} else {
|
|
|
|
bdev_nvme_reset_destroy_qpairs(nvme_ctrlr);
|
|
|
|
}
|
2021-10-31 10:38:18 +00:00
|
|
|
}
|
|
|
|
|
2017-06-08 18:49:22 +00:00
|
|
|
static int
|
2021-07-05 11:03:54 +00:00
|
|
|
bdev_nvme_reset(struct nvme_ctrlr *nvme_ctrlr)
|
2017-06-08 18:49:22 +00:00
|
|
|
{
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
|
|
|
if (nvme_ctrlr->destruct) {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2021-07-20 15:36:17 +00:00
|
|
|
return -ENXIO;
|
2020-03-12 17:42:25 +00:00
|
|
|
}
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
if (nvme_ctrlr->resetting) {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2019-11-08 21:26:09 +00:00
|
|
|
SPDK_NOTICELOG("Unable to perform reset, already in progress.\n");
|
2021-07-20 15:36:17 +00:00
|
|
|
return -EBUSY;
|
2020-10-22 17:39:05 +00:00
|
|
|
}
|
|
|
|
|
2022-01-13 07:03:36 +00:00
|
|
|
if (nvme_ctrlr->reconnect_is_delayed) {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
SPDK_NOTICELOG("Reconnect is already scheduled.\n");
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr->resetting = true;
|
2022-01-13 07:03:36 +00:00
|
|
|
|
|
|
|
assert(nvme_ctrlr->reset_start_tsc == 0);
|
|
|
|
nvme_ctrlr->reset_start_tsc = spdk_get_ticks();
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2021-03-18 20:44:58 +00:00
|
|
|
|
2021-10-31 10:38:18 +00:00
|
|
|
spdk_thread_send_msg(nvme_ctrlr->thread, _bdev_nvme_reset, nvme_ctrlr);
|
2021-04-05 12:58:55 +00:00
|
|
|
return 0;
|
2020-10-22 17:39:05 +00:00
|
|
|
}
|
|
|
|
|
2021-06-16 17:24:56 +00:00
|
|
|
int
|
|
|
|
bdev_nvme_reset_rpc(struct nvme_ctrlr *nvme_ctrlr, bdev_nvme_reset_cb cb_fn, void *cb_arg)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = bdev_nvme_reset(nvme_ctrlr);
|
|
|
|
if (rc == 0) {
|
|
|
|
nvme_ctrlr->reset_cb_fn = cb_fn;
|
|
|
|
nvme_ctrlr->reset_cb_arg = cb_arg;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-09-28 15:34:56 +00:00
|
|
|
static int _bdev_nvme_reset_io(struct nvme_io_path *io_path, struct nvme_bdev_io *bio);
|
|
|
|
|
2021-07-02 01:27:59 +00:00
|
|
|
static void
|
2021-10-31 07:11:00 +00:00
|
|
|
bdev_nvme_reset_io_complete(struct nvme_bdev_io *bio)
|
2021-07-02 01:27:59 +00:00
|
|
|
{
|
2021-09-28 15:08:37 +00:00
|
|
|
enum spdk_bdev_io_status io_status;
|
|
|
|
|
2021-10-31 07:11:00 +00:00
|
|
|
if (bio->cpl.cdw0 == 0) {
|
2021-09-28 15:08:37 +00:00
|
|
|
io_status = SPDK_BDEV_IO_STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
io_status = SPDK_BDEV_IO_STATUS_FAILED;
|
|
|
|
}
|
2021-07-02 01:27:59 +00:00
|
|
|
|
2022-08-11 00:21:53 +00:00
|
|
|
__bdev_nvme_io_complete(spdk_bdev_io_from_ctx(bio), io_status, NULL);
|
2021-07-02 01:27:59 +00:00
|
|
|
}
|
|
|
|
|
2021-09-28 15:34:56 +00:00
|
|
|
static void
|
2021-10-31 07:11:00 +00:00
|
|
|
_bdev_nvme_reset_io_continue(void *ctx)
|
2021-09-28 15:34:56 +00:00
|
|
|
{
|
2021-10-31 07:11:00 +00:00
|
|
|
struct nvme_bdev_io *bio = ctx;
|
2021-09-28 15:34:56 +00:00
|
|
|
struct nvme_io_path *prev_io_path, *next_io_path;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
prev_io_path = bio->io_path;
|
|
|
|
bio->io_path = NULL;
|
|
|
|
|
2021-10-31 07:11:00 +00:00
|
|
|
if (bio->cpl.cdw0 != 0) {
|
2021-09-28 15:34:56 +00:00
|
|
|
goto complete;
|
|
|
|
}
|
|
|
|
|
|
|
|
next_io_path = STAILQ_NEXT(prev_io_path, stailq);
|
|
|
|
if (next_io_path == NULL) {
|
|
|
|
goto complete;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = _bdev_nvme_reset_io(next_io_path, bio);
|
|
|
|
if (rc == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-10-31 07:11:00 +00:00
|
|
|
bio->cpl.cdw0 = 1;
|
2021-09-28 15:34:56 +00:00
|
|
|
|
|
|
|
complete:
|
2021-10-31 07:11:00 +00:00
|
|
|
bdev_nvme_reset_io_complete(bio);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_reset_io_continue(void *cb_arg, bool success)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_io *bio = cb_arg;
|
|
|
|
|
|
|
|
bio->cpl.cdw0 = !success;
|
|
|
|
|
|
|
|
spdk_thread_send_msg(bio->orig_thread, _bdev_nvme_reset_io_continue, bio);
|
2021-09-28 15:34:56 +00:00
|
|
|
}
|
|
|
|
|
2020-11-02 14:21:21 +00:00
|
|
|
static int
|
2021-09-27 23:15:02 +00:00
|
|
|
_bdev_nvme_reset_io(struct nvme_io_path *io_path, struct nvme_bdev_io *bio)
|
2020-11-02 14:21:21 +00:00
|
|
|
{
|
2022-03-09 06:44:18 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr = io_path->qpair->ctrlr;
|
|
|
|
struct nvme_ctrlr_channel *ctrlr_ch;
|
2021-07-05 11:06:19 +00:00
|
|
|
struct spdk_bdev_io *bdev_io;
|
2020-11-02 14:21:21 +00:00
|
|
|
int rc;
|
|
|
|
|
2021-08-11 08:11:19 +00:00
|
|
|
rc = bdev_nvme_reset(nvme_ctrlr);
|
2021-03-18 21:51:01 +00:00
|
|
|
if (rc == 0) {
|
2021-09-28 15:34:56 +00:00
|
|
|
assert(bio->io_path == NULL);
|
|
|
|
bio->io_path = io_path;
|
|
|
|
|
2021-08-11 08:11:19 +00:00
|
|
|
assert(nvme_ctrlr->reset_cb_fn == NULL);
|
|
|
|
assert(nvme_ctrlr->reset_cb_arg == NULL);
|
2021-09-28 15:34:56 +00:00
|
|
|
nvme_ctrlr->reset_cb_fn = bdev_nvme_reset_io_continue;
|
2021-08-11 08:11:19 +00:00
|
|
|
nvme_ctrlr->reset_cb_arg = bio;
|
2021-07-20 15:36:17 +00:00
|
|
|
} else if (rc == -EBUSY) {
|
2022-03-09 06:44:18 +00:00
|
|
|
ctrlr_ch = io_path->qpair->ctrlr_ch;
|
|
|
|
assert(ctrlr_ch != NULL);
|
2020-11-02 14:21:21 +00:00
|
|
|
/*
|
|
|
|
* Reset call is queued only if it is from the app framework. This is on purpose so that
|
|
|
|
* we don't interfere with the app framework reset strategy. i.e. we are deferring to the
|
|
|
|
* upper level. If they are in the middle of a reset, we won't try to schedule another one.
|
|
|
|
*/
|
2021-07-05 11:06:19 +00:00
|
|
|
bdev_io = spdk_bdev_io_from_ctx(bio);
|
2021-07-07 01:02:14 +00:00
|
|
|
TAILQ_INSERT_TAIL(&ctrlr_ch->pending_resets, bdev_io, module_link);
|
2020-11-02 14:21:21 +00:00
|
|
|
} else {
|
|
|
|
return rc;
|
|
|
|
}
|
2021-03-18 21:51:01 +00:00
|
|
|
|
|
|
|
return 0;
|
2020-11-02 14:21:21 +00:00
|
|
|
}
|
|
|
|
|
2021-09-28 05:37:36 +00:00
|
|
|
static void
|
2021-09-27 23:15:02 +00:00
|
|
|
bdev_nvme_reset_io(struct nvme_bdev_channel *nbdev_ch, struct nvme_bdev_io *bio)
|
|
|
|
{
|
|
|
|
struct nvme_io_path *io_path;
|
2021-09-28 05:37:36 +00:00
|
|
|
int rc;
|
2021-09-27 23:15:02 +00:00
|
|
|
|
2021-10-31 07:11:00 +00:00
|
|
|
bio->cpl.cdw0 = 0;
|
|
|
|
bio->orig_thread = spdk_get_thread();
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
/* Reset only the first nvme_ctrlr in the nvme_bdev_ctrlr for now.
|
|
|
|
*
|
|
|
|
* TODO: Reset all nvme_ctrlrs in the nvme_bdev_ctrlr sequentially.
|
|
|
|
* This will be done in the following patches.
|
|
|
|
*/
|
|
|
|
io_path = STAILQ_FIRST(&nbdev_ch->io_path_list);
|
|
|
|
assert(io_path != NULL);
|
|
|
|
|
2021-09-28 05:37:36 +00:00
|
|
|
rc = _bdev_nvme_reset_io(io_path, bio);
|
|
|
|
if (rc != 0) {
|
2021-10-31 07:11:00 +00:00
|
|
|
bio->cpl.cdw0 = 1;
|
|
|
|
bdev_nvme_reset_io_complete(bio);
|
2021-09-28 05:37:36 +00:00
|
|
|
}
|
2021-09-27 23:15:02 +00:00
|
|
|
}
|
|
|
|
|
2020-10-22 17:39:05 +00:00
|
|
|
static int
|
2021-11-25 18:41:24 +00:00
|
|
|
bdev_nvme_failover(struct nvme_ctrlr *nvme_ctrlr, bool remove)
|
2020-10-22 17:39:05 +00:00
|
|
|
{
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
|
|
|
if (nvme_ctrlr->destruct) {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2020-10-22 17:39:05 +00:00
|
|
|
/* Don't bother resetting if the controller is in the process of being destructed. */
|
2021-07-20 15:36:17 +00:00
|
|
|
return -ENXIO;
|
2020-10-22 17:39:05 +00:00
|
|
|
}
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
if (nvme_ctrlr->resetting) {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2020-10-22 17:39:05 +00:00
|
|
|
SPDK_NOTICELOG("Unable to perform reset, already in progress.\n");
|
2021-11-25 09:43:17 +00:00
|
|
|
return -EBUSY;
|
2020-06-12 23:35:47 +00:00
|
|
|
}
|
|
|
|
|
2021-11-25 18:42:49 +00:00
|
|
|
bdev_nvme_failover_trid(nvme_ctrlr, remove);
|
2020-12-22 07:35:03 +00:00
|
|
|
|
2022-01-13 07:03:36 +00:00
|
|
|
if (nvme_ctrlr->reconnect_is_delayed) {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
SPDK_NOTICELOG("Reconnect is already scheduled.\n");
|
|
|
|
|
|
|
|
/* We rely on the next reconnect for the failover. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-11-25 18:42:49 +00:00
|
|
|
nvme_ctrlr->resetting = true;
|
2019-11-08 21:26:09 +00:00
|
|
|
|
2022-03-16 04:35:12 +00:00
|
|
|
assert(nvme_ctrlr->reset_start_tsc == 0);
|
|
|
|
nvme_ctrlr->reset_start_tsc = spdk_get_ticks();
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2017-06-08 18:49:22 +00:00
|
|
|
|
2021-11-25 18:41:24 +00:00
|
|
|
spdk_thread_send_msg(nvme_ctrlr->thread, _bdev_nvme_reset, nvme_ctrlr);
|
|
|
|
return 0;
|
2016-07-20 18:16:23 +00:00
|
|
|
}
|
|
|
|
|
2021-09-16 11:10:56 +00:00
|
|
|
static int bdev_nvme_unmap(struct nvme_bdev_io *bio, uint64_t offset_blocks,
|
|
|
|
uint64_t num_blocks);
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2021-09-16 11:10:56 +00:00
|
|
|
static int bdev_nvme_write_zeroes(struct nvme_bdev_io *bio, uint64_t offset_blocks,
|
|
|
|
uint64_t num_blocks);
|
2021-05-14 11:26:40 +00:00
|
|
|
|
2022-08-22 12:47:31 +00:00
|
|
|
static int bdev_nvme_copy(struct nvme_bdev_io *bio, uint64_t dst_offset_blocks,
|
|
|
|
uint64_t src_offset_blocks,
|
|
|
|
uint64_t num_blocks);
|
|
|
|
|
2017-02-28 17:51:25 +00:00
|
|
|
static void
|
bdev: Not assert but pass completion status to spdk_bdev_io_get_buf_cb
When the specified buffer size to spdk_bdev_io_get_buf() is greater
than the permitted maximum, spdk_bdev_io_get_buf() asserts simply and
doesn't call the specified callback function.
SPDK SCSI library doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
Bdev perf tool also doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
When we support DIF insert and strip in iSCSI target, the read
buffer size iSCSI initiator requests and the read buffer size iSCSI target
requests will become different.
Even after that, iSCSI initiator and iSCSI target will negotiate correctly
not to cause buffer overflow in spdk_bdev_io_get_buf(), but if iSCSI
initiator ignores the result of negotiation, iSCSI initiator can request
read buffer size larger than the permitted maximum, and can cause
failure in iSCSI target. This is very flagile and should be avoided.
This patch do the following
- Add the completion status of spdk_bdev_io_get_buf() to
spdk_bdev_io_get_buf_cb(),
- spdk_bdev_io_get_buf() calls spdk_bdev_io_get_buf_cb() by setting
success to false, and return.
- spdk_bdev_io_get_buf_cb() in each bdev module calls assert if success
is false.
Subsequent patches will process the case that success is false
in spdk_bdev_io_get_buf_cb().
Change-Id: I76429a86e18a69aa085a353ac94743296d270b82
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/446045
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
2019-02-25 00:34:28 +00:00
|
|
|
bdev_nvme_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
|
|
|
|
bool success)
|
2016-07-20 18:16:23 +00:00
|
|
|
{
|
2021-04-20 22:54:59 +00:00
|
|
|
struct nvme_bdev_io *bio = (struct nvme_bdev_io *)bdev_io->driver_ctx;
|
2020-11-23 04:09:54 +00:00
|
|
|
struct spdk_bdev *bdev = bdev_io->bdev;
|
2016-07-20 18:16:23 +00:00
|
|
|
int ret;
|
|
|
|
|
2019-02-25 01:43:13 +00:00
|
|
|
if (!success) {
|
2021-05-13 02:38:11 +00:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto exit;
|
2019-02-25 01:43:13 +00:00
|
|
|
}
|
bdev: Not assert but pass completion status to spdk_bdev_io_get_buf_cb
When the specified buffer size to spdk_bdev_io_get_buf() is greater
than the permitted maximum, spdk_bdev_io_get_buf() asserts simply and
doesn't call the specified callback function.
SPDK SCSI library doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
Bdev perf tool also doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().
When we support DIF insert and strip in iSCSI target, the read
buffer size iSCSI initiator requests and the read buffer size iSCSI target
requests will become different.
Even after that, iSCSI initiator and iSCSI target will negotiate correctly
not to cause buffer overflow in spdk_bdev_io_get_buf(), but if iSCSI
initiator ignores the result of negotiation, iSCSI initiator can request
read buffer size larger than the permitted maximum, and can cause
failure in iSCSI target. This is very flagile and should be avoided.
This patch do the following
- Add the completion status of spdk_bdev_io_get_buf() to
spdk_bdev_io_get_buf_cb(),
- spdk_bdev_io_get_buf() calls spdk_bdev_io_get_buf_cb() by setting
success to false, and return.
- spdk_bdev_io_get_buf_cb() in each bdev module calls assert if success
is false.
Subsequent patches will process the case that success is false
in spdk_bdev_io_get_buf_cb().
Change-Id: I76429a86e18a69aa085a353ac94743296d270b82
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/446045
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
2019-02-25 00:34:28 +00:00
|
|
|
|
2021-09-16 11:10:56 +00:00
|
|
|
if (spdk_unlikely(!nvme_io_path_is_available(bio->io_path))) {
|
2021-05-13 02:38:11 +00:00
|
|
|
ret = -ENXIO;
|
|
|
|
goto exit;
|
2021-01-10 15:13:56 +00:00
|
|
|
}
|
|
|
|
|
2021-09-16 11:10:56 +00:00
|
|
|
ret = bdev_nvme_readv(bio,
|
2017-09-20 13:10:17 +00:00
|
|
|
bdev_io->u.bdev.iovs,
|
|
|
|
bdev_io->u.bdev.iovcnt,
|
2019-04-16 08:17:08 +00:00
|
|
|
bdev_io->u.bdev.md_buf,
|
2017-09-20 13:10:17 +00:00
|
|
|
bdev_io->u.bdev.num_blocks,
|
2020-09-23 20:37:27 +00:00
|
|
|
bdev_io->u.bdev.offset_blocks,
|
2021-08-25 03:18:56 +00:00
|
|
|
bdev->dif_check_flags,
|
2021-11-25 14:27:42 +00:00
|
|
|
bdev_io->u.bdev.ext_opts);
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2021-05-13 02:38:11 +00:00
|
|
|
exit:
|
2022-12-16 02:39:39 +00:00
|
|
|
if (spdk_unlikely(ret != 0)) {
|
2021-04-20 22:54:59 +00:00
|
|
|
bdev_nvme_io_complete(bio, ret);
|
2016-07-20 18:16:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-10 06:39:41 +00:00
|
|
|
static inline void
|
|
|
|
_bdev_nvme_submit_request(struct nvme_bdev_channel *nbdev_ch, struct spdk_bdev_io *bdev_io)
|
2016-07-20 18:16:23 +00:00
|
|
|
{
|
2019-05-16 09:58:41 +00:00
|
|
|
struct nvme_bdev_io *nbdev_io = (struct nvme_bdev_io *)bdev_io->driver_ctx;
|
2023-01-10 06:39:41 +00:00
|
|
|
struct spdk_bdev *bdev = bdev_io->bdev;
|
2020-07-08 08:03:49 +00:00
|
|
|
struct nvme_bdev_io *nbdev_io_to_abort;
|
2021-05-13 02:09:53 +00:00
|
|
|
int rc = 0;
|
2019-05-16 09:58:41 +00:00
|
|
|
|
2016-07-20 18:16:23 +00:00
|
|
|
switch (bdev_io->type) {
|
|
|
|
case SPDK_BDEV_IO_TYPE_READ:
|
2020-09-18 17:38:27 +00:00
|
|
|
if (bdev_io->u.bdev.iovs && bdev_io->u.bdev.iovs[0].iov_base) {
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = bdev_nvme_readv(nbdev_io,
|
2021-05-13 02:09:53 +00:00
|
|
|
bdev_io->u.bdev.iovs,
|
|
|
|
bdev_io->u.bdev.iovcnt,
|
|
|
|
bdev_io->u.bdev.md_buf,
|
|
|
|
bdev_io->u.bdev.num_blocks,
|
|
|
|
bdev_io->u.bdev.offset_blocks,
|
2021-08-25 03:18:56 +00:00
|
|
|
bdev->dif_check_flags,
|
2021-11-25 14:27:42 +00:00
|
|
|
bdev_io->u.bdev.ext_opts);
|
2020-09-18 17:38:27 +00:00
|
|
|
} else {
|
|
|
|
spdk_bdev_io_get_buf(bdev_io, bdev_nvme_get_buf_cb,
|
2020-11-23 04:09:54 +00:00
|
|
|
bdev_io->u.bdev.num_blocks * bdev->blocklen);
|
2022-12-16 02:39:39 +00:00
|
|
|
rc = 0;
|
2020-09-18 17:38:27 +00:00
|
|
|
}
|
2021-05-13 02:09:53 +00:00
|
|
|
break;
|
2016-07-20 18:16:23 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_WRITE:
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = bdev_nvme_writev(nbdev_io,
|
2021-05-13 02:09:53 +00:00
|
|
|
bdev_io->u.bdev.iovs,
|
|
|
|
bdev_io->u.bdev.iovcnt,
|
|
|
|
bdev_io->u.bdev.md_buf,
|
|
|
|
bdev_io->u.bdev.num_blocks,
|
|
|
|
bdev_io->u.bdev.offset_blocks,
|
2021-08-25 03:18:56 +00:00
|
|
|
bdev->dif_check_flags,
|
2021-11-25 14:27:42 +00:00
|
|
|
bdev_io->u.bdev.ext_opts);
|
2021-05-13 02:09:53 +00:00
|
|
|
break;
|
|
|
|
case SPDK_BDEV_IO_TYPE_COMPARE:
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = bdev_nvme_comparev(nbdev_io,
|
2017-09-20 13:10:17 +00:00
|
|
|
bdev_io->u.bdev.iovs,
|
|
|
|
bdev_io->u.bdev.iovcnt,
|
2019-04-16 08:17:08 +00:00
|
|
|
bdev_io->u.bdev.md_buf,
|
2017-09-20 13:10:17 +00:00
|
|
|
bdev_io->u.bdev.num_blocks,
|
2020-09-23 20:37:27 +00:00
|
|
|
bdev_io->u.bdev.offset_blocks,
|
2020-11-23 04:09:54 +00:00
|
|
|
bdev->dif_check_flags);
|
2021-05-13 02:09:53 +00:00
|
|
|
break;
|
2019-12-20 11:29:48 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_COMPARE_AND_WRITE:
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = bdev_nvme_comparev_and_writev(nbdev_io,
|
2021-05-13 02:09:53 +00:00
|
|
|
bdev_io->u.bdev.iovs,
|
|
|
|
bdev_io->u.bdev.iovcnt,
|
|
|
|
bdev_io->u.bdev.fused_iovs,
|
|
|
|
bdev_io->u.bdev.fused_iovcnt,
|
|
|
|
bdev_io->u.bdev.md_buf,
|
|
|
|
bdev_io->u.bdev.num_blocks,
|
|
|
|
bdev_io->u.bdev.offset_blocks,
|
|
|
|
bdev->dif_check_flags);
|
|
|
|
break;
|
2016-07-20 18:16:23 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_UNMAP:
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = bdev_nvme_unmap(nbdev_io,
|
2021-05-13 02:09:53 +00:00
|
|
|
bdev_io->u.bdev.offset_blocks,
|
|
|
|
bdev_io->u.bdev.num_blocks);
|
|
|
|
break;
|
2021-05-14 11:26:40 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = bdev_nvme_write_zeroes(nbdev_io,
|
2021-05-14 11:26:40 +00:00
|
|
|
bdev_io->u.bdev.offset_blocks,
|
|
|
|
bdev_io->u.bdev.num_blocks);
|
|
|
|
break;
|
2016-07-20 18:16:23 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_RESET:
|
2021-09-28 07:43:22 +00:00
|
|
|
nbdev_io->io_path = NULL;
|
2021-09-28 05:37:36 +00:00
|
|
|
bdev_nvme_reset_io(nbdev_ch, nbdev_io);
|
2022-12-16 02:39:39 +00:00
|
|
|
break;
|
2016-07-20 18:16:23 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_FLUSH:
|
2022-11-18 02:54:09 +00:00
|
|
|
bdev_nvme_io_complete(nbdev_io, 0);
|
2022-12-16 02:39:39 +00:00
|
|
|
break;
|
2021-03-03 18:38:38 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_ZONE_APPEND:
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = bdev_nvme_zone_appendv(nbdev_io,
|
2021-05-13 02:09:53 +00:00
|
|
|
bdev_io->u.bdev.iovs,
|
|
|
|
bdev_io->u.bdev.iovcnt,
|
|
|
|
bdev_io->u.bdev.md_buf,
|
|
|
|
bdev_io->u.bdev.num_blocks,
|
|
|
|
bdev_io->u.bdev.offset_blocks,
|
|
|
|
bdev->dif_check_flags);
|
|
|
|
break;
|
2021-03-03 18:38:38 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_GET_ZONE_INFO:
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = bdev_nvme_get_zone_info(nbdev_io,
|
2021-05-13 02:09:53 +00:00
|
|
|
bdev_io->u.zone_mgmt.zone_id,
|
|
|
|
bdev_io->u.zone_mgmt.num_zones,
|
|
|
|
bdev_io->u.zone_mgmt.buf);
|
|
|
|
break;
|
|
|
|
case SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT:
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = bdev_nvme_zone_management(nbdev_io,
|
2021-03-03 18:38:38 +00:00
|
|
|
bdev_io->u.zone_mgmt.zone_id,
|
2021-05-13 02:09:53 +00:00
|
|
|
bdev_io->u.zone_mgmt.zone_action);
|
|
|
|
break;
|
2017-05-13 20:12:13 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_NVME_ADMIN:
|
2021-09-28 07:43:22 +00:00
|
|
|
nbdev_io->io_path = NULL;
|
2021-10-18 13:15:32 +00:00
|
|
|
bdev_nvme_admin_passthru(nbdev_ch,
|
|
|
|
nbdev_io,
|
|
|
|
&bdev_io->u.nvme_passthru.cmd,
|
|
|
|
bdev_io->u.nvme_passthru.buf,
|
|
|
|
bdev_io->u.nvme_passthru.nbytes);
|
2022-12-16 02:39:39 +00:00
|
|
|
break;
|
2017-06-05 18:02:09 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_NVME_IO:
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = bdev_nvme_io_passthru(nbdev_io,
|
2021-05-13 02:09:53 +00:00
|
|
|
&bdev_io->u.nvme_passthru.cmd,
|
|
|
|
bdev_io->u.nvme_passthru.buf,
|
|
|
|
bdev_io->u.nvme_passthru.nbytes);
|
|
|
|
break;
|
2017-11-14 06:33:11 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_NVME_IO_MD:
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = bdev_nvme_io_passthru_md(nbdev_io,
|
2021-05-13 02:09:53 +00:00
|
|
|
&bdev_io->u.nvme_passthru.cmd,
|
|
|
|
bdev_io->u.nvme_passthru.buf,
|
|
|
|
bdev_io->u.nvme_passthru.nbytes,
|
|
|
|
bdev_io->u.nvme_passthru.md_buf,
|
|
|
|
bdev_io->u.nvme_passthru.md_len);
|
|
|
|
break;
|
2020-07-08 08:03:49 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_ABORT:
|
2021-09-28 07:43:22 +00:00
|
|
|
nbdev_io->io_path = NULL;
|
2020-07-08 08:03:49 +00:00
|
|
|
nbdev_io_to_abort = (struct nvme_bdev_io *)bdev_io->u.abort.bio_to_abort->driver_ctx;
|
2021-09-28 05:37:36 +00:00
|
|
|
bdev_nvme_abort(nbdev_ch,
|
|
|
|
nbdev_io,
|
|
|
|
nbdev_io_to_abort);
|
2022-12-16 02:39:39 +00:00
|
|
|
break;
|
2022-08-22 12:47:31 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_COPY:
|
|
|
|
rc = bdev_nvme_copy(nbdev_io,
|
|
|
|
bdev_io->u.bdev.offset_blocks,
|
|
|
|
bdev_io->u.bdev.copy.src_offset_blocks,
|
|
|
|
bdev_io->u.bdev.num_blocks);
|
|
|
|
break;
|
2016-07-20 18:16:23 +00:00
|
|
|
default:
|
2021-05-13 02:09:53 +00:00
|
|
|
rc = -EINVAL;
|
|
|
|
break;
|
2016-07-20 18:16:23 +00:00
|
|
|
}
|
2017-09-15 23:46:53 +00:00
|
|
|
|
2022-12-16 02:39:39 +00:00
|
|
|
if (spdk_unlikely(rc != 0)) {
|
2021-04-20 22:54:59 +00:00
|
|
|
bdev_nvme_io_complete(nbdev_io, rc);
|
2016-07-20 18:16:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-10 06:39:41 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(ch);
|
|
|
|
struct nvme_bdev_io *nbdev_io = (struct nvme_bdev_io *)bdev_io->driver_ctx;
|
|
|
|
|
2022-09-29 03:52:43 +00:00
|
|
|
if (spdk_likely(nbdev_io->submit_tsc == 0)) {
|
|
|
|
nbdev_io->submit_tsc = spdk_bdev_io_get_submit_tsc(bdev_io);
|
|
|
|
} else {
|
|
|
|
/* There are cases where submit_tsc != 0, i.e. retry I/O.
|
|
|
|
* We need to update submit_tsc here.
|
|
|
|
*/
|
|
|
|
nbdev_io->submit_tsc = spdk_get_ticks();
|
|
|
|
}
|
|
|
|
|
2023-01-10 06:39:41 +00:00
|
|
|
spdk_trace_record(TRACE_BDEV_NVME_IO_START, 0, 0, (uintptr_t)nbdev_io, (uintptr_t)bdev_io);
|
|
|
|
nbdev_io->io_path = bdev_nvme_find_io_path(nbdev_ch);
|
|
|
|
if (spdk_unlikely(!nbdev_io->io_path)) {
|
|
|
|
if (!bdev_nvme_io_type_is_admin(bdev_io->type)) {
|
|
|
|
bdev_nvme_io_complete(nbdev_io, -ENXIO);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Admin commands do not use the optimal I/O path.
|
|
|
|
* Simply fall through even if it is not found.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
_bdev_nvme_submit_request(nbdev_ch, bdev_io);
|
|
|
|
}
|
|
|
|
|
2016-08-24 17:25:49 +00:00
|
|
|
static bool
|
2017-04-04 21:10:00 +00:00
|
|
|
bdev_nvme_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
|
2016-08-24 17:25:49 +00:00
|
|
|
{
|
2017-04-04 21:10:00 +00:00
|
|
|
struct nvme_bdev *nbdev = ctx;
|
2021-06-30 01:08:29 +00:00
|
|
|
struct nvme_ns *nvme_ns;
|
2021-01-10 18:15:22 +00:00
|
|
|
struct spdk_nvme_ns *ns;
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr;
|
2016-08-24 17:25:49 +00:00
|
|
|
const struct spdk_nvme_ctrlr_data *cdata;
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
nvme_ns = TAILQ_FIRST(&nbdev->nvme_ns_list);
|
2021-01-10 18:15:22 +00:00
|
|
|
assert(nvme_ns != NULL);
|
|
|
|
ns = nvme_ns->ns;
|
|
|
|
ctrlr = spdk_nvme_ns_get_ctrlr(ns);
|
|
|
|
|
2016-08-24 17:25:49 +00:00
|
|
|
switch (io_type) {
|
|
|
|
case SPDK_BDEV_IO_TYPE_READ:
|
|
|
|
case SPDK_BDEV_IO_TYPE_WRITE:
|
|
|
|
case SPDK_BDEV_IO_TYPE_RESET:
|
|
|
|
case SPDK_BDEV_IO_TYPE_FLUSH:
|
2017-05-13 20:12:13 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_NVME_ADMIN:
|
2017-06-05 18:02:09 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_NVME_IO:
|
2020-07-08 08:03:49 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_ABORT:
|
2016-08-24 17:25:49 +00:00
|
|
|
return true;
|
|
|
|
|
2019-12-13 08:40:54 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_COMPARE:
|
2020-11-14 22:40:19 +00:00
|
|
|
return spdk_nvme_ns_supports_compare(ns);
|
2019-12-13 08:40:54 +00:00
|
|
|
|
2017-11-14 06:33:11 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_NVME_IO_MD:
|
2020-11-14 22:40:19 +00:00
|
|
|
return spdk_nvme_ns_get_md_size(ns) ? true : false;
|
2017-11-14 06:33:11 +00:00
|
|
|
|
2016-08-24 17:25:49 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_UNMAP:
|
2020-11-14 22:40:19 +00:00
|
|
|
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
|
2016-08-24 17:25:49 +00:00
|
|
|
return cdata->oncs.dsm;
|
|
|
|
|
2017-07-28 20:01:14 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
|
2021-05-14 11:26:40 +00:00
|
|
|
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
|
|
|
|
return cdata->oncs.write_zeroes;
|
2017-07-28 20:01:14 +00:00
|
|
|
|
2019-12-20 11:29:48 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_COMPARE_AND_WRITE:
|
2020-11-14 22:40:19 +00:00
|
|
|
if (spdk_nvme_ctrlr_get_flags(ctrlr) &
|
2019-12-20 11:29:48 +00:00
|
|
|
SPDK_NVME_CTRLR_COMPARE_AND_WRITE_SUPPORTED) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
|
2021-03-03 18:38:38 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_GET_ZONE_INFO:
|
|
|
|
case SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT:
|
|
|
|
return spdk_nvme_ns_get_csi(ns) == SPDK_NVME_CSI_ZNS;
|
|
|
|
|
|
|
|
case SPDK_BDEV_IO_TYPE_ZONE_APPEND:
|
|
|
|
return spdk_nvme_ns_get_csi(ns) == SPDK_NVME_CSI_ZNS &&
|
|
|
|
spdk_nvme_ctrlr_get_flags(ctrlr) & SPDK_NVME_CTRLR_ZONE_APPEND_SUPPORTED;
|
|
|
|
|
2022-08-22 12:47:31 +00:00
|
|
|
case SPDK_BDEV_IO_TYPE_COPY:
|
|
|
|
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
|
|
|
|
return cdata->oncs.copy;
|
|
|
|
|
2016-08-24 17:25:49 +00:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-16 19:53:32 +00:00
|
|
|
static int
|
2022-03-07 01:38:34 +00:00
|
|
|
nvme_qpair_create(struct nvme_ctrlr *nvme_ctrlr, struct nvme_ctrlr_channel *ctrlr_ch)
|
2016-09-16 19:53:32 +00:00
|
|
|
{
|
2022-03-09 06:44:18 +00:00
|
|
|
struct nvme_qpair *nvme_qpair;
|
2021-05-10 18:14:58 +00:00
|
|
|
struct spdk_io_channel *pg_ch;
|
2020-02-07 00:20:35 +00:00
|
|
|
int rc;
|
2017-06-15 16:59:02 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_qpair = calloc(1, sizeof(*nvme_qpair));
|
|
|
|
if (!nvme_qpair) {
|
|
|
|
SPDK_ERRLOG("Failed to alloc nvme_qpair.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_INIT(&nvme_qpair->io_path_list);
|
|
|
|
|
|
|
|
nvme_qpair->ctrlr = nvme_ctrlr;
|
|
|
|
nvme_qpair->ctrlr_ch = ctrlr_ch;
|
2022-03-07 01:38:34 +00:00
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
pg_ch = spdk_get_io_channel(&g_nvme_bdev_ctrlrs);
|
2020-02-07 00:20:35 +00:00
|
|
|
if (!pg_ch) {
|
2022-03-09 06:44:18 +00:00
|
|
|
free(nvme_qpair);
|
2021-05-10 18:14:58 +00:00
|
|
|
return -1;
|
2020-02-07 00:20:35 +00:00
|
|
|
}
|
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_qpair->group = spdk_io_channel_get_ctx(pg_ch);
|
2020-02-07 00:20:35 +00:00
|
|
|
|
|
|
|
#ifdef SPDK_CONFIG_VTUNE
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_qpair->group->collect_spin_stat = true;
|
2020-02-07 00:20:35 +00:00
|
|
|
#else
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_qpair->group->collect_spin_stat = false;
|
2020-02-07 00:20:35 +00:00
|
|
|
#endif
|
2019-11-08 21:26:09 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
rc = bdev_nvme_create_qpair(nvme_qpair);
|
2020-11-13 12:06:52 +00:00
|
|
|
if (rc != 0) {
|
2022-09-12 01:22:33 +00:00
|
|
|
/* nvme_ctrlr can't create IO qpair if connection is down.
|
|
|
|
*
|
|
|
|
* If reconnect_delay_sec is non-zero, creating IO qpair is retried
|
|
|
|
* after reconnect_delay_sec seconds. If bdev_retry_count is non-zero,
|
|
|
|
* submitted IO will be queued until IO qpair is successfully created.
|
|
|
|
*
|
|
|
|
* Hence, if both are satisfied, ignore the failure.
|
|
|
|
*/
|
|
|
|
if (nvme_ctrlr->opts.reconnect_delay_sec == 0 || g_opts.bdev_retry_count == 0) {
|
2022-03-07 01:38:34 +00:00
|
|
|
spdk_put_io_channel(pg_ch);
|
2022-03-09 06:44:18 +00:00
|
|
|
free(nvme_qpair);
|
2022-03-07 01:38:34 +00:00
|
|
|
return rc;
|
2021-12-22 11:53:42 +00:00
|
|
|
}
|
2020-11-13 12:06:52 +00:00
|
|
|
}
|
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
TAILQ_INSERT_TAIL(&nvme_qpair->group->qpair_list, nvme_qpair, tailq);
|
|
|
|
|
|
|
|
ctrlr_ch->qpair = nvme_qpair;
|
2022-03-07 01:38:34 +00:00
|
|
|
|
2022-03-09 06:48:11 +00:00
|
|
|
pthread_mutex_lock(&nvme_qpair->ctrlr->mutex);
|
|
|
|
nvme_qpair->ctrlr->ref++;
|
|
|
|
pthread_mutex_unlock(&nvme_qpair->ctrlr->mutex);
|
|
|
|
|
2016-09-16 19:53:32 +00:00
|
|
|
return 0;
|
2022-03-07 01:38:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bdev_nvme_create_ctrlr_channel_cb(void *io_device, void *ctx_buf)
|
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = io_device;
|
|
|
|
struct nvme_ctrlr_channel *ctrlr_ch = ctx_buf;
|
|
|
|
|
|
|
|
TAILQ_INIT(&ctrlr_ch->pending_resets);
|
|
|
|
|
|
|
|
return nvme_qpair_create(nvme_ctrlr, ctrlr_ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_qpair_delete(struct nvme_qpair *nvme_qpair)
|
2022-03-07 01:38:34 +00:00
|
|
|
{
|
2022-03-09 06:44:18 +00:00
|
|
|
assert(nvme_qpair->group != NULL);
|
|
|
|
|
|
|
|
TAILQ_REMOVE(&nvme_qpair->group->qpair_list, nvme_qpair, tailq);
|
2020-02-07 00:20:35 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
spdk_put_io_channel(spdk_io_channel_from_ctx(nvme_qpair->group));
|
2020-11-13 12:06:52 +00:00
|
|
|
|
2022-03-09 06:48:11 +00:00
|
|
|
nvme_ctrlr_release(nvme_qpair->ctrlr);
|
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
free(nvme_qpair);
|
2016-09-16 19:53:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-07-07 01:02:14 +00:00
|
|
|
bdev_nvme_destroy_ctrlr_channel_cb(void *io_device, void *ctx_buf)
|
2016-09-16 19:53:32 +00:00
|
|
|
{
|
2021-07-07 01:02:14 +00:00
|
|
|
struct nvme_ctrlr_channel *ctrlr_ch = ctx_buf;
|
2022-03-09 06:44:18 +00:00
|
|
|
struct nvme_qpair *nvme_qpair;
|
2020-02-07 00:20:35 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_qpair = ctrlr_ch->qpair;
|
|
|
|
assert(nvme_qpair != NULL);
|
2022-03-08 22:24:35 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
_bdev_nvme_clear_io_path_cache(nvme_qpair);
|
|
|
|
|
|
|
|
if (nvme_qpair->qpair != NULL) {
|
2022-03-09 06:53:15 +00:00
|
|
|
if (ctrlr_ch->reset_iter == NULL) {
|
|
|
|
spdk_nvme_ctrlr_disconnect_io_qpair(nvme_qpair->qpair);
|
|
|
|
} else {
|
|
|
|
/* Skip current ctrlr_channel in a full reset sequence because
|
|
|
|
* it is being deleted now. The qpair is already being disconnected.
|
|
|
|
* We do not have to restart disconnecting it.
|
|
|
|
*/
|
|
|
|
spdk_for_each_channel_continue(ctrlr_ch->reset_iter, 0);
|
|
|
|
}
|
2020-02-07 00:20:35 +00:00
|
|
|
|
2022-03-09 06:48:11 +00:00
|
|
|
/* We cannot release a reference to the poll group now.
|
|
|
|
* The qpair may be disconnected asynchronously later.
|
|
|
|
* We need to poll it until it is actually disconnected.
|
2022-03-09 06:53:15 +00:00
|
|
|
* Just detach the qpair from the deleting ctrlr_channel.
|
2022-03-09 06:48:11 +00:00
|
|
|
*/
|
|
|
|
nvme_qpair->ctrlr_ch = NULL;
|
|
|
|
} else {
|
2022-03-09 06:53:15 +00:00
|
|
|
assert(ctrlr_ch->reset_iter == NULL);
|
|
|
|
|
2022-03-09 06:48:11 +00:00
|
|
|
nvme_qpair_delete(nvme_qpair);
|
|
|
|
}
|
2020-02-07 00:20:35 +00:00
|
|
|
}
|
|
|
|
|
2021-03-08 17:43:10 +00:00
|
|
|
static void
|
2021-07-06 17:20:32 +00:00
|
|
|
bdev_nvme_submit_accel_crc32c(void *ctx, uint32_t *dst, struct iovec *iov,
|
|
|
|
uint32_t iov_cnt, uint32_t seed,
|
|
|
|
spdk_nvme_accel_completion_cb cb_fn, void *cb_arg)
|
2021-03-08 17:43:10 +00:00
|
|
|
{
|
2021-07-06 17:20:32 +00:00
|
|
|
struct nvme_poll_group *group = ctx;
|
2021-03-08 17:43:10 +00:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
assert(group->accel_channel != NULL);
|
|
|
|
assert(cb_fn != NULL);
|
|
|
|
|
|
|
|
rc = spdk_accel_submit_crc32cv(group->accel_channel, dst, iov, iov_cnt, seed, cb_fn, cb_arg);
|
|
|
|
if (rc) {
|
|
|
|
/* For the two cases, spdk_accel_submit_crc32cv does not call the user's cb_fn */
|
|
|
|
if (rc == -ENOMEM || rc == -EINVAL) {
|
|
|
|
cb_fn(cb_arg, rc);
|
|
|
|
}
|
|
|
|
SPDK_ERRLOG("Cannot complete the accelerated crc32c operation with iov=%p\n", iov);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct spdk_nvme_accel_fn_table g_bdev_nvme_accel_fn_table = {
|
|
|
|
.table_size = sizeof(struct spdk_nvme_accel_fn_table),
|
2021-07-06 17:20:32 +00:00
|
|
|
.submit_accel_crc32c = bdev_nvme_submit_accel_crc32c,
|
2021-03-08 17:43:10 +00:00
|
|
|
};
|
|
|
|
|
2020-02-07 00:20:35 +00:00
|
|
|
static int
|
2021-07-06 17:20:32 +00:00
|
|
|
bdev_nvme_create_poll_group_cb(void *io_device, void *ctx_buf)
|
2020-02-07 00:20:35 +00:00
|
|
|
{
|
2021-07-06 17:20:32 +00:00
|
|
|
struct nvme_poll_group *group = ctx_buf;
|
2020-02-07 00:20:35 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
TAILQ_INIT(&group->qpair_list);
|
2021-09-15 03:10:35 +00:00
|
|
|
|
2021-03-08 17:43:10 +00:00
|
|
|
group->group = spdk_nvme_poll_group_create(group, &g_bdev_nvme_accel_fn_table);
|
2020-02-07 00:20:35 +00:00
|
|
|
if (group->group == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-08-08 20:51:25 +00:00
|
|
|
group->accel_channel = spdk_accel_get_io_channel();
|
2021-03-08 17:43:10 +00:00
|
|
|
if (!group->accel_channel) {
|
|
|
|
spdk_nvme_poll_group_destroy(group->group);
|
|
|
|
SPDK_ERRLOG("Cannot get the accel_channel for bdev nvme polling group=%p\n",
|
|
|
|
group);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-07-08 01:13:08 +00:00
|
|
|
group->poller = SPDK_POLLER_REGISTER(bdev_nvme_poll, group, g_opts.nvme_ioq_poll_period_us);
|
2020-02-07 00:20:35 +00:00
|
|
|
|
|
|
|
if (group->poller == NULL) {
|
2021-03-08 17:43:10 +00:00
|
|
|
spdk_put_io_channel(group->accel_channel);
|
2020-02-07 00:20:35 +00:00
|
|
|
spdk_nvme_poll_group_destroy(group->group);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-07-06 17:20:32 +00:00
|
|
|
bdev_nvme_destroy_poll_group_cb(void *io_device, void *ctx_buf)
|
2020-02-07 00:20:35 +00:00
|
|
|
{
|
2021-07-06 17:20:32 +00:00
|
|
|
struct nvme_poll_group *group = ctx_buf;
|
2020-02-07 00:20:35 +00:00
|
|
|
|
2022-03-09 06:44:18 +00:00
|
|
|
assert(TAILQ_EMPTY(&group->qpair_list));
|
2021-09-15 03:10:35 +00:00
|
|
|
|
2021-03-08 17:43:10 +00:00
|
|
|
if (group->accel_channel) {
|
|
|
|
spdk_put_io_channel(group->accel_channel);
|
|
|
|
}
|
|
|
|
|
2020-02-07 00:20:35 +00:00
|
|
|
spdk_poller_unregister(&group->poller);
|
|
|
|
if (spdk_nvme_poll_group_destroy(group->group)) {
|
2021-03-24 03:35:32 +00:00
|
|
|
SPDK_ERRLOG("Unable to destroy a poll group for the NVMe bdev module.\n");
|
2020-02-07 00:20:35 +00:00
|
|
|
assert(false);
|
|
|
|
}
|
2016-09-16 19:53:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct spdk_io_channel *
|
2017-05-18 17:48:04 +00:00
|
|
|
bdev_nvme_get_io_channel(void *ctx)
|
2016-09-16 19:53:32 +00:00
|
|
|
{
|
2017-04-04 21:10:00 +00:00
|
|
|
struct nvme_bdev *nvme_bdev = ctx;
|
2016-09-16 19:53:32 +00:00
|
|
|
|
2021-07-06 17:35:01 +00:00
|
|
|
return spdk_get_io_channel(nvme_bdev);
|
2016-09-16 19:53:32 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 16:13:54 +00:00
|
|
|
static void *
|
|
|
|
bdev_nvme_get_module_ctx(void *ctx)
|
|
|
|
{
|
|
|
|
struct nvme_bdev *nvme_bdev = ctx;
|
2021-09-27 23:15:02 +00:00
|
|
|
struct nvme_ns *nvme_ns;
|
|
|
|
|
|
|
|
if (!nvme_bdev || nvme_bdev->disk.module != &nvme_if) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-10-27 16:13:54 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
nvme_ns = TAILQ_FIRST(&nvme_bdev->nvme_ns_list);
|
|
|
|
if (!nvme_ns) {
|
2021-09-01 09:47:10 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
return nvme_ns->ns;
|
2020-10-27 16:13:54 +00:00
|
|
|
}
|
|
|
|
|
2021-04-20 14:42:50 +00:00
|
|
|
static const char *
|
|
|
|
_nvme_ana_state_str(enum spdk_nvme_ana_state ana_state)
|
|
|
|
{
|
|
|
|
switch (ana_state) {
|
|
|
|
case SPDK_NVME_ANA_OPTIMIZED_STATE:
|
|
|
|
return "optimized";
|
|
|
|
case SPDK_NVME_ANA_NON_OPTIMIZED_STATE:
|
|
|
|
return "non_optimized";
|
|
|
|
case SPDK_NVME_ANA_INACCESSIBLE_STATE:
|
|
|
|
return "inaccessible";
|
|
|
|
case SPDK_NVME_ANA_PERSISTENT_LOSS_STATE:
|
|
|
|
return "persistent_loss";
|
|
|
|
case SPDK_NVME_ANA_CHANGE_STATE:
|
|
|
|
return "change";
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-06 05:31:02 +00:00
|
|
|
static int
|
|
|
|
bdev_nvme_get_memory_domains(void *ctx, struct spdk_memory_domain **domains, int array_size)
|
|
|
|
{
|
2022-10-13 14:45:51 +00:00
|
|
|
struct spdk_memory_domain **_domains = NULL;
|
2021-08-06 05:31:02 +00:00
|
|
|
struct nvme_bdev *nbdev = ctx;
|
2021-09-27 23:15:02 +00:00
|
|
|
struct nvme_ns *nvme_ns;
|
2022-10-13 14:45:51 +00:00
|
|
|
int i = 0, _array_size = array_size;
|
|
|
|
int rc = 0;
|
2021-09-27 23:15:02 +00:00
|
|
|
|
2022-10-13 14:45:51 +00:00
|
|
|
TAILQ_FOREACH(nvme_ns, &nbdev->nvme_ns_list, tailq) {
|
|
|
|
if (domains && array_size >= i) {
|
|
|
|
_domains = &domains[i];
|
|
|
|
} else {
|
|
|
|
_domains = NULL;
|
|
|
|
}
|
|
|
|
rc = spdk_nvme_ctrlr_get_memory_domains(nvme_ns->ctrlr->ctrlr, _domains, _array_size);
|
|
|
|
if (rc > 0) {
|
|
|
|
i += rc;
|
|
|
|
if (_array_size >= rc) {
|
|
|
|
_array_size -= rc;
|
|
|
|
} else {
|
|
|
|
_array_size = 0;
|
|
|
|
}
|
|
|
|
} else if (rc < 0) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
2021-08-06 05:31:02 +00:00
|
|
|
|
2022-10-13 14:45:51 +00:00
|
|
|
return i;
|
2021-08-06 05:31:02 +00:00
|
|
|
}
|
|
|
|
|
2022-04-20 05:11:04 +00:00
|
|
|
static const char *
|
|
|
|
nvme_ctrlr_get_state_str(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
if (nvme_ctrlr->destruct) {
|
|
|
|
return "deleting";
|
|
|
|
} else if (spdk_nvme_ctrlr_is_failed(nvme_ctrlr->ctrlr)) {
|
|
|
|
return "failed";
|
|
|
|
} else if (nvme_ctrlr->resetting) {
|
|
|
|
return "resetting";
|
|
|
|
} else if (nvme_ctrlr->reconnect_is_delayed > 0) {
|
|
|
|
return "reconnect_is_delayed";
|
|
|
|
} else {
|
|
|
|
return "enabled";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nvme_ctrlr_info_json(struct spdk_json_write_ctx *w, struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_transport_id *trid;
|
|
|
|
const struct spdk_nvme_ctrlr_opts *opts;
|
2022-04-20 05:39:47 +00:00
|
|
|
const struct spdk_nvme_ctrlr_data *cdata;
|
2022-04-20 05:11:04 +00:00
|
|
|
|
|
|
|
spdk_json_write_object_begin(w);
|
|
|
|
|
|
|
|
spdk_json_write_named_string(w, "state", nvme_ctrlr_get_state_str(nvme_ctrlr));
|
|
|
|
|
|
|
|
#ifdef SPDK_CONFIG_NVME_CUSE
|
|
|
|
size_t cuse_name_size = 128;
|
|
|
|
char cuse_name[cuse_name_size];
|
|
|
|
|
|
|
|
int rc = spdk_nvme_cuse_get_ctrlr_name(nvme_ctrlr->ctrlr, cuse_name, &cuse_name_size);
|
|
|
|
if (rc == 0) {
|
|
|
|
spdk_json_write_named_string(w, "cuse_device", cuse_name);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
trid = &nvme_ctrlr->active_path_id->trid;
|
|
|
|
spdk_json_write_named_object_begin(w, "trid");
|
|
|
|
nvme_bdev_dump_trid_json(trid, w);
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
2022-04-20 05:39:47 +00:00
|
|
|
cdata = spdk_nvme_ctrlr_get_data(nvme_ctrlr->ctrlr);
|
|
|
|
spdk_json_write_named_uint16(w, "cntlid", cdata->cntlid);
|
|
|
|
|
2022-04-20 05:11:04 +00:00
|
|
|
opts = spdk_nvme_ctrlr_get_opts(nvme_ctrlr->ctrlr);
|
|
|
|
spdk_json_write_named_object_begin(w, "host");
|
|
|
|
spdk_json_write_named_string(w, "nqn", opts->hostnqn);
|
|
|
|
spdk_json_write_named_string(w, "addr", opts->src_addr);
|
|
|
|
spdk_json_write_named_string(w, "svcid", opts->src_svcid);
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
static void
|
|
|
|
nvme_namespace_info_json(struct spdk_json_write_ctx *w,
|
|
|
|
struct nvme_ns *nvme_ns)
|
2016-11-18 17:22:58 +00:00
|
|
|
{
|
2021-01-10 18:15:22 +00:00
|
|
|
struct spdk_nvme_ns *ns;
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr;
|
2016-12-05 20:59:39 +00:00
|
|
|
const struct spdk_nvme_ctrlr_data *cdata;
|
2020-11-14 22:57:14 +00:00
|
|
|
const struct spdk_nvme_transport_id *trid;
|
2016-12-05 20:59:39 +00:00
|
|
|
union spdk_nvme_vs_register vs;
|
2022-04-20 05:33:23 +00:00
|
|
|
const struct spdk_nvme_ns_data *nsdata;
|
2016-12-05 20:59:39 +00:00
|
|
|
char buf[128];
|
|
|
|
|
2021-01-10 18:15:22 +00:00
|
|
|
ns = nvme_ns->ns;
|
|
|
|
ctrlr = spdk_nvme_ns_get_ctrlr(ns);
|
|
|
|
|
2020-11-14 23:05:33 +00:00
|
|
|
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
|
|
|
|
trid = spdk_nvme_ctrlr_get_transport_id(ctrlr);
|
|
|
|
vs = spdk_nvme_ctrlr_get_regs_vs(ctrlr);
|
2016-11-18 17:22:58 +00:00
|
|
|
|
2021-11-08 02:16:40 +00:00
|
|
|
spdk_json_write_object_begin(w);
|
2016-11-18 17:22:58 +00:00
|
|
|
|
2020-11-14 22:57:14 +00:00
|
|
|
if (trid->trtype == SPDK_NVME_TRANSPORT_PCIE) {
|
|
|
|
spdk_json_write_named_string(w, "pci_address", trid->traddr);
|
2017-01-25 23:36:40 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 19:30:03 +00:00
|
|
|
spdk_json_write_named_object_begin(w, "trid");
|
2017-01-25 23:36:40 +00:00
|
|
|
|
2020-11-14 22:57:14 +00:00
|
|
|
nvme_bdev_dump_trid_json(trid, w);
|
2017-01-25 23:36:40 +00:00
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
2016-12-05 20:59:39 +00:00
|
|
|
|
2019-10-24 18:09:47 +00:00
|
|
|
#ifdef SPDK_CONFIG_NVME_CUSE
|
2020-04-22 11:36:06 +00:00
|
|
|
size_t cuse_name_size = 128;
|
|
|
|
char cuse_name[cuse_name_size];
|
2019-10-24 18:09:47 +00:00
|
|
|
|
2020-11-14 23:05:33 +00:00
|
|
|
int rc = spdk_nvme_cuse_get_ns_name(ctrlr, spdk_nvme_ns_get_id(ns),
|
2020-04-22 11:36:06 +00:00
|
|
|
cuse_name, &cuse_name_size);
|
|
|
|
if (rc == 0) {
|
|
|
|
spdk_json_write_named_string(w, "cuse_device", cuse_name);
|
2019-10-24 18:09:47 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-02-22 19:30:03 +00:00
|
|
|
spdk_json_write_named_object_begin(w, "ctrlr_data");
|
2016-12-12 23:57:20 +00:00
|
|
|
|
2022-04-20 05:39:47 +00:00
|
|
|
spdk_json_write_named_uint16(w, "cntlid", cdata->cntlid);
|
|
|
|
|
2018-02-22 19:30:03 +00:00
|
|
|
spdk_json_write_named_string_fmt(w, "vendor_id", "0x%04x", cdata->vid);
|
2016-12-05 20:59:39 +00:00
|
|
|
|
|
|
|
snprintf(buf, sizeof(cdata->mn) + 1, "%s", cdata->mn);
|
|
|
|
spdk_str_trim(buf);
|
2018-02-22 19:30:03 +00:00
|
|
|
spdk_json_write_named_string(w, "model_number", buf);
|
2016-12-05 20:59:39 +00:00
|
|
|
|
|
|
|
snprintf(buf, sizeof(cdata->sn) + 1, "%s", cdata->sn);
|
|
|
|
spdk_str_trim(buf);
|
2018-02-22 19:30:03 +00:00
|
|
|
spdk_json_write_named_string(w, "serial_number", buf);
|
2016-12-05 20:59:39 +00:00
|
|
|
|
|
|
|
snprintf(buf, sizeof(cdata->fr) + 1, "%s", cdata->fr);
|
|
|
|
spdk_str_trim(buf);
|
2018-02-22 19:30:03 +00:00
|
|
|
spdk_json_write_named_string(w, "firmware_revision", buf);
|
2016-12-05 20:59:39 +00:00
|
|
|
|
2020-10-29 19:27:14 +00:00
|
|
|
if (cdata->subnqn[0] != '\0') {
|
|
|
|
spdk_json_write_named_string(w, "subnqn", cdata->subnqn);
|
|
|
|
}
|
|
|
|
|
2018-02-22 19:30:03 +00:00
|
|
|
spdk_json_write_named_object_begin(w, "oacs");
|
2017-01-03 22:47:32 +00:00
|
|
|
|
2018-02-22 19:30:03 +00:00
|
|
|
spdk_json_write_named_uint32(w, "security", cdata->oacs.security);
|
|
|
|
spdk_json_write_named_uint32(w, "format", cdata->oacs.format);
|
|
|
|
spdk_json_write_named_uint32(w, "firmware", cdata->oacs.firmware);
|
|
|
|
spdk_json_write_named_uint32(w, "ns_manage", cdata->oacs.ns_manage);
|
2017-01-03 22:47:32 +00:00
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
2022-04-20 05:33:23 +00:00
|
|
|
spdk_json_write_named_bool(w, "multi_ctrlr", cdata->cmic.multi_ctrlr);
|
|
|
|
spdk_json_write_named_bool(w, "ana_reporting", cdata->cmic.ana_reporting);
|
|
|
|
|
2016-12-12 23:57:20 +00:00
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
2018-02-22 19:30:03 +00:00
|
|
|
spdk_json_write_named_object_begin(w, "vs");
|
2016-12-12 23:57:20 +00:00
|
|
|
|
2016-12-06 22:25:28 +00:00
|
|
|
spdk_json_write_name(w, "nvme_version");
|
2016-12-05 20:59:39 +00:00
|
|
|
if (vs.bits.ter) {
|
2016-12-06 22:25:28 +00:00
|
|
|
spdk_json_write_string_fmt(w, "%u.%u.%u", vs.bits.mjr, vs.bits.mnr, vs.bits.ter);
|
|
|
|
} else {
|
|
|
|
spdk_json_write_string_fmt(w, "%u.%u", vs.bits.mjr, vs.bits.mnr);
|
2016-12-05 20:59:39 +00:00
|
|
|
}
|
|
|
|
|
2016-12-12 23:57:20 +00:00
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
2022-04-20 05:33:23 +00:00
|
|
|
nsdata = spdk_nvme_ns_get_data(ns);
|
|
|
|
|
2018-02-22 19:30:03 +00:00
|
|
|
spdk_json_write_named_object_begin(w, "ns_data");
|
2016-12-12 23:57:20 +00:00
|
|
|
|
2018-02-22 19:30:03 +00:00
|
|
|
spdk_json_write_named_uint32(w, "id", spdk_nvme_ns_get_id(ns));
|
2016-12-05 20:59:39 +00:00
|
|
|
|
2021-04-20 14:42:50 +00:00
|
|
|
if (cdata->cmic.ana_reporting) {
|
|
|
|
spdk_json_write_named_string(w, "ana_state",
|
2021-07-02 07:03:59 +00:00
|
|
|
_nvme_ana_state_str(nvme_ns->ana_state));
|
2021-04-20 14:42:50 +00:00
|
|
|
}
|
|
|
|
|
2022-04-20 05:33:23 +00:00
|
|
|
spdk_json_write_named_bool(w, "can_share", nsdata->nmic.can_share);
|
|
|
|
|
2016-11-18 17:22:58 +00:00
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
2019-07-19 15:26:53 +00:00
|
|
|
if (cdata->oacs.security) {
|
|
|
|
spdk_json_write_named_object_begin(w, "security");
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
spdk_json_write_named_bool(w, "opal", nvme_ns->bdev->opal);
|
2019-07-19 15:26:53 +00:00
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
|
2016-12-12 23:57:20 +00:00
|
|
|
spdk_json_write_object_end(w);
|
2021-09-27 23:15:02 +00:00
|
|
|
}
|
|
|
|
|
2022-04-29 05:37:35 +00:00
|
|
|
static const char *
|
|
|
|
nvme_bdev_get_mp_policy_str(struct nvme_bdev *nbdev)
|
|
|
|
{
|
|
|
|
switch (nbdev->mp_policy) {
|
|
|
|
case BDEV_NVME_MP_POLICY_ACTIVE_PASSIVE:
|
|
|
|
return "active_passive";
|
|
|
|
case BDEV_NVME_MP_POLICY_ACTIVE_ACTIVE:
|
|
|
|
return "active_active";
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
return "invalid";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
static int
|
|
|
|
bdev_nvme_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
|
|
|
|
{
|
|
|
|
struct nvme_bdev *nvme_bdev = ctx;
|
|
|
|
struct nvme_ns *nvme_ns;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&nvme_bdev->mutex);
|
2021-11-08 02:16:40 +00:00
|
|
|
spdk_json_write_named_array_begin(w, "nvme");
|
2021-09-27 23:15:02 +00:00
|
|
|
TAILQ_FOREACH(nvme_ns, &nvme_bdev->nvme_ns_list, tailq) {
|
|
|
|
nvme_namespace_info_json(w, nvme_ns);
|
|
|
|
}
|
2021-11-08 02:16:40 +00:00
|
|
|
spdk_json_write_array_end(w);
|
2022-04-29 05:37:35 +00:00
|
|
|
spdk_json_write_named_string(w, "mp_policy", nvme_bdev_get_mp_policy_str(nvme_bdev));
|
2021-09-27 23:15:02 +00:00
|
|
|
pthread_mutex_unlock(&nvme_bdev->mutex);
|
2016-12-12 23:57:20 +00:00
|
|
|
|
2016-11-18 17:22:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-05 15:43:55 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
|
|
|
|
{
|
|
|
|
/* No config per bdev needed */
|
|
|
|
}
|
|
|
|
|
2017-06-15 16:59:02 +00:00
|
|
|
static uint64_t
|
|
|
|
bdev_nvme_get_spin_time(struct spdk_io_channel *ch)
|
|
|
|
{
|
2021-07-06 17:35:01 +00:00
|
|
|
struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(ch);
|
2021-09-27 23:15:02 +00:00
|
|
|
struct nvme_io_path *io_path;
|
|
|
|
struct nvme_poll_group *group;
|
|
|
|
uint64_t spin_time = 0;
|
2017-06-15 16:59:02 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
|
2022-03-09 06:44:18 +00:00
|
|
|
group = io_path->qpair->group;
|
2017-06-15 16:59:02 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
if (!group || !group->collect_spin_stat) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-06-15 16:59:02 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
if (group->end_ticks != 0) {
|
|
|
|
group->spin_ticks += (group->end_ticks - group->start_ticks);
|
|
|
|
group->end_ticks = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_time += group->spin_ticks;
|
|
|
|
group->start_ticks = 0;
|
|
|
|
group->spin_ticks = 0;
|
|
|
|
}
|
2017-06-15 16:59:02 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
return (spin_time * 1000000ULL) / spdk_get_ticks_hz();
|
2017-06-15 16:59:02 +00:00
|
|
|
}
|
|
|
|
|
bdev/nvme: Count number of NVMe errors per type or code
Error counters for NVMe error was added in the generic bdev layer but
we want to know more detailed information for some use cases.
Add NVMe error counters per type and per code as module specific
statistics.
For status codes, the first idea was to have different named member
for each status code value. However, it was bad and too hard to test,
review, and maintain.
Instead, we have just two dimensional uint32_t arrays, and increment
one of these uint32_t values based on the status code type and status
code. Then, when dump the JSON, we use spdk_nvme_cpl_get_status_string()
and spdk_nvme_cpl_get_status_type_string().
This idea has one potential downside. This idea consumes 4 (types) *
256 (codes) * 4 (counter) = 4KB per NVMe bdev. We can make this smarter
if memory allocation is a problem. Hence we add an option
nvme_error_stat to enable this feature only if the user requests.
Additionally, the string returned by spdk_nvme_cpl_get_status_string()
or spdk_nvme_cpl_get_status_type_string() has uppercases, spaces, and
hyphens. These should not be included in JSON strings. Hence, convert
these via spdk_strcpy_replace().
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I07b07621e777bdf6556b95054abbbb65e5f9ea3e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15370
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
2023-01-05 23:26:33 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_reset_device_stat(void *ctx)
|
|
|
|
{
|
|
|
|
struct nvme_bdev *nbdev = ctx;
|
|
|
|
|
|
|
|
if (nbdev->err_stat != NULL) {
|
|
|
|
memset(nbdev->err_stat, 0, sizeof(struct nvme_error_stat));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* JSON string should be lowercases and underscore delimited string. */
|
|
|
|
static void
|
|
|
|
bdev_nvme_format_nvme_status(char *dst, const char *src)
|
|
|
|
{
|
|
|
|
char tmp[256];
|
|
|
|
|
|
|
|
spdk_strcpy_replace(dst, 256, src, " - ", "_");
|
|
|
|
spdk_strcpy_replace(tmp, 256, dst, "-", "_");
|
|
|
|
spdk_strcpy_replace(dst, 256, tmp, " ", "_");
|
|
|
|
spdk_strlwr(dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_dump_device_stat_json(void *ctx, struct spdk_json_write_ctx *w)
|
|
|
|
{
|
|
|
|
struct nvme_bdev *nbdev = ctx;
|
|
|
|
struct spdk_nvme_status status = {};
|
|
|
|
uint16_t sct, sc;
|
|
|
|
char status_json[256];
|
|
|
|
const char *status_str;
|
|
|
|
|
|
|
|
if (nbdev->err_stat == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_json_write_named_object_begin(w, "nvme_error");
|
|
|
|
|
|
|
|
spdk_json_write_named_object_begin(w, "status_type");
|
|
|
|
for (sct = 0; sct < 8; sct++) {
|
|
|
|
if (nbdev->err_stat->status_type[sct] == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
status.sct = sct;
|
|
|
|
|
|
|
|
status_str = spdk_nvme_cpl_get_status_type_string(&status);
|
|
|
|
assert(status_str != NULL);
|
|
|
|
bdev_nvme_format_nvme_status(status_json, status_str);
|
|
|
|
|
|
|
|
spdk_json_write_named_uint32(w, status_json, nbdev->err_stat->status_type[sct]);
|
|
|
|
}
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
|
|
|
spdk_json_write_named_object_begin(w, "status_code");
|
|
|
|
for (sct = 0; sct < 4; sct++) {
|
|
|
|
status.sct = sct;
|
|
|
|
for (sc = 0; sc < 256; sc++) {
|
|
|
|
if (nbdev->err_stat->status[sct][sc] == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
status.sc = sc;
|
|
|
|
|
|
|
|
status_str = spdk_nvme_cpl_get_status_string(&status);
|
|
|
|
assert(status_str != NULL);
|
|
|
|
bdev_nvme_format_nvme_status(status_json, status_str);
|
|
|
|
|
|
|
|
spdk_json_write_named_uint32(w, status_json, nbdev->err_stat->status[sct][sc]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
|
2016-08-30 19:56:06 +00:00
|
|
|
static const struct spdk_bdev_fn_table nvmelib_fn_table = {
|
2017-02-28 17:51:25 +00:00
|
|
|
.destruct = bdev_nvme_destruct,
|
|
|
|
.submit_request = bdev_nvme_submit_request,
|
|
|
|
.io_type_supported = bdev_nvme_io_type_supported,
|
|
|
|
.get_io_channel = bdev_nvme_get_io_channel,
|
2018-02-22 12:48:13 +00:00
|
|
|
.dump_info_json = bdev_nvme_dump_info_json,
|
2018-04-05 15:43:55 +00:00
|
|
|
.write_config_json = bdev_nvme_write_config_json,
|
2017-06-15 16:59:02 +00:00
|
|
|
.get_spin_time = bdev_nvme_get_spin_time,
|
2020-10-27 16:13:54 +00:00
|
|
|
.get_module_ctx = bdev_nvme_get_module_ctx,
|
2021-08-06 05:31:02 +00:00
|
|
|
.get_memory_domains = bdev_nvme_get_memory_domains,
|
bdev/nvme: Count number of NVMe errors per type or code
Error counters for NVMe error was added in the generic bdev layer but
we want to know more detailed information for some use cases.
Add NVMe error counters per type and per code as module specific
statistics.
For status codes, the first idea was to have different named member
for each status code value. However, it was bad and too hard to test,
review, and maintain.
Instead, we have just two dimensional uint32_t arrays, and increment
one of these uint32_t values based on the status code type and status
code. Then, when dump the JSON, we use spdk_nvme_cpl_get_status_string()
and spdk_nvme_cpl_get_status_type_string().
This idea has one potential downside. This idea consumes 4 (types) *
256 (codes) * 4 (counter) = 4KB per NVMe bdev. We can make this smarter
if memory allocation is a problem. Hence we add an option
nvme_error_stat to enable this feature only if the user requests.
Additionally, the string returned by spdk_nvme_cpl_get_status_string()
or spdk_nvme_cpl_get_status_type_string() has uppercases, spaces, and
hyphens. These should not be included in JSON strings. Hence, convert
these via spdk_strcpy_replace().
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I07b07621e777bdf6556b95054abbbb65e5f9ea3e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15370
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
2023-01-05 23:26:33 +00:00
|
|
|
.reset_device_stat = bdev_nvme_reset_device_stat,
|
|
|
|
.dump_device_stat_json = bdev_nvme_dump_device_stat_json,
|
2016-07-20 18:16:23 +00:00
|
|
|
};
|
|
|
|
|
2021-07-05 11:07:14 +00:00
|
|
|
typedef int (*bdev_nvme_parse_ana_log_page_cb)(
|
|
|
|
const struct spdk_nvme_ana_group_descriptor *desc, void *cb_arg);
|
|
|
|
|
|
|
|
static int
|
|
|
|
bdev_nvme_parse_ana_log_page(struct nvme_ctrlr *nvme_ctrlr,
|
|
|
|
bdev_nvme_parse_ana_log_page_cb cb_fn, void *cb_arg)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_ana_group_descriptor *copied_desc;
|
|
|
|
uint8_t *orig_desc;
|
|
|
|
uint32_t i, desc_size, copy_len;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (nvme_ctrlr->ana_log_page == NULL) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
copied_desc = nvme_ctrlr->copied_ana_desc;
|
|
|
|
|
|
|
|
orig_desc = (uint8_t *)nvme_ctrlr->ana_log_page + sizeof(struct spdk_nvme_ana_page);
|
2022-07-13 04:57:25 +00:00
|
|
|
copy_len = nvme_ctrlr->max_ana_log_page_size - sizeof(struct spdk_nvme_ana_page);
|
2021-07-05 11:07:14 +00:00
|
|
|
|
|
|
|
for (i = 0; i < nvme_ctrlr->ana_log_page->num_ana_group_desc; i++) {
|
|
|
|
memcpy(copied_desc, orig_desc, copy_len);
|
|
|
|
|
|
|
|
rc = cb_fn(copied_desc, cb_arg);
|
|
|
|
if (rc != 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
desc_size = sizeof(struct spdk_nvme_ana_group_descriptor) +
|
|
|
|
copied_desc->num_of_nsid * sizeof(uint32_t);
|
|
|
|
orig_desc += desc_size;
|
|
|
|
copy_len -= desc_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2022-04-07 08:29:05 +00:00
|
|
|
static int
|
|
|
|
nvme_ns_ana_transition_timedout(void *ctx)
|
|
|
|
{
|
|
|
|
struct nvme_ns *nvme_ns = ctx;
|
|
|
|
|
|
|
|
spdk_poller_unregister(&nvme_ns->anatt_timer);
|
|
|
|
nvme_ns->ana_transition_timedout = true;
|
|
|
|
|
|
|
|
return SPDK_POLLER_BUSY;
|
|
|
|
}
|
|
|
|
|
2022-04-07 00:44:38 +00:00
|
|
|
static void
|
|
|
|
_nvme_ns_set_ana_state(struct nvme_ns *nvme_ns,
|
|
|
|
const struct spdk_nvme_ana_group_descriptor *desc)
|
|
|
|
{
|
2022-04-07 08:29:05 +00:00
|
|
|
const struct spdk_nvme_ctrlr_data *cdata;
|
|
|
|
|
2022-04-07 00:44:38 +00:00
|
|
|
nvme_ns->ana_group_id = desc->ana_group_id;
|
|
|
|
nvme_ns->ana_state = desc->ana_state;
|
|
|
|
nvme_ns->ana_state_updating = false;
|
2022-04-07 08:29:05 +00:00
|
|
|
|
|
|
|
switch (nvme_ns->ana_state) {
|
|
|
|
case SPDK_NVME_ANA_OPTIMIZED_STATE:
|
|
|
|
case SPDK_NVME_ANA_NON_OPTIMIZED_STATE:
|
|
|
|
nvme_ns->ana_transition_timedout = false;
|
|
|
|
spdk_poller_unregister(&nvme_ns->anatt_timer);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SPDK_NVME_ANA_INACCESSIBLE_STATE:
|
|
|
|
case SPDK_NVME_ANA_CHANGE_STATE:
|
|
|
|
if (nvme_ns->anatt_timer != NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cdata = spdk_nvme_ctrlr_get_data(nvme_ns->ctrlr->ctrlr);
|
|
|
|
nvme_ns->anatt_timer = SPDK_POLLER_REGISTER(nvme_ns_ana_transition_timedout,
|
|
|
|
nvme_ns,
|
|
|
|
cdata->anatt * SPDK_SEC_TO_USEC);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2022-04-07 00:44:38 +00:00
|
|
|
}
|
|
|
|
|
2021-07-05 11:07:14 +00:00
|
|
|
static int
|
|
|
|
nvme_ns_set_ana_state(const struct spdk_nvme_ana_group_descriptor *desc, void *cb_arg)
|
|
|
|
{
|
|
|
|
struct nvme_ns *nvme_ns = cb_arg;
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < desc->num_of_nsid; i++) {
|
|
|
|
if (desc->nsid[i] != spdk_nvme_ns_get_id(nvme_ns->ns)) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-04-07 00:44:38 +00:00
|
|
|
|
|
|
|
_nvme_ns_set_ana_state(nvme_ns, desc);
|
2021-07-05 11:07:14 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-10-24 12:53:22 +00:00
|
|
|
static void
|
|
|
|
merge_nsid_sn_strings(const char *sn, char *nsid, int8_t *out)
|
|
|
|
{
|
|
|
|
int i = 0, j = 0;
|
|
|
|
int sn_len = strlen(sn), nsid_len = strlen(nsid);
|
|
|
|
|
|
|
|
for (i = 0; i < nsid_len; i++) {
|
|
|
|
out[i] = nsid[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Since last few characters are more likely to be unique,
|
|
|
|
* even among the devices from the same manufacturer,
|
|
|
|
* we use serial number in reverse. We also skip the
|
|
|
|
* terminating character of serial number string. */
|
|
|
|
for (j = sn_len - 1; j >= 0; j--) {
|
|
|
|
if (i == SPDK_UUID_STRING_LEN - 1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* There may be a lot of spaces in serial number string
|
|
|
|
* and they will generate equally large number of the
|
|
|
|
* same character, so just skip them. */
|
|
|
|
if (sn[j] == ' ') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
out[i] = sn[j];
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Dictionary of characters for UUID generation. */
|
|
|
|
static char dict[17] = "0123456789abcdef";
|
|
|
|
|
|
|
|
static struct spdk_uuid
|
|
|
|
nvme_generate_uuid(const char *sn, uint32_t nsid)
|
|
|
|
{
|
|
|
|
struct spdk_uuid new_uuid;
|
|
|
|
char buf[SPDK_UUID_STRING_LEN] = {'\0'}, merged_str[SPDK_UUID_STRING_LEN] = {'\0'};
|
|
|
|
char nsid_str[NSID_STR_LEN] = {'\0'}, tmp;
|
|
|
|
uint64_t i = 0, j = 0, rem, dict_size = strlen(dict);
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
assert(strlen(sn) <= SPDK_NVME_CTRLR_SN_LEN);
|
|
|
|
|
|
|
|
snprintf(nsid_str, NSID_STR_LEN, "%" PRIu32, nsid);
|
|
|
|
|
|
|
|
merge_nsid_sn_strings(sn, nsid_str, merged_str);
|
|
|
|
|
|
|
|
while (i < SPDK_UUID_STRING_LEN) {
|
|
|
|
/* If 'j' is equal to indexes, where '-' should be placed,
|
|
|
|
* insert this character and continue the loop without
|
|
|
|
* increasing 'i'. */
|
|
|
|
if ((j == 8 || j == 13 || j == 18 || j == 23)) {
|
|
|
|
buf[j] = '-';
|
|
|
|
j++;
|
|
|
|
|
|
|
|
/* Break, if we ran out of characters in
|
|
|
|
* serial number and namespace ID string. */
|
|
|
|
if (j == strlen(merged_str)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Change character in shuffled string to lower case. */
|
|
|
|
tmp = tolower(merged_str[i]);
|
|
|
|
|
|
|
|
if (isxdigit(tmp)) {
|
|
|
|
/* If character can be represented by a hex
|
|
|
|
* value as is, copy it to the result buffer. */
|
|
|
|
buf[j] = tmp;
|
|
|
|
} else {
|
|
|
|
/* Otherwise get its code and divide it
|
|
|
|
* by the number of elements in dictionary.
|
|
|
|
* The remainder will be the index of dictionary
|
|
|
|
* character to replace tmp value with. */
|
|
|
|
rem = tmp % dict_size;
|
|
|
|
buf[j] = dict[rem];
|
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
j++;
|
|
|
|
|
|
|
|
/* Break, if we ran out of characters in
|
|
|
|
* serial number and namespace ID string. */
|
|
|
|
if (j == strlen(merged_str)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there are not enough values to fill UUID,
|
|
|
|
* the rest is taken from dictionary characters. */
|
|
|
|
i = 0;
|
|
|
|
while (j < SPDK_UUID_STRING_LEN - 1) {
|
|
|
|
if ((j == 8 || j == 13 || j == 18 || j == 23)) {
|
|
|
|
buf[j] = '-';
|
|
|
|
j++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
buf[j] = dict[i % dict_size];
|
|
|
|
i++;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = spdk_uuid_parse(&new_uuid, buf);
|
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Unexpected spdk_uuid_parse failure on %s.\n", buf);
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
return new_uuid;
|
|
|
|
}
|
|
|
|
|
2020-12-27 09:20:01 +00:00
|
|
|
static int
|
|
|
|
nvme_disk_create(struct spdk_bdev *disk, const char *base_name,
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns,
|
|
|
|
uint32_t prchk_flags, void *ctx)
|
2018-06-13 05:06:40 +00:00
|
|
|
{
|
2020-11-03 23:36:48 +00:00
|
|
|
const struct spdk_uuid *uuid;
|
2021-07-02 12:07:15 +00:00
|
|
|
const uint8_t *nguid;
|
2018-06-13 05:06:40 +00:00
|
|
|
const struct spdk_nvme_ctrlr_data *cdata;
|
2020-11-03 23:36:48 +00:00
|
|
|
const struct spdk_nvme_ns_data *nsdata;
|
2022-04-07 02:58:45 +00:00
|
|
|
const struct spdk_nvme_ctrlr_opts *opts;
|
2021-03-03 18:38:38 +00:00
|
|
|
enum spdk_nvme_csi csi;
|
2021-06-07 14:02:38 +00:00
|
|
|
uint32_t atomic_bs, phys_bs, bs;
|
2022-10-24 12:53:22 +00:00
|
|
|
char sn_tmp[SPDK_NVME_CTRLR_SN_LEN + 1] = {'\0'};
|
2018-06-13 05:06:40 +00:00
|
|
|
|
|
|
|
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
|
2021-03-03 18:38:38 +00:00
|
|
|
csi = spdk_nvme_ns_get_csi(ns);
|
2022-04-07 02:58:45 +00:00
|
|
|
opts = spdk_nvme_ctrlr_get_opts(ctrlr);
|
2021-03-03 18:38:38 +00:00
|
|
|
|
|
|
|
switch (csi) {
|
|
|
|
case SPDK_NVME_CSI_NVM:
|
|
|
|
disk->product_name = "NVMe disk";
|
|
|
|
break;
|
|
|
|
case SPDK_NVME_CSI_ZNS:
|
|
|
|
disk->product_name = "NVMe ZNS disk";
|
|
|
|
disk->zoned = true;
|
|
|
|
disk->zone_size = spdk_nvme_zns_ns_get_zone_size_sectors(ns);
|
|
|
|
disk->max_zone_append_size = spdk_nvme_zns_ctrlr_get_max_zone_append_size(ctrlr) /
|
|
|
|
spdk_nvme_ns_get_extended_sector_size(ns);
|
|
|
|
disk->max_open_zones = spdk_nvme_zns_ns_get_max_open_zones(ns);
|
|
|
|
disk->max_active_zones = spdk_nvme_zns_ns_get_max_active_zones(ns);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SPDK_ERRLOG("unsupported CSI: %u\n", csi);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
2018-06-13 05:06:40 +00:00
|
|
|
|
2020-12-27 09:20:01 +00:00
|
|
|
disk->name = spdk_sprintf_alloc("%sn%d", base_name, spdk_nvme_ns_get_id(ns));
|
|
|
|
if (!disk->name) {
|
|
|
|
return -ENOMEM;
|
2019-10-14 12:35:11 +00:00
|
|
|
}
|
2018-06-13 05:06:40 +00:00
|
|
|
|
2020-12-27 09:20:01 +00:00
|
|
|
disk->write_cache = 0;
|
2018-06-13 05:06:40 +00:00
|
|
|
if (cdata->vwc.present) {
|
|
|
|
/* Enable if the Volatile Write Cache exists */
|
2020-12-27 09:20:01 +00:00
|
|
|
disk->write_cache = 1;
|
2018-06-13 05:06:40 +00:00
|
|
|
}
|
2021-05-14 11:26:40 +00:00
|
|
|
if (cdata->oncs.write_zeroes) {
|
|
|
|
disk->max_write_zeroes = UINT16_MAX + 1;
|
|
|
|
}
|
2020-12-27 09:20:01 +00:00
|
|
|
disk->blocklen = spdk_nvme_ns_get_extended_sector_size(ns);
|
|
|
|
disk->blockcnt = spdk_nvme_ns_get_num_sectors(ns);
|
2022-04-07 02:58:45 +00:00
|
|
|
disk->max_segment_size = spdk_nvme_ctrlr_get_max_xfer_size(ctrlr);
|
|
|
|
/* NVMe driver will split one request into multiple requests
|
|
|
|
* based on MDTS and stripe boundary, the bdev layer will use
|
|
|
|
* max_segment_size and max_num_segments to split one big IO
|
|
|
|
* into multiple requests, then small request can't run out
|
|
|
|
* of NVMe internal requests data structure.
|
|
|
|
*/
|
|
|
|
if (opts && opts->io_queue_requests) {
|
|
|
|
disk->max_num_segments = opts->io_queue_requests / 2;
|
|
|
|
}
|
2020-12-27 09:20:01 +00:00
|
|
|
disk->optimal_io_boundary = spdk_nvme_ns_get_optimal_io_boundary(ns);
|
2018-06-13 05:06:40 +00:00
|
|
|
|
2021-07-02 12:07:15 +00:00
|
|
|
nguid = spdk_nvme_ns_get_nguid(ns);
|
|
|
|
if (!nguid) {
|
|
|
|
uuid = spdk_nvme_ns_get_uuid(ns);
|
|
|
|
if (uuid) {
|
|
|
|
disk->uuid = *uuid;
|
2022-10-24 12:53:22 +00:00
|
|
|
} else if (g_opts.generate_uuids) {
|
2022-11-22 10:28:10 +00:00
|
|
|
spdk_strcpy_pad(sn_tmp, cdata->sn, SPDK_NVME_CTRLR_SN_LEN, '\0');
|
2022-10-24 12:53:22 +00:00
|
|
|
disk->uuid = nvme_generate_uuid(sn_tmp, spdk_nvme_ns_get_id(ns));
|
2021-07-02 12:07:15 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
memcpy(&disk->uuid, nguid, sizeof(disk->uuid));
|
2018-06-13 05:06:40 +00:00
|
|
|
}
|
|
|
|
|
2019-12-13 09:56:17 +00:00
|
|
|
nsdata = spdk_nvme_ns_get_data(ns);
|
2021-06-07 14:02:38 +00:00
|
|
|
bs = spdk_nvme_ns_get_sector_size(ns);
|
|
|
|
atomic_bs = bs;
|
|
|
|
phys_bs = bs;
|
|
|
|
if (nsdata->nabo == 0) {
|
|
|
|
if (nsdata->nsfeat.ns_atomic_write_unit && nsdata->nawupf) {
|
|
|
|
atomic_bs = bs * (1 + nsdata->nawupf);
|
|
|
|
} else {
|
|
|
|
atomic_bs = bs * (1 + cdata->awupf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nsdata->nsfeat.optperf) {
|
|
|
|
phys_bs = bs * (1 + nsdata->npwg);
|
|
|
|
}
|
|
|
|
disk->phys_blocklen = spdk_min(phys_bs, atomic_bs);
|
2019-12-13 09:56:17 +00:00
|
|
|
|
2020-12-27 09:20:01 +00:00
|
|
|
disk->md_len = spdk_nvme_ns_get_md_size(ns);
|
|
|
|
if (disk->md_len != 0) {
|
|
|
|
disk->md_interleave = nsdata->flbas.extended;
|
|
|
|
disk->dif_type = (enum spdk_dif_type)spdk_nvme_ns_get_pi_type(ns);
|
|
|
|
if (disk->dif_type != SPDK_DIF_DISABLE) {
|
|
|
|
disk->dif_is_head_of_md = nsdata->dps.md_start;
|
|
|
|
disk->dif_check_flags = prchk_flags;
|
2019-02-05 06:00:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-19 07:00:45 +00:00
|
|
|
if (!(spdk_nvme_ctrlr_get_flags(ctrlr) &
|
|
|
|
SPDK_NVME_CTRLR_COMPARE_AND_WRITE_SUPPORTED)) {
|
2020-12-27 09:20:01 +00:00
|
|
|
disk->acwu = 0;
|
2019-12-13 09:56:17 +00:00
|
|
|
} else if (nsdata->nsfeat.ns_atomic_write_unit) {
|
2022-04-25 17:41:12 +00:00
|
|
|
disk->acwu = nsdata->nacwu + 1; /* 0-based */
|
2019-12-13 09:56:17 +00:00
|
|
|
} else {
|
2022-04-25 17:41:12 +00:00
|
|
|
disk->acwu = cdata->acwu + 1; /* 0-based */
|
2019-12-13 09:56:17 +00:00
|
|
|
}
|
|
|
|
|
2022-08-22 12:47:31 +00:00
|
|
|
if (cdata->oncs.copy) {
|
|
|
|
/* For now bdev interface allows only single segment copy */
|
|
|
|
disk->max_copy = nsdata->mssrl;
|
|
|
|
}
|
|
|
|
|
2020-12-27 09:20:01 +00:00
|
|
|
disk->ctxt = ctx;
|
|
|
|
disk->fn_table = &nvmelib_fn_table;
|
|
|
|
disk->module = &nvme_if;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-12-21 02:19:46 +00:00
|
|
|
static int
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_bdev_create(struct nvme_ctrlr *nvme_ctrlr, struct nvme_ns *nvme_ns)
|
2020-12-27 09:20:01 +00:00
|
|
|
{
|
|
|
|
struct nvme_bdev *bdev;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
bdev = calloc(1, sizeof(*bdev));
|
|
|
|
if (!bdev) {
|
|
|
|
SPDK_ERRLOG("bdev calloc() failed\n");
|
2020-12-21 02:19:46 +00:00
|
|
|
return -ENOMEM;
|
2020-12-27 09:20:01 +00:00
|
|
|
}
|
|
|
|
|
bdev/nvme: Count number of NVMe errors per type or code
Error counters for NVMe error was added in the generic bdev layer but
we want to know more detailed information for some use cases.
Add NVMe error counters per type and per code as module specific
statistics.
For status codes, the first idea was to have different named member
for each status code value. However, it was bad and too hard to test,
review, and maintain.
Instead, we have just two dimensional uint32_t arrays, and increment
one of these uint32_t values based on the status code type and status
code. Then, when dump the JSON, we use spdk_nvme_cpl_get_status_string()
and spdk_nvme_cpl_get_status_type_string().
This idea has one potential downside. This idea consumes 4 (types) *
256 (codes) * 4 (counter) = 4KB per NVMe bdev. We can make this smarter
if memory allocation is a problem. Hence we add an option
nvme_error_stat to enable this feature only if the user requests.
Additionally, the string returned by spdk_nvme_cpl_get_status_string()
or spdk_nvme_cpl_get_status_type_string() has uppercases, spaces, and
hyphens. These should not be included in JSON strings. Hence, convert
these via spdk_strcpy_replace().
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I07b07621e777bdf6556b95054abbbb65e5f9ea3e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15370
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
2023-01-05 23:26:33 +00:00
|
|
|
if (g_opts.nvme_error_stat) {
|
|
|
|
bdev->err_stat = calloc(1, sizeof(struct nvme_error_stat));
|
|
|
|
if (!bdev->err_stat) {
|
|
|
|
SPDK_ERRLOG("err_stat calloc() failed\n");
|
|
|
|
free(bdev);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
rc = pthread_mutex_init(&bdev->mutex, NULL);
|
|
|
|
if (rc != 0) {
|
bdev/nvme: Count number of NVMe errors per type or code
Error counters for NVMe error was added in the generic bdev layer but
we want to know more detailed information for some use cases.
Add NVMe error counters per type and per code as module specific
statistics.
For status codes, the first idea was to have different named member
for each status code value. However, it was bad and too hard to test,
review, and maintain.
Instead, we have just two dimensional uint32_t arrays, and increment
one of these uint32_t values based on the status code type and status
code. Then, when dump the JSON, we use spdk_nvme_cpl_get_status_string()
and spdk_nvme_cpl_get_status_type_string().
This idea has one potential downside. This idea consumes 4 (types) *
256 (codes) * 4 (counter) = 4KB per NVMe bdev. We can make this smarter
if memory allocation is a problem. Hence we add an option
nvme_error_stat to enable this feature only if the user requests.
Additionally, the string returned by spdk_nvme_cpl_get_status_string()
or spdk_nvme_cpl_get_status_type_string() has uppercases, spaces, and
hyphens. These should not be included in JSON strings. Hence, convert
these via spdk_strcpy_replace().
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I07b07621e777bdf6556b95054abbbb65e5f9ea3e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15370
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
2023-01-05 23:26:33 +00:00
|
|
|
free(bdev->err_stat);
|
2021-09-27 23:15:02 +00:00
|
|
|
free(bdev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
bdev->ref = 1;
|
2022-04-29 05:37:35 +00:00
|
|
|
bdev->mp_policy = BDEV_NVME_MP_POLICY_ACTIVE_PASSIVE;
|
2022-09-20 07:12:47 +00:00
|
|
|
bdev->mp_selector = BDEV_NVME_MP_SELECTOR_ROUND_ROBIN;
|
2022-10-31 07:13:30 +00:00
|
|
|
bdev->rr_min_io = UINT32_MAX;
|
2021-09-27 23:15:02 +00:00
|
|
|
TAILQ_INIT(&bdev->nvme_ns_list);
|
|
|
|
TAILQ_INSERT_TAIL(&bdev->nvme_ns_list, nvme_ns, tailq);
|
2021-07-06 19:42:41 +00:00
|
|
|
bdev->opal = nvme_ctrlr->opal_dev != NULL;
|
2020-12-27 09:20:01 +00:00
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
rc = nvme_disk_create(&bdev->disk, nvme_ctrlr->nbdev_ctrlr->name, nvme_ctrlr->ctrlr,
|
2022-03-04 04:51:53 +00:00
|
|
|
nvme_ns->ns, nvme_ctrlr->opts.prchk_flags, bdev);
|
2020-12-27 09:20:01 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Failed to create NVMe disk\n");
|
2021-10-15 13:24:49 +00:00
|
|
|
pthread_mutex_destroy(&bdev->mutex);
|
bdev/nvme: Count number of NVMe errors per type or code
Error counters for NVMe error was added in the generic bdev layer but
we want to know more detailed information for some use cases.
Add NVMe error counters per type and per code as module specific
statistics.
For status codes, the first idea was to have different named member
for each status code value. However, it was bad and too hard to test,
review, and maintain.
Instead, we have just two dimensional uint32_t arrays, and increment
one of these uint32_t values based on the status code type and status
code. Then, when dump the JSON, we use spdk_nvme_cpl_get_status_string()
and spdk_nvme_cpl_get_status_type_string().
This idea has one potential downside. This idea consumes 4 (types) *
256 (codes) * 4 (counter) = 4KB per NVMe bdev. We can make this smarter
if memory allocation is a problem. Hence we add an option
nvme_error_stat to enable this feature only if the user requests.
Additionally, the string returned by spdk_nvme_cpl_get_status_string()
or spdk_nvme_cpl_get_status_type_string() has uppercases, spaces, and
hyphens. These should not be included in JSON strings. Hence, convert
these via spdk_strcpy_replace().
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I07b07621e777bdf6556b95054abbbb65e5f9ea3e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15370
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
2023-01-05 23:26:33 +00:00
|
|
|
free(bdev->err_stat);
|
2019-10-14 12:35:11 +00:00
|
|
|
free(bdev);
|
2020-12-21 02:19:46 +00:00
|
|
|
return rc;
|
2020-11-03 23:36:48 +00:00
|
|
|
}
|
|
|
|
|
2021-07-06 17:35:01 +00:00
|
|
|
spdk_io_device_register(bdev,
|
|
|
|
bdev_nvme_create_bdev_channel_cb,
|
|
|
|
bdev_nvme_destroy_bdev_channel_cb,
|
|
|
|
sizeof(struct nvme_bdev_channel),
|
|
|
|
bdev->disk.name);
|
|
|
|
|
|
|
|
rc = spdk_bdev_register(&bdev->disk);
|
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("spdk_bdev_register() failed\n");
|
|
|
|
spdk_io_device_unregister(bdev, NULL);
|
2021-09-27 23:15:02 +00:00
|
|
|
pthread_mutex_destroy(&bdev->mutex);
|
2021-07-06 17:35:01 +00:00
|
|
|
free(bdev->disk.name);
|
bdev/nvme: Count number of NVMe errors per type or code
Error counters for NVMe error was added in the generic bdev layer but
we want to know more detailed information for some use cases.
Add NVMe error counters per type and per code as module specific
statistics.
For status codes, the first idea was to have different named member
for each status code value. However, it was bad and too hard to test,
review, and maintain.
Instead, we have just two dimensional uint32_t arrays, and increment
one of these uint32_t values based on the status code type and status
code. Then, when dump the JSON, we use spdk_nvme_cpl_get_status_string()
and spdk_nvme_cpl_get_status_type_string().
This idea has one potential downside. This idea consumes 4 (types) *
256 (codes) * 4 (counter) = 4KB per NVMe bdev. We can make this smarter
if memory allocation is a problem. Hence we add an option
nvme_error_stat to enable this feature only if the user requests.
Additionally, the string returned by spdk_nvme_cpl_get_status_string()
or spdk_nvme_cpl_get_status_type_string() has uppercases, spaces, and
hyphens. These should not be included in JSON strings. Hence, convert
these via spdk_strcpy_replace().
Signed-off-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I07b07621e777bdf6556b95054abbbb65e5f9ea3e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15370
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
2023-01-05 23:26:33 +00:00
|
|
|
free(bdev->err_stat);
|
2021-07-06 17:35:01 +00:00
|
|
|
free(bdev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-02-17 16:07:25 +00:00
|
|
|
nvme_ns->bdev = bdev;
|
2021-09-27 23:15:02 +00:00
|
|
|
bdev->nsid = nvme_ns->id;
|
|
|
|
|
|
|
|
bdev->nbdev_ctrlr = nvme_ctrlr->nbdev_ctrlr;
|
|
|
|
TAILQ_INSERT_TAIL(&nvme_ctrlr->nbdev_ctrlr->bdevs, bdev, tailq);
|
2021-01-04 07:50:15 +00:00
|
|
|
|
2020-12-21 02:19:46 +00:00
|
|
|
return 0;
|
2020-11-03 23:36:48 +00:00
|
|
|
}
|
|
|
|
|
2021-05-12 07:22:58 +00:00
|
|
|
static bool
|
|
|
|
bdev_nvme_compare_ns(struct spdk_nvme_ns *ns1, struct spdk_nvme_ns *ns2)
|
|
|
|
{
|
|
|
|
const struct spdk_nvme_ns_data *nsdata1, *nsdata2;
|
2021-05-16 21:47:51 +00:00
|
|
|
const struct spdk_uuid *uuid1, *uuid2;
|
2021-05-12 07:22:58 +00:00
|
|
|
|
|
|
|
nsdata1 = spdk_nvme_ns_get_data(ns1);
|
|
|
|
nsdata2 = spdk_nvme_ns_get_data(ns2);
|
2021-05-16 21:47:51 +00:00
|
|
|
uuid1 = spdk_nvme_ns_get_uuid(ns1);
|
|
|
|
uuid2 = spdk_nvme_ns_get_uuid(ns2);
|
2021-05-12 07:22:58 +00:00
|
|
|
|
2021-05-16 21:47:51 +00:00
|
|
|
return memcmp(nsdata1->nguid, nsdata2->nguid, sizeof(nsdata1->nguid)) == 0 &&
|
|
|
|
nsdata1->eui64 == nsdata2->eui64 &&
|
2022-01-27 14:29:46 +00:00
|
|
|
((uuid1 == NULL && uuid2 == NULL) ||
|
|
|
|
(uuid1 != NULL && uuid2 != NULL && spdk_uuid_compare(uuid1, uuid2) == 0)) &&
|
|
|
|
spdk_nvme_ns_get_csi(ns1) == spdk_nvme_ns_get_csi(ns2);
|
2021-05-12 07:22:58 +00:00
|
|
|
}
|
|
|
|
|
2017-03-01 01:23:53 +00:00
|
|
|
static bool
|
|
|
|
hotplug_probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
|
|
|
|
struct spdk_nvme_ctrlr_opts *opts)
|
|
|
|
{
|
2019-02-13 05:08:22 +00:00
|
|
|
struct nvme_probe_skip_entry *entry;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(entry, &g_skipped_nvme_ctrlrs, tailq) {
|
|
|
|
if (spdk_nvme_transport_id_compare(trid, &entry->trid) == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-03 03:48:49 +00:00
|
|
|
opts->arbitration_burst = (uint8_t)g_opts.arbitration_burst;
|
|
|
|
opts->low_priority_weight = (uint8_t)g_opts.low_priority_weight;
|
|
|
|
opts->medium_priority_weight = (uint8_t)g_opts.medium_priority_weight;
|
|
|
|
opts->high_priority_weight = (uint8_t)g_opts.high_priority_weight;
|
2021-07-07 15:27:55 +00:00
|
|
|
opts->disable_read_ana_log_page = true;
|
2019-09-03 03:48:49 +00:00
|
|
|
|
2020-09-04 11:27:29 +00:00
|
|
|
SPDK_DEBUGLOG(bdev_nvme, "Attaching to %s\n", trid->traddr);
|
2017-03-01 01:23:53 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-03-30 19:49:52 +00:00
|
|
|
static void
|
2020-05-10 07:46:07 +00:00
|
|
|
nvme_abort_cpl(void *ctx, const struct spdk_nvme_cpl *cpl)
|
2017-03-30 19:49:52 +00:00
|
|
|
{
|
2021-07-06 19:42:41 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr = ctx;
|
2017-03-30 19:49:52 +00:00
|
|
|
|
|
|
|
if (spdk_nvme_cpl_is_error(cpl)) {
|
2021-03-24 03:35:32 +00:00
|
|
|
SPDK_WARNLOG("Abort failed. Resetting controller. sc is %u, sct is %u.\n", cpl->status.sc,
|
|
|
|
cpl->status.sct);
|
2021-07-05 11:03:54 +00:00
|
|
|
bdev_nvme_reset(nvme_ctrlr);
|
2021-08-26 15:57:34 +00:00
|
|
|
} else if (cpl->cdw0 & 0x1) {
|
|
|
|
SPDK_WARNLOG("Specified command could not be aborted.\n");
|
|
|
|
bdev_nvme_reset(nvme_ctrlr);
|
2017-03-30 19:49:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-10 22:43:18 +00:00
|
|
|
static void
|
2017-02-28 17:51:25 +00:00
|
|
|
timeout_cb(void *cb_arg, struct spdk_nvme_ctrlr *ctrlr,
|
|
|
|
struct spdk_nvme_qpair *qpair, uint16_t cid)
|
2016-12-10 22:43:18 +00:00
|
|
|
{
|
2021-07-06 19:42:41 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr = cb_arg;
|
2018-08-07 00:17:42 +00:00
|
|
|
union spdk_nvme_csts_register csts;
|
2020-10-22 12:26:25 +00:00
|
|
|
int rc;
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
assert(nvme_ctrlr->ctrlr == ctrlr);
|
2016-12-10 22:43:18 +00:00
|
|
|
|
2017-02-23 16:24:58 +00:00
|
|
|
SPDK_WARNLOG("Warning: Detected a timeout. ctrlr=%p qpair=%p cid=%u\n", ctrlr, qpair, cid);
|
2016-12-10 22:43:18 +00:00
|
|
|
|
2020-12-09 23:11:08 +00:00
|
|
|
/* Only try to read CSTS if it's a PCIe controller or we have a timeout on an I/O
|
|
|
|
* queue. (Note: qpair == NULL when there's an admin cmd timeout.) Otherwise we
|
|
|
|
* would submit another fabrics cmd on the admin queue to read CSTS and check for its
|
|
|
|
* completion recursively.
|
|
|
|
*/
|
2021-09-21 19:17:12 +00:00
|
|
|
if (nvme_ctrlr->active_path_id->trid.trtype == SPDK_NVME_TRANSPORT_PCIE || qpair != NULL) {
|
2020-12-09 23:11:08 +00:00
|
|
|
csts = spdk_nvme_ctrlr_get_regs_csts(ctrlr);
|
|
|
|
if (csts.bits.cfs) {
|
|
|
|
SPDK_ERRLOG("Controller Fatal Status, reset required\n");
|
2021-07-05 11:03:54 +00:00
|
|
|
bdev_nvme_reset(nvme_ctrlr);
|
2020-12-09 23:11:08 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-08-07 00:17:42 +00:00
|
|
|
}
|
|
|
|
|
2018-07-09 21:04:33 +00:00
|
|
|
switch (g_opts.action_on_timeout) {
|
|
|
|
case SPDK_BDEV_NVME_TIMEOUT_ACTION_ABORT:
|
2017-03-30 19:49:52 +00:00
|
|
|
if (qpair) {
|
2021-11-24 02:09:59 +00:00
|
|
|
/* Don't send abort to ctrlr when ctrlr is not available. */
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
2021-11-24 02:09:59 +00:00
|
|
|
if (!nvme_ctrlr_is_available(nvme_ctrlr)) {
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2021-11-24 02:09:59 +00:00
|
|
|
SPDK_NOTICELOG("Quit abort. Ctrlr is not available.\n");
|
2021-03-24 03:35:32 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2021-03-24 03:35:32 +00:00
|
|
|
|
2017-03-30 19:49:52 +00:00
|
|
|
rc = spdk_nvme_ctrlr_cmd_abort(ctrlr, qpair, cid,
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_abort_cpl, nvme_ctrlr);
|
2017-03-30 19:49:52 +00:00
|
|
|
if (rc == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-24 03:35:32 +00:00
|
|
|
SPDK_ERRLOG("Unable to send abort. Resetting, rc is %d.\n", rc);
|
2017-03-30 19:49:52 +00:00
|
|
|
}
|
|
|
|
|
2017-06-02 06:32:45 +00:00
|
|
|
/* FALLTHROUGH */
|
2018-07-09 21:04:33 +00:00
|
|
|
case SPDK_BDEV_NVME_TIMEOUT_ACTION_RESET:
|
2021-07-05 11:03:54 +00:00
|
|
|
bdev_nvme_reset(nvme_ctrlr);
|
2017-03-30 19:49:52 +00:00
|
|
|
break;
|
2018-07-09 21:04:33 +00:00
|
|
|
case SPDK_BDEV_NVME_TIMEOUT_ACTION_NONE:
|
2020-09-04 11:27:29 +00:00
|
|
|
SPDK_DEBUGLOG(bdev_nvme, "No action for nvme controller timeout.\n");
|
2018-10-23 10:41:37 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SPDK_ERRLOG("An invalid timeout action value is found.\n");
|
2017-03-30 19:49:52 +00:00
|
|
|
break;
|
2016-12-10 22:43:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-16 06:43:32 +00:00
|
|
|
static struct nvme_ns *
|
|
|
|
nvme_ns_alloc(void)
|
|
|
|
{
|
|
|
|
return calloc(1, sizeof(struct nvme_ns));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvme_ns_free(struct nvme_ns *nvme_ns)
|
|
|
|
{
|
|
|
|
free(nvme_ns);
|
|
|
|
}
|
|
|
|
|
2021-09-02 12:24:57 +00:00
|
|
|
static void
|
2021-09-02 12:33:32 +00:00
|
|
|
nvme_ctrlr_populate_namespace_done(struct nvme_ns *nvme_ns, int rc)
|
2021-09-02 12:24:57 +00:00
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = nvme_ns->ctrlr;
|
2021-09-02 12:33:32 +00:00
|
|
|
struct nvme_async_probe_ctx *ctx = nvme_ns->probe_ctx;
|
2021-09-02 12:24:57 +00:00
|
|
|
|
|
|
|
if (rc == 0) {
|
2021-09-02 12:33:32 +00:00
|
|
|
nvme_ns->probe_ctx = NULL;
|
2021-09-02 12:24:57 +00:00
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
|
|
|
nvme_ctrlr->ref++;
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
} else {
|
2021-08-25 16:58:16 +00:00
|
|
|
RB_REMOVE(nvme_ns_tree, &nvme_ctrlr->namespaces, nvme_ns);
|
2023-01-16 06:43:32 +00:00
|
|
|
nvme_ns_free(nvme_ns);
|
2021-09-02 12:24:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx) {
|
|
|
|
ctx->populates_in_progress--;
|
|
|
|
if (ctx->populates_in_progress == 0) {
|
|
|
|
nvme_ctrlr_populate_namespaces_done(nvme_ctrlr, ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_add_io_path(struct spdk_io_channel_iter *i)
|
|
|
|
{
|
|
|
|
struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
|
|
|
|
struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(_ch);
|
|
|
|
struct nvme_ns *nvme_ns = spdk_io_channel_iter_get_ctx(i);
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = _bdev_nvme_add_io_path(nbdev_ch, nvme_ns);
|
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Failed to add I/O path to bdev_channel dynamically.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_for_each_channel_continue(i, rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_delete_io_path(struct spdk_io_channel_iter *i)
|
|
|
|
{
|
|
|
|
struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
|
|
|
|
struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(_ch);
|
|
|
|
struct nvme_ns *nvme_ns = spdk_io_channel_iter_get_ctx(i);
|
|
|
|
struct nvme_io_path *io_path;
|
|
|
|
|
|
|
|
io_path = _bdev_nvme_get_io_path(nbdev_ch, nvme_ns);
|
|
|
|
if (io_path != NULL) {
|
|
|
|
_bdev_nvme_delete_io_path(nbdev_ch, io_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_for_each_channel_continue(i, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_add_io_path_failed(struct spdk_io_channel_iter *i, int status)
|
|
|
|
{
|
|
|
|
struct nvme_ns *nvme_ns = spdk_io_channel_iter_get_ctx(i);
|
|
|
|
|
|
|
|
nvme_ctrlr_populate_namespace_done(nvme_ns, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_add_io_path_done(struct spdk_io_channel_iter *i, int status)
|
|
|
|
{
|
|
|
|
struct nvme_ns *nvme_ns = spdk_io_channel_iter_get_ctx(i);
|
|
|
|
struct nvme_bdev *bdev = spdk_io_channel_iter_get_io_device(i);
|
|
|
|
|
|
|
|
if (status == 0) {
|
|
|
|
nvme_ctrlr_populate_namespace_done(nvme_ns, 0);
|
|
|
|
} else {
|
|
|
|
/* Delete the added io_paths and fail populating the namespace. */
|
|
|
|
spdk_for_each_channel(bdev,
|
|
|
|
bdev_nvme_delete_io_path,
|
|
|
|
nvme_ns,
|
|
|
|
bdev_nvme_add_io_path_failed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
nvme_bdev_add_ns(struct nvme_bdev *bdev, struct nvme_ns *nvme_ns)
|
|
|
|
{
|
|
|
|
struct nvme_ns *tmp_ns;
|
2021-11-24 01:40:25 +00:00
|
|
|
const struct spdk_nvme_ns_data *nsdata;
|
|
|
|
|
|
|
|
nsdata = spdk_nvme_ns_get_data(nvme_ns->ns);
|
|
|
|
if (!nsdata->nmic.can_share) {
|
|
|
|
SPDK_ERRLOG("Namespace cannot be shared.\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2021-09-27 23:15:02 +00:00
|
|
|
|
|
|
|
pthread_mutex_lock(&bdev->mutex);
|
|
|
|
|
|
|
|
tmp_ns = TAILQ_FIRST(&bdev->nvme_ns_list);
|
|
|
|
assert(tmp_ns != NULL);
|
|
|
|
|
|
|
|
if (!bdev_nvme_compare_ns(nvme_ns->ns, tmp_ns->ns)) {
|
|
|
|
pthread_mutex_unlock(&bdev->mutex);
|
|
|
|
SPDK_ERRLOG("Namespaces are not identical.\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bdev->ref++;
|
|
|
|
TAILQ_INSERT_TAIL(&bdev->nvme_ns_list, nvme_ns, tailq);
|
|
|
|
nvme_ns->bdev = bdev;
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&bdev->mutex);
|
|
|
|
|
|
|
|
/* Add nvme_io_path to nvme_bdev_channels dynamically. */
|
|
|
|
spdk_for_each_channel(bdev,
|
|
|
|
bdev_nvme_add_io_path,
|
|
|
|
nvme_ns,
|
|
|
|
bdev_nvme_add_io_path_done);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-21 01:10:30 +00:00
|
|
|
static void
|
2021-09-02 12:33:32 +00:00
|
|
|
nvme_ctrlr_populate_namespace(struct nvme_ctrlr *nvme_ctrlr, struct nvme_ns *nvme_ns)
|
2018-06-21 01:10:30 +00:00
|
|
|
{
|
2021-08-27 20:31:04 +00:00
|
|
|
struct spdk_nvme_ns *ns;
|
2021-09-27 23:15:02 +00:00
|
|
|
struct nvme_bdev *bdev;
|
2021-08-27 20:31:04 +00:00
|
|
|
int rc = 0;
|
2019-10-17 11:33:25 +00:00
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
ns = spdk_nvme_ctrlr_get_ns(nvme_ctrlr->ctrlr, nvme_ns->id);
|
2021-08-27 20:31:04 +00:00
|
|
|
if (!ns) {
|
|
|
|
SPDK_DEBUGLOG(bdev_nvme, "Invalid NS %d\n", nvme_ns->id);
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto done;
|
2019-10-17 11:33:25 +00:00
|
|
|
}
|
|
|
|
|
2021-08-27 20:31:04 +00:00
|
|
|
nvme_ns->ns = ns;
|
|
|
|
nvme_ns->ana_state = SPDK_NVME_ANA_OPTIMIZED_STATE;
|
2018-06-21 01:10:30 +00:00
|
|
|
|
2021-08-27 20:31:04 +00:00
|
|
|
if (nvme_ctrlr->ana_log_page != NULL) {
|
|
|
|
bdev_nvme_parse_ana_log_page(nvme_ctrlr, nvme_ns_set_ana_state, nvme_ns);
|
|
|
|
}
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
bdev = nvme_bdev_ctrlr_get_bdev(nvme_ctrlr->nbdev_ctrlr, nvme_ns->id);
|
|
|
|
if (bdev == NULL) {
|
|
|
|
rc = nvme_bdev_create(nvme_ctrlr, nvme_ns);
|
|
|
|
} else {
|
|
|
|
rc = nvme_bdev_add_ns(bdev, nvme_ns);
|
|
|
|
if (rc == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-08-27 20:31:04 +00:00
|
|
|
done:
|
2021-09-02 12:33:32 +00:00
|
|
|
nvme_ctrlr_populate_namespace_done(nvme_ns, rc);
|
2019-11-25 20:16:24 +00:00
|
|
|
}
|
|
|
|
|
2020-10-13 07:48:13 +00:00
|
|
|
static void
|
2021-09-02 12:24:57 +00:00
|
|
|
nvme_ctrlr_depopulate_namespace_done(struct nvme_ns *nvme_ns)
|
2019-11-25 20:16:24 +00:00
|
|
|
{
|
2021-09-02 12:24:57 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr = nvme_ns->ctrlr;
|
2021-08-27 20:31:04 +00:00
|
|
|
|
2021-09-02 12:24:57 +00:00
|
|
|
assert(nvme_ctrlr != NULL);
|
2021-08-27 20:31:04 +00:00
|
|
|
|
2021-08-27 20:36:19 +00:00
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
2021-03-01 22:39:39 +00:00
|
|
|
|
2021-08-25 16:58:16 +00:00
|
|
|
RB_REMOVE(nvme_ns_tree, &nvme_ctrlr->namespaces, nvme_ns);
|
2021-03-01 22:39:39 +00:00
|
|
|
|
2021-08-27 20:36:19 +00:00
|
|
|
if (nvme_ns->bdev != NULL) {
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2021-08-27 20:36:19 +00:00
|
|
|
return;
|
2019-11-26 18:39:01 +00:00
|
|
|
}
|
2021-08-25 22:03:09 +00:00
|
|
|
|
2023-01-16 06:43:32 +00:00
|
|
|
nvme_ns_free(nvme_ns);
|
2021-08-27 20:36:19 +00:00
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2019-11-26 18:11:29 +00:00
|
|
|
|
2021-08-27 20:36:19 +00:00
|
|
|
nvme_ctrlr_release(nvme_ctrlr);
|
2019-11-26 18:39:01 +00:00
|
|
|
}
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_delete_io_path_done(struct spdk_io_channel_iter *i, int status)
|
|
|
|
{
|
|
|
|
struct nvme_ns *nvme_ns = spdk_io_channel_iter_get_ctx(i);
|
|
|
|
|
|
|
|
nvme_ctrlr_depopulate_namespace_done(nvme_ns);
|
|
|
|
}
|
|
|
|
|
2021-09-02 12:24:57 +00:00
|
|
|
static void
|
|
|
|
nvme_ctrlr_depopulate_namespace(struct nvme_ctrlr *nvme_ctrlr, struct nvme_ns *nvme_ns)
|
|
|
|
{
|
|
|
|
struct nvme_bdev *bdev;
|
|
|
|
|
2022-04-07 08:29:05 +00:00
|
|
|
spdk_poller_unregister(&nvme_ns->anatt_timer);
|
|
|
|
|
2021-09-02 12:24:57 +00:00
|
|
|
bdev = nvme_ns->bdev;
|
|
|
|
if (bdev != NULL) {
|
2021-09-27 23:15:02 +00:00
|
|
|
pthread_mutex_lock(&bdev->mutex);
|
|
|
|
|
|
|
|
assert(bdev->ref > 0);
|
|
|
|
bdev->ref--;
|
|
|
|
if (bdev->ref == 0) {
|
|
|
|
pthread_mutex_unlock(&bdev->mutex);
|
|
|
|
|
|
|
|
spdk_bdev_unregister(&bdev->disk, NULL, NULL);
|
|
|
|
} else {
|
|
|
|
/* spdk_bdev_unregister() is not called until the last nvme_ns is
|
|
|
|
* depopulated. Hence we need to remove nvme_ns from bdev->nvme_ns_list
|
|
|
|
* and clear nvme_ns->bdev here.
|
|
|
|
*/
|
|
|
|
TAILQ_REMOVE(&bdev->nvme_ns_list, nvme_ns, tailq);
|
|
|
|
nvme_ns->bdev = NULL;
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&bdev->mutex);
|
|
|
|
|
|
|
|
/* Delete nvme_io_paths from nvme_bdev_channels dynamically. After that,
|
|
|
|
* we call depopulate_namespace_done() to avoid use-after-free.
|
|
|
|
*/
|
|
|
|
spdk_for_each_channel(bdev,
|
|
|
|
bdev_nvme_delete_io_path,
|
|
|
|
nvme_ns,
|
|
|
|
bdev_nvme_delete_io_path_done);
|
|
|
|
return;
|
|
|
|
}
|
2021-09-02 12:24:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nvme_ctrlr_depopulate_namespace_done(nvme_ns);
|
|
|
|
}
|
|
|
|
|
2018-06-21 01:10:30 +00:00
|
|
|
static void
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr_populate_namespaces(struct nvme_ctrlr *nvme_ctrlr,
|
2019-11-26 16:55:40 +00:00
|
|
|
struct nvme_async_probe_ctx *ctx)
|
2018-06-21 01:10:30 +00:00
|
|
|
{
|
2021-07-06 19:42:41 +00:00
|
|
|
struct spdk_nvme_ctrlr *ctrlr = nvme_ctrlr->ctrlr;
|
2021-08-26 21:19:46 +00:00
|
|
|
struct nvme_ns *nvme_ns, *next;
|
2020-11-25 14:52:16 +00:00
|
|
|
struct spdk_nvme_ns *ns;
|
2020-02-13 07:34:09 +00:00
|
|
|
struct nvme_bdev *bdev;
|
2021-08-26 21:19:46 +00:00
|
|
|
uint32_t nsid;
|
2020-02-13 07:34:09 +00:00
|
|
|
int rc;
|
|
|
|
uint64_t num_sectors;
|
2019-11-26 18:11:29 +00:00
|
|
|
|
|
|
|
if (ctx) {
|
|
|
|
/* Initialize this count to 1 to handle the populate functions
|
|
|
|
* calling nvme_ctrlr_populate_namespace_done() immediately.
|
|
|
|
*/
|
|
|
|
ctx->populates_in_progress = 1;
|
|
|
|
}
|
2018-06-21 01:10:30 +00:00
|
|
|
|
2021-08-26 21:19:46 +00:00
|
|
|
/* First loop over our existing namespaces and see if they have been
|
|
|
|
* removed. */
|
|
|
|
nvme_ns = nvme_ctrlr_get_first_active_ns(nvme_ctrlr);
|
|
|
|
while (nvme_ns != NULL) {
|
|
|
|
next = nvme_ctrlr_get_next_active_ns(nvme_ctrlr, nvme_ns);
|
2020-02-13 07:34:09 +00:00
|
|
|
|
2021-08-26 21:19:46 +00:00
|
|
|
if (spdk_nvme_ctrlr_is_active_ns(ctrlr, nvme_ns->id)) {
|
2020-02-13 07:34:09 +00:00
|
|
|
/* NS is still there but attributes may have changed */
|
2021-08-26 21:19:46 +00:00
|
|
|
ns = spdk_nvme_ctrlr_get_ns(ctrlr, nvme_ns->id);
|
2020-11-25 14:52:16 +00:00
|
|
|
num_sectors = spdk_nvme_ns_get_num_sectors(ns);
|
2021-03-26 14:29:54 +00:00
|
|
|
bdev = nvme_ns->bdev;
|
2021-01-06 16:21:06 +00:00
|
|
|
assert(bdev != NULL);
|
2020-02-13 07:34:09 +00:00
|
|
|
if (bdev->disk.blockcnt != num_sectors) {
|
2020-11-17 16:29:21 +00:00
|
|
|
SPDK_NOTICELOG("NSID %u is resized: bdev name %s, old size %" PRIu64 ", new size %" PRIu64 "\n",
|
2021-08-26 21:19:46 +00:00
|
|
|
nvme_ns->id,
|
2020-02-13 07:34:09 +00:00
|
|
|
bdev->disk.name,
|
|
|
|
bdev->disk.blockcnt,
|
|
|
|
num_sectors);
|
|
|
|
rc = spdk_bdev_notify_blockcnt_change(&bdev->disk, num_sectors);
|
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Could not change num blocks for nvme bdev: name %s, errno: %d.\n",
|
|
|
|
bdev->disk.name, rc);
|
|
|
|
}
|
|
|
|
}
|
2021-08-26 21:19:46 +00:00
|
|
|
} else {
|
|
|
|
/* Namespace was removed */
|
|
|
|
nvme_ctrlr_depopulate_namespace(nvme_ctrlr, nvme_ns);
|
2020-02-13 07:34:09 +00:00
|
|
|
}
|
|
|
|
|
2021-08-26 21:19:46 +00:00
|
|
|
nvme_ns = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loop through all of the namespaces at the nvme level and see if any of them are new */
|
|
|
|
nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
|
|
|
|
while (nsid != 0) {
|
|
|
|
nvme_ns = nvme_ctrlr_get_ns(nvme_ctrlr, nsid);
|
|
|
|
|
|
|
|
if (nvme_ns == NULL) {
|
|
|
|
/* Found a new one */
|
2023-01-16 06:43:32 +00:00
|
|
|
nvme_ns = nvme_ns_alloc();
|
2021-08-25 22:03:09 +00:00
|
|
|
if (nvme_ns == NULL) {
|
|
|
|
SPDK_ERRLOG("Failed to allocate namespace\n");
|
|
|
|
/* This just fails to attach the namespace. It may work on a future attempt. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-11-25 14:52:16 +00:00
|
|
|
nvme_ns->id = nsid;
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ns->ctrlr = nvme_ctrlr;
|
2019-10-14 12:35:11 +00:00
|
|
|
|
2021-02-17 16:07:25 +00:00
|
|
|
nvme_ns->bdev = NULL;
|
2019-10-17 11:33:25 +00:00
|
|
|
|
2019-11-26 18:11:29 +00:00
|
|
|
if (ctx) {
|
|
|
|
ctx->populates_in_progress++;
|
|
|
|
}
|
2021-09-02 12:33:32 +00:00
|
|
|
nvme_ns->probe_ctx = ctx;
|
|
|
|
|
2021-08-25 16:58:16 +00:00
|
|
|
RB_INSERT(nvme_ns_tree, &nvme_ctrlr->namespaces, nvme_ns);
|
|
|
|
|
2021-09-02 12:33:32 +00:00
|
|
|
nvme_ctrlr_populate_namespace(nvme_ctrlr, nvme_ns);
|
2018-06-21 01:10:30 +00:00
|
|
|
}
|
|
|
|
|
2021-08-26 21:19:46 +00:00
|
|
|
nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, nsid);
|
2018-06-21 01:10:30 +00:00
|
|
|
}
|
|
|
|
|
2019-11-26 18:11:29 +00:00
|
|
|
if (ctx) {
|
|
|
|
/* Decrement this count now that the loop is over to account
|
|
|
|
* for the one we started with. If the count is then 0, we
|
|
|
|
* know any populate_namespace functions completed immediately,
|
|
|
|
* so we'll kick the callback here.
|
|
|
|
*/
|
|
|
|
ctx->populates_in_progress--;
|
|
|
|
if (ctx->populates_in_progress == 0) {
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr_populate_namespaces_done(nvme_ctrlr, ctx);
|
2019-11-26 18:11:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-21 01:10:30 +00:00
|
|
|
}
|
|
|
|
|
2020-10-13 07:48:13 +00:00
|
|
|
static void
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr_depopulate_namespaces(struct nvme_ctrlr *nvme_ctrlr)
|
2020-10-13 07:48:13 +00:00
|
|
|
{
|
2021-08-25 16:58:16 +00:00
|
|
|
struct nvme_ns *nvme_ns, *tmp;
|
2020-10-13 07:48:13 +00:00
|
|
|
|
2021-08-25 16:58:16 +00:00
|
|
|
RB_FOREACH_SAFE(nvme_ns, nvme_ns_tree, &nvme_ctrlr->namespaces, tmp) {
|
|
|
|
nvme_ctrlr_depopulate_namespace(nvme_ctrlr, nvme_ns);
|
2020-10-13 07:48:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-13 04:57:25 +00:00
|
|
|
static uint32_t
|
|
|
|
nvme_ctrlr_get_ana_log_page_size(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr = nvme_ctrlr->ctrlr;
|
|
|
|
const struct spdk_nvme_ctrlr_data *cdata;
|
|
|
|
uint32_t nsid, ns_count = 0;
|
|
|
|
|
|
|
|
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
|
|
|
|
|
|
|
|
for (nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
|
|
|
|
nsid != 0; nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, nsid)) {
|
|
|
|
ns_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sizeof(struct spdk_nvme_ana_page) + cdata->nanagrpid *
|
|
|
|
sizeof(struct spdk_nvme_ana_group_descriptor) + ns_count *
|
|
|
|
sizeof(uint32_t);
|
|
|
|
}
|
|
|
|
|
2021-07-02 07:03:59 +00:00
|
|
|
static int
|
|
|
|
nvme_ctrlr_set_ana_states(const struct spdk_nvme_ana_group_descriptor *desc,
|
|
|
|
void *cb_arg)
|
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = cb_arg;
|
|
|
|
struct nvme_ns *nvme_ns;
|
|
|
|
uint32_t i, nsid;
|
|
|
|
|
|
|
|
for (i = 0; i < desc->num_of_nsid; i++) {
|
|
|
|
nsid = desc->nsid[i];
|
2021-08-25 16:58:16 +00:00
|
|
|
if (nsid == 0) {
|
2021-07-02 07:03:59 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-08-25 23:18:18 +00:00
|
|
|
nvme_ns = nvme_ctrlr_get_ns(nvme_ctrlr, nsid);
|
2021-07-02 07:03:59 +00:00
|
|
|
|
2021-08-25 22:03:09 +00:00
|
|
|
assert(nvme_ns != NULL);
|
|
|
|
if (nvme_ns == NULL) {
|
|
|
|
/* Target told us that an inactive namespace had an ANA change */
|
2021-07-02 07:03:59 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-04-07 00:44:38 +00:00
|
|
|
_nvme_ns_set_ana_state(nvme_ns, desc);
|
2021-07-02 07:03:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-02-03 22:14:10 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_disable_read_ana_log_page(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
struct nvme_ns *nvme_ns;
|
|
|
|
|
2022-02-23 06:04:42 +00:00
|
|
|
spdk_free(nvme_ctrlr->ana_log_page);
|
2022-02-03 22:14:10 +00:00
|
|
|
nvme_ctrlr->ana_log_page = NULL;
|
|
|
|
|
|
|
|
for (nvme_ns = nvme_ctrlr_get_first_active_ns(nvme_ctrlr);
|
|
|
|
nvme_ns != NULL;
|
|
|
|
nvme_ns = nvme_ctrlr_get_next_active_ns(nvme_ctrlr, nvme_ns)) {
|
|
|
|
nvme_ns->ana_state_updating = false;
|
|
|
|
nvme_ns->ana_state = SPDK_NVME_ANA_OPTIMIZED_STATE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-15 10:28:09 +00:00
|
|
|
static void
|
|
|
|
nvme_ctrlr_read_ana_log_page_done(void *ctx, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = ctx;
|
|
|
|
|
|
|
|
if (cpl != NULL && spdk_nvme_cpl_is_success(cpl)) {
|
|
|
|
bdev_nvme_parse_ana_log_page(nvme_ctrlr, nvme_ctrlr_set_ana_states,
|
|
|
|
nvme_ctrlr);
|
2022-02-03 22:14:10 +00:00
|
|
|
} else {
|
|
|
|
bdev_nvme_disable_read_ana_log_page(nvme_ctrlr);
|
2021-10-15 10:28:09 +00:00
|
|
|
}
|
|
|
|
|
2022-08-09 01:46:48 +00:00
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
|
|
|
|
|
|
|
assert(nvme_ctrlr->ana_log_page_updating == true);
|
|
|
|
nvme_ctrlr->ana_log_page_updating = false;
|
|
|
|
|
|
|
|
if (nvme_ctrlr_can_be_unregistered(nvme_ctrlr)) {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
|
|
|
|
nvme_ctrlr_unregister(nvme_ctrlr);
|
|
|
|
} else {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
|
|
|
|
bdev_nvme_clear_io_path_caches(nvme_ctrlr);
|
|
|
|
}
|
2021-10-15 10:28:09 +00:00
|
|
|
}
|
|
|
|
|
2022-02-03 22:14:10 +00:00
|
|
|
static int
|
2021-07-02 07:03:59 +00:00
|
|
|
nvme_ctrlr_read_ana_log_page(struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
2022-07-13 04:57:25 +00:00
|
|
|
uint32_t ana_log_page_size;
|
2021-07-02 07:03:59 +00:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (nvme_ctrlr->ana_log_page == NULL) {
|
2022-02-03 22:14:10 +00:00
|
|
|
return -EINVAL;
|
2021-07-02 07:03:59 +00:00
|
|
|
}
|
|
|
|
|
2022-07-13 04:57:25 +00:00
|
|
|
ana_log_page_size = nvme_ctrlr_get_ana_log_page_size(nvme_ctrlr);
|
|
|
|
|
|
|
|
if (ana_log_page_size > nvme_ctrlr->max_ana_log_page_size) {
|
|
|
|
SPDK_ERRLOG("ANA log page size %" PRIu32 " is larger than allowed %" PRIu32 "\n",
|
|
|
|
ana_log_page_size, nvme_ctrlr->max_ana_log_page_size);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-09-16 05:24:37 +00:00
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
2021-11-24 02:09:59 +00:00
|
|
|
if (!nvme_ctrlr_is_available(nvme_ctrlr) ||
|
2021-09-16 05:24:37 +00:00
|
|
|
nvme_ctrlr->ana_log_page_updating) {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2022-02-03 22:14:10 +00:00
|
|
|
return -EBUSY;
|
2021-07-02 07:03:59 +00:00
|
|
|
}
|
|
|
|
|
2021-09-16 05:24:37 +00:00
|
|
|
nvme_ctrlr->ana_log_page_updating = true;
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
|
2021-07-02 07:03:59 +00:00
|
|
|
rc = spdk_nvme_ctrlr_cmd_get_log_page(nvme_ctrlr->ctrlr,
|
|
|
|
SPDK_NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS,
|
|
|
|
SPDK_NVME_GLOBAL_NS_TAG,
|
|
|
|
nvme_ctrlr->ana_log_page,
|
2022-07-13 04:57:25 +00:00
|
|
|
ana_log_page_size, 0,
|
2021-07-02 07:03:59 +00:00
|
|
|
nvme_ctrlr_read_ana_log_page_done,
|
|
|
|
nvme_ctrlr);
|
|
|
|
if (rc != 0) {
|
2021-09-16 05:24:37 +00:00
|
|
|
nvme_ctrlr_read_ana_log_page_done(nvme_ctrlr, NULL);
|
2021-07-02 07:03:59 +00:00
|
|
|
}
|
2022-02-03 22:14:10 +00:00
|
|
|
|
|
|
|
return rc;
|
2021-07-02 07:03:59 +00:00
|
|
|
}
|
|
|
|
|
2022-04-13 21:23:40 +00:00
|
|
|
static void
|
|
|
|
dummy_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
struct bdev_nvme_set_preferred_path_ctx {
|
|
|
|
struct spdk_bdev_desc *desc;
|
|
|
|
struct nvme_ns *nvme_ns;
|
|
|
|
bdev_nvme_set_preferred_path_cb cb_fn;
|
|
|
|
void *cb_arg;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_set_preferred_path_done(struct spdk_io_channel_iter *i, int status)
|
|
|
|
{
|
|
|
|
struct bdev_nvme_set_preferred_path_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
|
|
|
|
|
|
|
|
assert(ctx != NULL);
|
|
|
|
assert(ctx->desc != NULL);
|
|
|
|
assert(ctx->cb_fn != NULL);
|
|
|
|
|
|
|
|
spdk_bdev_close(ctx->desc);
|
|
|
|
|
|
|
|
ctx->cb_fn(ctx->cb_arg, status);
|
|
|
|
|
|
|
|
free(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_bdev_nvme_set_preferred_path(struct spdk_io_channel_iter *i)
|
|
|
|
{
|
|
|
|
struct bdev_nvme_set_preferred_path_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
|
|
|
|
struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
|
|
|
|
struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(_ch);
|
|
|
|
struct nvme_io_path *io_path, *prev;
|
|
|
|
|
|
|
|
prev = NULL;
|
|
|
|
STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
|
|
|
|
if (io_path->nvme_ns == ctx->nvme_ns) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prev = io_path;
|
|
|
|
}
|
|
|
|
|
2022-05-02 03:07:02 +00:00
|
|
|
if (io_path != NULL) {
|
|
|
|
if (prev != NULL) {
|
|
|
|
STAILQ_REMOVE_AFTER(&nbdev_ch->io_path_list, prev, stailq);
|
|
|
|
STAILQ_INSERT_HEAD(&nbdev_ch->io_path_list, io_path, stailq);
|
|
|
|
}
|
2022-04-13 21:23:40 +00:00
|
|
|
|
|
|
|
/* We can set io_path to nbdev_ch->current_io_path directly here.
|
|
|
|
* However, it needs to be conditional. To simplify the code,
|
|
|
|
* just clear nbdev_ch->current_io_path and let find_io_path()
|
|
|
|
* fill it.
|
2022-05-02 03:07:02 +00:00
|
|
|
*
|
|
|
|
* Automatic failback may be disabled. Hence even if the io_path is
|
|
|
|
* already at the head, clear nbdev_ch->current_io_path.
|
2022-04-13 21:23:40 +00:00
|
|
|
*/
|
2022-11-29 08:44:19 +00:00
|
|
|
bdev_nvme_clear_current_io_path(nbdev_ch);
|
2022-04-13 21:23:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
spdk_for_each_channel_continue(i, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct nvme_ns *
|
|
|
|
bdev_nvme_set_preferred_ns(struct nvme_bdev *nbdev, uint16_t cntlid)
|
|
|
|
{
|
|
|
|
struct nvme_ns *nvme_ns, *prev;
|
|
|
|
const struct spdk_nvme_ctrlr_data *cdata;
|
|
|
|
|
|
|
|
prev = NULL;
|
|
|
|
TAILQ_FOREACH(nvme_ns, &nbdev->nvme_ns_list, tailq) {
|
|
|
|
cdata = spdk_nvme_ctrlr_get_data(nvme_ns->ctrlr->ctrlr);
|
|
|
|
|
|
|
|
if (cdata->cntlid == cntlid) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prev = nvme_ns;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nvme_ns != NULL && prev != NULL) {
|
|
|
|
TAILQ_REMOVE(&nbdev->nvme_ns_list, nvme_ns, tailq);
|
|
|
|
TAILQ_INSERT_HEAD(&nbdev->nvme_ns_list, nvme_ns, tailq);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nvme_ns;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function supports only multipath mode. There is only a single I/O path
|
|
|
|
* for each NVMe-oF controller. Hence, just move the matched I/O path to the
|
|
|
|
* head of the I/O path list for each NVMe bdev channel.
|
|
|
|
*
|
|
|
|
* NVMe bdev channel may be acquired after completing this function. move the
|
|
|
|
* matched namespace to the head of the namespace list for the NVMe bdev too.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
bdev_nvme_set_preferred_path(const char *name, uint16_t cntlid,
|
|
|
|
bdev_nvme_set_preferred_path_cb cb_fn, void *cb_arg)
|
|
|
|
{
|
|
|
|
struct bdev_nvme_set_preferred_path_ctx *ctx;
|
|
|
|
struct spdk_bdev *bdev;
|
|
|
|
struct nvme_bdev *nbdev;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
assert(cb_fn != NULL);
|
|
|
|
|
|
|
|
ctx = calloc(1, sizeof(*ctx));
|
|
|
|
if (ctx == NULL) {
|
|
|
|
SPDK_ERRLOG("Failed to alloc context.\n");
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto err_alloc;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->cb_fn = cb_fn;
|
|
|
|
ctx->cb_arg = cb_arg;
|
|
|
|
|
|
|
|
rc = spdk_bdev_open_ext(name, false, dummy_bdev_event_cb, NULL, &ctx->desc);
|
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Failed to open bdev %s.\n", name);
|
|
|
|
goto err_open;
|
|
|
|
}
|
|
|
|
|
|
|
|
bdev = spdk_bdev_desc_get_bdev(ctx->desc);
|
|
|
|
|
|
|
|
if (bdev->module != &nvme_if) {
|
|
|
|
SPDK_ERRLOG("bdev %s is not registered in this module.\n", name);
|
|
|
|
rc = -ENODEV;
|
|
|
|
goto err_bdev;
|
|
|
|
}
|
|
|
|
|
|
|
|
nbdev = SPDK_CONTAINEROF(bdev, struct nvme_bdev, disk);
|
|
|
|
|
|
|
|
pthread_mutex_lock(&nbdev->mutex);
|
|
|
|
|
|
|
|
ctx->nvme_ns = bdev_nvme_set_preferred_ns(nbdev, cntlid);
|
|
|
|
if (ctx->nvme_ns == NULL) {
|
|
|
|
pthread_mutex_unlock(&nbdev->mutex);
|
|
|
|
|
|
|
|
SPDK_ERRLOG("bdev %s does not have namespace to controller %u.\n", name, cntlid);
|
|
|
|
rc = -ENODEV;
|
|
|
|
goto err_bdev;
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&nbdev->mutex);
|
|
|
|
|
|
|
|
spdk_for_each_channel(nbdev,
|
|
|
|
_bdev_nvme_set_preferred_path,
|
|
|
|
ctx,
|
|
|
|
bdev_nvme_set_preferred_path_done);
|
|
|
|
return;
|
|
|
|
|
|
|
|
err_bdev:
|
|
|
|
spdk_bdev_close(ctx->desc);
|
|
|
|
err_open:
|
|
|
|
free(ctx);
|
|
|
|
err_alloc:
|
|
|
|
cb_fn(cb_arg, rc);
|
|
|
|
}
|
|
|
|
|
2022-04-29 05:37:35 +00:00
|
|
|
struct bdev_nvme_set_multipath_policy_ctx {
|
|
|
|
struct spdk_bdev_desc *desc;
|
|
|
|
bdev_nvme_set_multipath_policy_cb cb_fn;
|
|
|
|
void *cb_arg;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_set_multipath_policy_done(struct spdk_io_channel_iter *i, int status)
|
|
|
|
{
|
|
|
|
struct bdev_nvme_set_multipath_policy_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
|
|
|
|
|
|
|
|
assert(ctx != NULL);
|
|
|
|
assert(ctx->desc != NULL);
|
|
|
|
assert(ctx->cb_fn != NULL);
|
|
|
|
|
|
|
|
spdk_bdev_close(ctx->desc);
|
|
|
|
|
|
|
|
ctx->cb_fn(ctx->cb_arg, status);
|
|
|
|
|
|
|
|
free(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_bdev_nvme_set_multipath_policy(struct spdk_io_channel_iter *i)
|
|
|
|
{
|
|
|
|
struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
|
|
|
|
struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(_ch);
|
|
|
|
struct nvme_bdev *nbdev = spdk_io_channel_get_io_device(_ch);
|
|
|
|
|
|
|
|
nbdev_ch->mp_policy = nbdev->mp_policy;
|
2022-09-20 07:12:47 +00:00
|
|
|
nbdev_ch->mp_selector = nbdev->mp_selector;
|
2022-10-31 07:13:30 +00:00
|
|
|
nbdev_ch->rr_min_io = nbdev->rr_min_io;
|
2022-11-29 08:44:19 +00:00
|
|
|
bdev_nvme_clear_current_io_path(nbdev_ch);
|
2022-04-29 05:37:35 +00:00
|
|
|
|
|
|
|
spdk_for_each_channel_continue(i, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bdev_nvme_set_multipath_policy(const char *name, enum bdev_nvme_multipath_policy policy,
|
2022-10-31 07:13:30 +00:00
|
|
|
enum bdev_nvme_multipath_selector selector, uint32_t rr_min_io,
|
|
|
|
bdev_nvme_set_multipath_policy_cb cb_fn, void *cb_arg)
|
2022-04-29 05:37:35 +00:00
|
|
|
{
|
|
|
|
struct bdev_nvme_set_multipath_policy_ctx *ctx;
|
|
|
|
struct spdk_bdev *bdev;
|
|
|
|
struct nvme_bdev *nbdev;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
assert(cb_fn != NULL);
|
|
|
|
|
2022-10-31 07:13:30 +00:00
|
|
|
if (policy == BDEV_NVME_MP_POLICY_ACTIVE_ACTIVE && selector == BDEV_NVME_MP_SELECTOR_ROUND_ROBIN) {
|
|
|
|
if (rr_min_io == UINT32_MAX) {
|
|
|
|
rr_min_io = 1;
|
|
|
|
} else if (rr_min_io == 0) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
} else if (rr_min_io != UINT32_MAX) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2022-04-29 05:37:35 +00:00
|
|
|
ctx = calloc(1, sizeof(*ctx));
|
|
|
|
if (ctx == NULL) {
|
|
|
|
SPDK_ERRLOG("Failed to alloc context.\n");
|
|
|
|
rc = -ENOMEM;
|
2022-10-31 07:13:30 +00:00
|
|
|
goto exit;
|
2022-04-29 05:37:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx->cb_fn = cb_fn;
|
|
|
|
ctx->cb_arg = cb_arg;
|
|
|
|
|
|
|
|
rc = spdk_bdev_open_ext(name, false, dummy_bdev_event_cb, NULL, &ctx->desc);
|
|
|
|
if (rc != 0) {
|
2022-06-06 23:44:54 +00:00
|
|
|
SPDK_ERRLOG("Failed to open bdev %s.\n", name);
|
2022-04-29 05:37:35 +00:00
|
|
|
rc = -ENODEV;
|
|
|
|
goto err_open;
|
|
|
|
}
|
|
|
|
|
|
|
|
bdev = spdk_bdev_desc_get_bdev(ctx->desc);
|
2022-06-06 23:44:54 +00:00
|
|
|
if (bdev->module != &nvme_if) {
|
|
|
|
SPDK_ERRLOG("bdev %s is not registered in this module.\n", name);
|
|
|
|
rc = -ENODEV;
|
|
|
|
goto err_module;
|
|
|
|
}
|
2022-04-29 05:37:35 +00:00
|
|
|
nbdev = SPDK_CONTAINEROF(bdev, struct nvme_bdev, disk);
|
|
|
|
|
|
|
|
pthread_mutex_lock(&nbdev->mutex);
|
|
|
|
nbdev->mp_policy = policy;
|
2022-09-20 07:12:47 +00:00
|
|
|
nbdev->mp_selector = selector;
|
2022-10-31 07:13:30 +00:00
|
|
|
nbdev->rr_min_io = rr_min_io;
|
2022-04-29 05:37:35 +00:00
|
|
|
pthread_mutex_unlock(&nbdev->mutex);
|
|
|
|
|
|
|
|
spdk_for_each_channel(nbdev,
|
|
|
|
_bdev_nvme_set_multipath_policy,
|
|
|
|
ctx,
|
|
|
|
bdev_nvme_set_multipath_policy_done);
|
|
|
|
return;
|
|
|
|
|
2022-06-06 23:44:54 +00:00
|
|
|
err_module:
|
|
|
|
spdk_bdev_close(ctx->desc);
|
2022-04-29 05:37:35 +00:00
|
|
|
err_open:
|
|
|
|
free(ctx);
|
2022-10-31 07:13:30 +00:00
|
|
|
exit:
|
2022-04-29 05:37:35 +00:00
|
|
|
cb_fn(cb_arg, rc);
|
|
|
|
}
|
|
|
|
|
2018-06-21 01:10:30 +00:00
|
|
|
static void
|
|
|
|
aer_cb(void *arg, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
2021-07-06 19:42:41 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr = arg;
|
2018-06-21 01:10:30 +00:00
|
|
|
union spdk_nvme_async_event_completion event;
|
|
|
|
|
|
|
|
if (spdk_nvme_cpl_is_error(cpl)) {
|
2022-08-04 16:00:07 +00:00
|
|
|
SPDK_WARNLOG("AER request execute failed\n");
|
2018-06-21 01:10:30 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
event.raw = cpl->cdw0;
|
|
|
|
if ((event.bits.async_event_type == SPDK_NVME_ASYNC_EVENT_TYPE_NOTICE) &&
|
|
|
|
(event.bits.async_event_info == SPDK_NVME_ASYNC_EVENT_NS_ATTR_CHANGED)) {
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr_populate_namespaces(nvme_ctrlr, NULL);
|
2021-07-02 07:03:59 +00:00
|
|
|
} else if ((event.bits.async_event_type == SPDK_NVME_ASYNC_EVENT_TYPE_NOTICE) &&
|
|
|
|
(event.bits.async_event_info == SPDK_NVME_ASYNC_EVENT_ANA_CHANGE)) {
|
|
|
|
nvme_ctrlr_read_ana_log_page(nvme_ctrlr);
|
2018-06-21 01:10:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-24 10:46:38 +00:00
|
|
|
static void
|
|
|
|
populate_namespaces_cb(struct nvme_async_probe_ctx *ctx, size_t count, int rc)
|
|
|
|
{
|
|
|
|
if (ctx->cb_fn) {
|
|
|
|
ctx->cb_fn(ctx->cb_ctx, count, rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->namespaces_populated = true;
|
|
|
|
if (ctx->probe_done) {
|
|
|
|
/* The probe was already completed, so we need to free the context
|
|
|
|
* here. This can happen for cases like OCSSD, where we need to
|
|
|
|
* send additional commands to the SSD after attach.
|
|
|
|
*/
|
|
|
|
free(ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-13 21:16:46 +00:00
|
|
|
static void
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr_create_done(struct nvme_ctrlr *nvme_ctrlr,
|
|
|
|
struct nvme_async_probe_ctx *ctx)
|
2021-06-13 21:16:46 +00:00
|
|
|
{
|
2021-07-06 19:42:41 +00:00
|
|
|
spdk_io_device_register(nvme_ctrlr,
|
2021-07-07 01:02:14 +00:00
|
|
|
bdev_nvme_create_ctrlr_channel_cb,
|
|
|
|
bdev_nvme_destroy_ctrlr_channel_cb,
|
|
|
|
sizeof(struct nvme_ctrlr_channel),
|
2021-09-07 16:13:07 +00:00
|
|
|
nvme_ctrlr->nbdev_ctrlr->name);
|
2021-06-13 21:16:46 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr_populate_namespaces(nvme_ctrlr, ctx);
|
2021-06-13 21:16:46 +00:00
|
|
|
}
|
|
|
|
|
2021-07-05 11:07:14 +00:00
|
|
|
static void
|
|
|
|
nvme_ctrlr_init_ana_log_page_done(void *_ctx, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = _ctx;
|
|
|
|
struct nvme_async_probe_ctx *ctx = nvme_ctrlr->probe_ctx;
|
|
|
|
|
|
|
|
nvme_ctrlr->probe_ctx = NULL;
|
|
|
|
|
|
|
|
if (spdk_nvme_cpl_is_error(cpl)) {
|
|
|
|
nvme_ctrlr_delete(nvme_ctrlr);
|
|
|
|
|
|
|
|
if (ctx != NULL) {
|
|
|
|
populate_namespaces_cb(ctx, 0, -1);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nvme_ctrlr_create_done(nvme_ctrlr, ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
nvme_ctrlr_init_ana_log_page(struct nvme_ctrlr *nvme_ctrlr,
|
|
|
|
struct nvme_async_probe_ctx *ctx)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr = nvme_ctrlr->ctrlr;
|
|
|
|
const struct spdk_nvme_ctrlr_data *cdata;
|
|
|
|
uint32_t ana_log_page_size;
|
|
|
|
|
|
|
|
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
|
|
|
|
|
2022-07-13 04:57:25 +00:00
|
|
|
/* Set buffer size enough to include maximum number of allowed namespaces. */
|
2021-07-05 11:07:14 +00:00
|
|
|
ana_log_page_size = sizeof(struct spdk_nvme_ana_page) + cdata->nanagrpid *
|
2022-06-14 18:55:45 +00:00
|
|
|
sizeof(struct spdk_nvme_ana_group_descriptor) + cdata->mnan *
|
2021-07-05 11:07:14 +00:00
|
|
|
sizeof(uint32_t);
|
|
|
|
|
|
|
|
nvme_ctrlr->ana_log_page = spdk_zmalloc(ana_log_page_size, 64, NULL,
|
|
|
|
SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
|
|
|
|
if (nvme_ctrlr->ana_log_page == NULL) {
|
|
|
|
SPDK_ERRLOG("could not allocate ANA log page buffer\n");
|
|
|
|
return -ENXIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Each descriptor in a ANA log page is not ensured to be 8-bytes aligned.
|
|
|
|
* Hence copy each descriptor to a temporary area when parsing it.
|
|
|
|
*
|
|
|
|
* Allocate a buffer whose size is as large as ANA log page buffer because
|
|
|
|
* we do not know the size of a descriptor until actually reading it.
|
|
|
|
*/
|
|
|
|
nvme_ctrlr->copied_ana_desc = calloc(1, ana_log_page_size);
|
|
|
|
if (nvme_ctrlr->copied_ana_desc == NULL) {
|
|
|
|
SPDK_ERRLOG("could not allocate a buffer to parse ANA descriptor\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2022-07-13 04:57:25 +00:00
|
|
|
nvme_ctrlr->max_ana_log_page_size = ana_log_page_size;
|
2021-07-05 11:07:14 +00:00
|
|
|
|
|
|
|
nvme_ctrlr->probe_ctx = ctx;
|
|
|
|
|
2022-07-13 04:57:25 +00:00
|
|
|
/* Then, set the read size only to include the current active namespaces. */
|
|
|
|
ana_log_page_size = nvme_ctrlr_get_ana_log_page_size(nvme_ctrlr);
|
|
|
|
|
|
|
|
if (ana_log_page_size > nvme_ctrlr->max_ana_log_page_size) {
|
|
|
|
SPDK_ERRLOG("ANA log page size %" PRIu32 " is larger than allowed %" PRIu32 "\n",
|
|
|
|
ana_log_page_size, nvme_ctrlr->max_ana_log_page_size);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-07-05 11:07:14 +00:00
|
|
|
return spdk_nvme_ctrlr_cmd_get_log_page(ctrlr,
|
|
|
|
SPDK_NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS,
|
|
|
|
SPDK_NVME_GLOBAL_NS_TAG,
|
|
|
|
nvme_ctrlr->ana_log_page,
|
2022-07-13 04:57:25 +00:00
|
|
|
ana_log_page_size, 0,
|
2021-07-05 11:07:14 +00:00
|
|
|
nvme_ctrlr_init_ana_log_page_done,
|
|
|
|
nvme_ctrlr);
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
/* hostnqn and subnqn were already verified before attaching a controller.
|
|
|
|
* Hence check only the multipath capability and cntlid here.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
bdev_nvme_check_multipath(struct nvme_bdev_ctrlr *nbdev_ctrlr, struct spdk_nvme_ctrlr *ctrlr)
|
|
|
|
{
|
|
|
|
struct nvme_ctrlr *tmp;
|
|
|
|
const struct spdk_nvme_ctrlr_data *cdata, *tmp_cdata;
|
|
|
|
|
|
|
|
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
|
|
|
|
|
|
|
|
if (!cdata->cmic.multi_ctrlr) {
|
|
|
|
SPDK_ERRLOG("Ctrlr%u does not support multipath.\n", cdata->cntlid);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_FOREACH(tmp, &nbdev_ctrlr->ctrlrs, tailq) {
|
|
|
|
tmp_cdata = spdk_nvme_ctrlr_get_data(tmp->ctrlr);
|
|
|
|
|
|
|
|
if (!tmp_cdata->cmic.multi_ctrlr) {
|
|
|
|
SPDK_ERRLOG("Ctrlr%u does not support multipath.\n", cdata->cntlid);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (cdata->cntlid == tmp_cdata->cntlid) {
|
|
|
|
SPDK_ERRLOG("cntlid %u are duplicated.\n", tmp_cdata->cntlid);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
nvme_bdev_ctrlr_create(const char *name, struct nvme_ctrlr *nvme_ctrlr)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_ctrlr *nbdev_ctrlr;
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr = nvme_ctrlr->ctrlr;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&g_bdev_nvme_mutex);
|
|
|
|
|
2021-11-10 02:05:00 +00:00
|
|
|
nbdev_ctrlr = nvme_bdev_ctrlr_get_by_name(name);
|
2021-09-07 16:13:07 +00:00
|
|
|
if (nbdev_ctrlr != NULL) {
|
|
|
|
if (!bdev_nvme_check_multipath(nbdev_ctrlr, ctrlr)) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nbdev_ctrlr = calloc(1, sizeof(*nbdev_ctrlr));
|
|
|
|
if (nbdev_ctrlr == NULL) {
|
|
|
|
SPDK_ERRLOG("Failed to allocate nvme_bdev_ctrlr.\n");
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
nbdev_ctrlr->name = strdup(name);
|
|
|
|
if (nbdev_ctrlr->name == NULL) {
|
|
|
|
SPDK_ERRLOG("Failed to allocate name of nvme_bdev_ctrlr.\n");
|
|
|
|
free(nbdev_ctrlr);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
TAILQ_INIT(&nbdev_ctrlr->ctrlrs);
|
2021-09-27 23:15:02 +00:00
|
|
|
TAILQ_INIT(&nbdev_ctrlr->bdevs);
|
2021-09-07 16:13:07 +00:00
|
|
|
TAILQ_INSERT_TAIL(&g_nvme_bdev_ctrlrs, nbdev_ctrlr, tailq);
|
|
|
|
}
|
|
|
|
nvme_ctrlr->nbdev_ctrlr = nbdev_ctrlr;
|
|
|
|
TAILQ_INSERT_TAIL(&nbdev_ctrlr->ctrlrs, nvme_ctrlr, tailq);
|
|
|
|
exit:
|
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-06-15 22:30:43 +00:00
|
|
|
static int
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr_create(struct spdk_nvme_ctrlr *ctrlr,
|
|
|
|
const char *name,
|
|
|
|
const struct spdk_nvme_transport_id *trid,
|
|
|
|
struct nvme_async_probe_ctx *ctx)
|
2016-07-20 18:16:23 +00:00
|
|
|
{
|
2021-07-06 19:42:41 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr;
|
2021-09-14 18:26:50 +00:00
|
|
|
struct nvme_path_id *path_id;
|
2021-07-05 11:07:14 +00:00
|
|
|
const struct spdk_nvme_ctrlr_data *cdata;
|
2019-12-11 11:20:08 +00:00
|
|
|
int rc;
|
2017-03-30 17:59:25 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr = calloc(1, sizeof(*nvme_ctrlr));
|
|
|
|
if (nvme_ctrlr == NULL) {
|
2016-07-20 18:16:23 +00:00
|
|
|
SPDK_ERRLOG("Failed to allocate device struct\n");
|
2018-06-15 22:30:43 +00:00
|
|
|
return -ENOMEM;
|
2016-07-20 18:16:23 +00:00
|
|
|
}
|
2020-06-24 22:00:57 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
rc = pthread_mutex_init(&nvme_ctrlr->mutex, NULL);
|
2021-03-03 17:23:21 +00:00
|
|
|
if (rc != 0) {
|
2021-07-06 19:42:41 +00:00
|
|
|
free(nvme_ctrlr);
|
2021-06-13 20:56:02 +00:00
|
|
|
return rc;
|
2021-03-03 17:23:21 +00:00
|
|
|
}
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
TAILQ_INIT(&nvme_ctrlr->trids);
|
2021-06-13 20:56:02 +00:00
|
|
|
|
2021-08-25 16:58:16 +00:00
|
|
|
RB_INIT(&nvme_ctrlr->namespaces);
|
2020-06-12 22:14:49 +00:00
|
|
|
|
2021-09-14 18:26:50 +00:00
|
|
|
path_id = calloc(1, sizeof(*path_id));
|
|
|
|
if (path_id == NULL) {
|
2020-06-12 22:14:49 +00:00
|
|
|
SPDK_ERRLOG("Failed to allocate trid entry pointer\n");
|
2020-10-01 09:11:39 +00:00
|
|
|
rc = -ENOMEM;
|
2021-06-13 20:56:02 +00:00
|
|
|
goto err;
|
2020-06-12 22:14:49 +00:00
|
|
|
}
|
|
|
|
|
2021-09-14 18:26:50 +00:00
|
|
|
path_id->trid = *trid;
|
2021-10-11 20:35:39 +00:00
|
|
|
if (ctx != NULL) {
|
2022-03-08 08:56:35 +00:00
|
|
|
memcpy(path_id->hostid.hostaddr, ctx->drv_opts.src_addr, sizeof(path_id->hostid.hostaddr));
|
|
|
|
memcpy(path_id->hostid.hostsvcid, ctx->drv_opts.src_svcid, sizeof(path_id->hostid.hostsvcid));
|
2021-10-11 20:35:39 +00:00
|
|
|
}
|
2021-09-21 19:17:12 +00:00
|
|
|
nvme_ctrlr->active_path_id = path_id;
|
2021-09-14 18:26:50 +00:00
|
|
|
TAILQ_INSERT_HEAD(&nvme_ctrlr->trids, path_id, link);
|
2021-07-06 19:42:41 +00:00
|
|
|
|
|
|
|
nvme_ctrlr->thread = spdk_get_thread();
|
|
|
|
nvme_ctrlr->ctrlr = ctrlr;
|
|
|
|
nvme_ctrlr->ref = 1;
|
2019-12-11 11:20:08 +00:00
|
|
|
|
2021-07-05 11:07:14 +00:00
|
|
|
if (spdk_nvme_ctrlr_is_ocssd_supported(ctrlr)) {
|
2021-08-27 20:23:56 +00:00
|
|
|
SPDK_ERRLOG("OCSSDs are not supported");
|
|
|
|
rc = -ENOTSUP;
|
|
|
|
goto err;
|
2019-12-11 11:20:08 +00:00
|
|
|
}
|
|
|
|
|
2021-11-28 15:20:29 +00:00
|
|
|
if (ctx != NULL) {
|
2022-03-04 04:51:53 +00:00
|
|
|
memcpy(&nvme_ctrlr->opts, &ctx->bdev_opts, sizeof(ctx->bdev_opts));
|
2022-03-25 21:38:09 +00:00
|
|
|
} else {
|
|
|
|
bdev_nvme_get_default_ctrlr_opts(&nvme_ctrlr->opts);
|
2021-11-28 15:20:29 +00:00
|
|
|
}
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr->adminq_timer_poller = SPDK_POLLER_REGISTER(bdev_nvme_poll_adminq, nvme_ctrlr,
|
|
|
|
g_opts.nvme_adminq_poll_period_us);
|
2017-01-13 19:58:23 +00:00
|
|
|
|
2019-02-19 22:03:10 +00:00
|
|
|
if (g_opts.timeout_us > 0) {
|
2021-05-26 20:43:22 +00:00
|
|
|
/* Register timeout callback. Timeout values for IO vs. admin reqs can be different. */
|
|
|
|
/* If timeout_admin_us is 0 (not specified), admin uses same timeout as IO. */
|
|
|
|
uint64_t adm_timeout_us = (g_opts.timeout_admin_us == 0) ?
|
|
|
|
g_opts.timeout_us : g_opts.timeout_admin_us;
|
2018-07-09 21:04:33 +00:00
|
|
|
spdk_nvme_ctrlr_register_timeout_callback(ctrlr, g_opts.timeout_us,
|
2021-05-26 20:43:22 +00:00
|
|
|
adm_timeout_us, timeout_cb, nvme_ctrlr);
|
2016-12-10 22:43:18 +00:00
|
|
|
}
|
2018-06-15 22:30:43 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
spdk_nvme_ctrlr_register_aer_callback(ctrlr, aer_cb, nvme_ctrlr);
|
|
|
|
spdk_nvme_ctrlr_set_remove_cb(ctrlr, remove_cb, nvme_ctrlr);
|
2018-06-21 01:10:30 +00:00
|
|
|
|
2021-07-05 11:07:14 +00:00
|
|
|
if (spdk_nvme_ctrlr_get_flags(ctrlr) &
|
2019-07-19 15:26:53 +00:00
|
|
|
SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) {
|
2021-07-05 11:07:14 +00:00
|
|
|
nvme_ctrlr->opal_dev = spdk_opal_dev_construct(ctrlr);
|
2019-07-19 15:26:53 +00:00
|
|
|
}
|
2020-06-12 22:14:49 +00:00
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
rc = nvme_bdev_ctrlr_create(name, nvme_ctrlr);
|
|
|
|
if (rc != 0) {
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2021-07-05 11:07:14 +00:00
|
|
|
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
|
|
|
|
|
|
|
|
if (cdata->cmic.ana_reporting) {
|
|
|
|
rc = nvme_ctrlr_init_ana_log_page(nvme_ctrlr, ctx);
|
|
|
|
if (rc == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nvme_ctrlr_create_done(nvme_ctrlr, ctx);
|
|
|
|
return 0;
|
|
|
|
}
|
2020-10-01 09:11:39 +00:00
|
|
|
|
2021-06-13 20:56:02 +00:00
|
|
|
err:
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr_delete(nvme_ctrlr);
|
2020-10-01 09:11:39 +00:00
|
|
|
return rc;
|
2018-06-15 22:30:43 +00:00
|
|
|
}
|
|
|
|
|
2022-03-09 12:04:14 +00:00
|
|
|
void
|
|
|
|
bdev_nvme_get_default_ctrlr_opts(struct nvme_ctrlr_opts *opts)
|
|
|
|
{
|
|
|
|
opts->prchk_flags = 0;
|
|
|
|
opts->ctrlr_loss_timeout_sec = g_opts.ctrlr_loss_timeout_sec;
|
|
|
|
opts->reconnect_delay_sec = g_opts.reconnect_delay_sec;
|
|
|
|
opts->fast_io_fail_timeout_sec = g_opts.fast_io_fail_timeout_sec;
|
|
|
|
}
|
|
|
|
|
2018-06-15 22:30:43 +00:00
|
|
|
static void
|
|
|
|
attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
|
2022-03-08 08:56:35 +00:00
|
|
|
struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *drv_opts)
|
2018-06-15 22:30:43 +00:00
|
|
|
{
|
2021-11-28 15:13:38 +00:00
|
|
|
char *name;
|
2018-06-15 22:30:43 +00:00
|
|
|
|
2021-11-28 15:13:38 +00:00
|
|
|
name = spdk_sprintf_alloc("HotInNvme%d", g_hot_insert_nvme_controller_index++);
|
2018-06-15 22:30:43 +00:00
|
|
|
if (!name) {
|
|
|
|
SPDK_ERRLOG("Failed to assign name to NVMe device\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-29 06:42:11 +00:00
|
|
|
if (nvme_ctrlr_create(ctrlr, name, trid, NULL) == 0) {
|
|
|
|
SPDK_DEBUGLOG(bdev_nvme, "Attached to %s (%s)\n", trid->traddr, name);
|
|
|
|
} else {
|
|
|
|
SPDK_ERRLOG("Failed to attach to %s (%s)\n", trid->traddr, name);
|
|
|
|
}
|
2019-09-17 08:06:33 +00:00
|
|
|
|
2018-06-15 22:44:08 +00:00
|
|
|
free(name);
|
2016-07-20 18:16:23 +00:00
|
|
|
}
|
|
|
|
|
2020-11-26 06:25:08 +00:00
|
|
|
static void
|
2021-07-06 19:42:41 +00:00
|
|
|
_nvme_ctrlr_destruct(void *ctx)
|
2020-11-26 06:25:08 +00:00
|
|
|
{
|
2021-07-06 19:42:41 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr = ctx;
|
2020-11-26 06:34:00 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr_depopulate_namespaces(nvme_ctrlr);
|
|
|
|
nvme_ctrlr_release(nvme_ctrlr);
|
2020-11-26 06:25:08 +00:00
|
|
|
}
|
|
|
|
|
2021-03-03 16:07:18 +00:00
|
|
|
static int
|
2021-07-06 19:42:41 +00:00
|
|
|
_bdev_nvme_delete(struct nvme_ctrlr *nvme_ctrlr, bool hotplug)
|
2017-03-01 01:23:53 +00:00
|
|
|
{
|
2021-03-03 16:07:18 +00:00
|
|
|
struct nvme_probe_skip_entry *entry;
|
2017-03-01 01:23:53 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
2021-03-03 16:07:18 +00:00
|
|
|
|
2020-12-07 15:42:00 +00:00
|
|
|
/* The controller's destruction was already started */
|
2021-07-06 19:42:41 +00:00
|
|
|
if (nvme_ctrlr->destruct) {
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2021-03-03 16:07:18 +00:00
|
|
|
return 0;
|
2017-03-01 01:23:53 +00:00
|
|
|
}
|
2021-03-03 16:07:18 +00:00
|
|
|
|
|
|
|
if (!hotplug &&
|
2021-09-21 19:17:12 +00:00
|
|
|
nvme_ctrlr->active_path_id->trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
|
2021-03-03 16:07:18 +00:00
|
|
|
entry = calloc(1, sizeof(*entry));
|
|
|
|
if (!entry) {
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2021-03-03 16:07:18 +00:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2021-09-21 19:17:12 +00:00
|
|
|
entry->trid = nvme_ctrlr->active_path_id->trid;
|
2021-03-03 16:07:18 +00:00
|
|
|
TAILQ_INSERT_TAIL(&g_skipped_nvme_ctrlrs, entry, tailq);
|
|
|
|
}
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr->destruct = true;
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2021-03-03 16:07:18 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
_nvme_ctrlr_destruct(nvme_ctrlr);
|
2021-03-03 16:07:18 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
remove_cb(void *cb_ctx, struct spdk_nvme_ctrlr *ctrlr)
|
|
|
|
{
|
2021-07-06 19:42:41 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr = cb_ctx;
|
2021-03-03 16:07:18 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
_bdev_nvme_delete(nvme_ctrlr, true);
|
2017-03-01 01:23:53 +00:00
|
|
|
}
|
|
|
|
|
2020-12-18 13:10:56 +00:00
|
|
|
static int
|
|
|
|
bdev_nvme_hotplug_probe(void *arg)
|
|
|
|
{
|
2021-03-23 19:25:08 +00:00
|
|
|
if (g_hotplug_probe_ctx == NULL) {
|
|
|
|
spdk_poller_unregister(&g_hotplug_probe_poller);
|
|
|
|
return SPDK_POLLER_IDLE;
|
|
|
|
}
|
|
|
|
|
2020-12-18 13:10:56 +00:00
|
|
|
if (spdk_nvme_probe_poll_async(g_hotplug_probe_ctx) != -EAGAIN) {
|
|
|
|
g_hotplug_probe_ctx = NULL;
|
|
|
|
spdk_poller_unregister(&g_hotplug_probe_poller);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SPDK_POLLER_BUSY;
|
|
|
|
}
|
|
|
|
|
2018-03-13 00:16:47 +00:00
|
|
|
static int
|
2017-07-13 04:08:53 +00:00
|
|
|
bdev_nvme_hotplug(void *arg)
|
2017-03-01 01:23:53 +00:00
|
|
|
{
|
2019-03-05 07:32:34 +00:00
|
|
|
struct spdk_nvme_transport_id trid_pcie;
|
|
|
|
|
2020-12-18 13:10:56 +00:00
|
|
|
if (g_hotplug_probe_ctx) {
|
|
|
|
return SPDK_POLLER_BUSY;
|
2019-03-05 07:32:34 +00:00
|
|
|
}
|
|
|
|
|
2020-12-18 13:10:56 +00:00
|
|
|
memset(&trid_pcie, 0, sizeof(trid_pcie));
|
|
|
|
spdk_nvme_trid_populate_transport(&trid_pcie, SPDK_NVME_TRANSPORT_PCIE);
|
|
|
|
|
|
|
|
g_hotplug_probe_ctx = spdk_nvme_probe_async(&trid_pcie, NULL,
|
|
|
|
hotplug_probe_cb, attach_cb, NULL);
|
|
|
|
|
|
|
|
if (g_hotplug_probe_ctx) {
|
|
|
|
assert(g_hotplug_probe_poller == NULL);
|
|
|
|
g_hotplug_probe_poller = SPDK_POLLER_REGISTER(bdev_nvme_hotplug_probe, NULL, 1000);
|
2017-03-01 01:23:53 +00:00
|
|
|
}
|
2018-03-13 00:16:47 +00:00
|
|
|
|
2020-05-04 09:51:27 +00:00
|
|
|
return SPDK_POLLER_BUSY;
|
2017-03-01 01:23:53 +00:00
|
|
|
}
|
|
|
|
|
2018-07-09 21:04:33 +00:00
|
|
|
void
|
2020-05-10 07:46:07 +00:00
|
|
|
bdev_nvme_get_opts(struct spdk_bdev_nvme_opts *opts)
|
2018-07-09 21:04:33 +00:00
|
|
|
{
|
|
|
|
*opts = g_opts;
|
|
|
|
}
|
|
|
|
|
2022-03-28 02:06:42 +00:00
|
|
|
static bool bdev_nvme_check_io_error_resiliency_params(int32_t ctrlr_loss_timeout_sec,
|
2022-03-09 12:04:14 +00:00
|
|
|
uint32_t reconnect_delay_sec,
|
|
|
|
uint32_t fast_io_fail_timeout_sec);
|
|
|
|
|
2021-06-02 17:42:34 +00:00
|
|
|
static int
|
|
|
|
bdev_nvme_validate_opts(const struct spdk_bdev_nvme_opts *opts)
|
|
|
|
{
|
|
|
|
if ((opts->timeout_us == 0) && (opts->timeout_admin_us != 0)) {
|
|
|
|
/* Can't set timeout_admin_us without also setting timeout_us */
|
|
|
|
SPDK_WARNLOG("Invalid options: Can't have (timeout_us == 0) with (timeout_admin_us > 0)\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-10-25 02:59:46 +00:00
|
|
|
if (opts->bdev_retry_count < -1) {
|
|
|
|
SPDK_WARNLOG("Invalid option: bdev_retry_count can't be less than -1.\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2022-03-28 02:06:42 +00:00
|
|
|
if (!bdev_nvme_check_io_error_resiliency_params(opts->ctrlr_loss_timeout_sec,
|
|
|
|
opts->reconnect_delay_sec,
|
|
|
|
opts->fast_io_fail_timeout_sec)) {
|
2022-03-09 12:04:14 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-06-02 17:42:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-09 21:04:33 +00:00
|
|
|
int
|
2020-05-10 07:46:07 +00:00
|
|
|
bdev_nvme_set_opts(const struct spdk_bdev_nvme_opts *opts)
|
2018-07-09 21:04:33 +00:00
|
|
|
{
|
2023-01-13 11:49:15 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = bdev_nvme_validate_opts(opts);
|
2021-06-02 17:42:34 +00:00
|
|
|
if (ret) {
|
|
|
|
SPDK_WARNLOG("Failed to set nvme opts.\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-07-12 12:26:19 +00:00
|
|
|
if (g_bdev_nvme_init_thread != NULL) {
|
2021-09-07 16:13:07 +00:00
|
|
|
if (!TAILQ_EMPTY(&g_nvme_bdev_ctrlrs)) {
|
2020-01-07 18:53:13 +00:00
|
|
|
return -EPERM;
|
|
|
|
}
|
2018-07-09 21:04:33 +00:00
|
|
|
}
|
|
|
|
|
2023-01-13 11:49:15 +00:00
|
|
|
if (opts->rdma_srq_size != 0) {
|
|
|
|
struct spdk_nvme_transport_opts drv_opts;
|
|
|
|
|
|
|
|
spdk_nvme_transport_get_opts(&drv_opts, sizeof(drv_opts));
|
|
|
|
drv_opts.rdma_srq_size = opts->rdma_srq_size;
|
|
|
|
|
|
|
|
ret = spdk_nvme_transport_set_opts(&drv_opts, sizeof(drv_opts));
|
|
|
|
if (ret) {
|
|
|
|
SPDK_ERRLOG("Failed to set NVMe transport opts.\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-09 21:04:33 +00:00
|
|
|
g_opts = *opts;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-07-10 05:13:31 +00:00
|
|
|
|
2018-07-12 12:26:19 +00:00
|
|
|
struct set_nvme_hotplug_ctx {
|
|
|
|
uint64_t period_us;
|
|
|
|
bool enabled;
|
2018-10-10 21:05:04 +00:00
|
|
|
spdk_msg_fn fn;
|
2018-07-12 12:26:19 +00:00
|
|
|
void *fn_ctx;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_nvme_hotplug_period_cb(void *_ctx)
|
|
|
|
{
|
|
|
|
struct set_nvme_hotplug_ctx *ctx = _ctx;
|
|
|
|
|
|
|
|
spdk_poller_unregister(&g_hotplug_poller);
|
|
|
|
if (ctx->enabled) {
|
2020-04-14 06:49:46 +00:00
|
|
|
g_hotplug_poller = SPDK_POLLER_REGISTER(bdev_nvme_hotplug, NULL, ctx->period_us);
|
2018-07-12 12:26:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
g_nvme_hotplug_poll_period_us = ctx->period_us;
|
|
|
|
g_nvme_hotplug_enabled = ctx->enabled;
|
|
|
|
if (ctx->fn) {
|
|
|
|
ctx->fn(ctx->fn_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2020-05-10 07:46:07 +00:00
|
|
|
bdev_nvme_set_hotplug(bool enabled, uint64_t period_us, spdk_msg_fn cb, void *cb_ctx)
|
2018-07-12 12:26:19 +00:00
|
|
|
{
|
|
|
|
struct set_nvme_hotplug_ctx *ctx;
|
|
|
|
|
|
|
|
if (enabled == true && !spdk_process_is_primary()) {
|
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = calloc(1, sizeof(*ctx));
|
|
|
|
if (ctx == NULL) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
period_us = period_us == 0 ? NVME_HOTPLUG_POLL_PERIOD_DEFAULT : period_us;
|
|
|
|
ctx->period_us = spdk_min(period_us, NVME_HOTPLUG_POLL_PERIOD_MAX);
|
|
|
|
ctx->enabled = enabled;
|
|
|
|
ctx->fn = cb;
|
|
|
|
ctx->fn_ctx = cb_ctx;
|
|
|
|
|
|
|
|
spdk_thread_send_msg(g_bdev_nvme_init_thread, set_nvme_hotplug_period_cb, ctx);
|
|
|
|
return 0;
|
|
|
|
}
|
2018-07-09 21:04:33 +00:00
|
|
|
|
2019-09-27 09:27:30 +00:00
|
|
|
static void
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr_populate_namespaces_done(struct nvme_ctrlr *nvme_ctrlr,
|
2021-03-01 22:39:39 +00:00
|
|
|
struct nvme_async_probe_ctx *ctx)
|
2019-03-05 06:13:03 +00:00
|
|
|
{
|
2021-06-30 01:08:29 +00:00
|
|
|
struct nvme_ns *nvme_ns;
|
2021-01-06 16:21:06 +00:00
|
|
|
struct nvme_bdev *nvme_bdev;
|
2019-03-05 06:13:03 +00:00
|
|
|
size_t j;
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
assert(nvme_ctrlr != NULL);
|
2019-09-17 08:06:33 +00:00
|
|
|
|
2021-12-07 23:55:06 +00:00
|
|
|
if (ctx->names == NULL) {
|
|
|
|
populate_namespaces_cb(ctx, 0, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-05 06:13:03 +00:00
|
|
|
/*
|
|
|
|
* Report the new bdevs that were created in this call.
|
2019-10-18 07:12:00 +00:00
|
|
|
* There can be more than one bdev per NVMe controller.
|
2019-03-05 06:13:03 +00:00
|
|
|
*/
|
|
|
|
j = 0;
|
2021-08-25 23:18:18 +00:00
|
|
|
nvme_ns = nvme_ctrlr_get_first_active_ns(nvme_ctrlr);
|
|
|
|
while (nvme_ns != NULL) {
|
2021-03-26 14:29:54 +00:00
|
|
|
nvme_bdev = nvme_ns->bdev;
|
2021-01-06 16:21:06 +00:00
|
|
|
if (j < ctx->count) {
|
|
|
|
ctx->names[j] = nvme_bdev->disk.name;
|
|
|
|
j++;
|
|
|
|
} else {
|
|
|
|
SPDK_ERRLOG("Maximum number of namespaces supported per NVMe controller is %du. Unable to return all names of created bdevs\n",
|
|
|
|
ctx->count);
|
|
|
|
populate_namespaces_cb(ctx, 0, -ERANGE);
|
|
|
|
return;
|
2019-03-05 06:13:03 +00:00
|
|
|
}
|
2021-08-25 23:18:18 +00:00
|
|
|
|
|
|
|
nvme_ns = nvme_ctrlr_get_next_active_ns(nvme_ctrlr, nvme_ns);
|
2019-03-05 06:13:03 +00:00
|
|
|
}
|
|
|
|
|
2019-11-26 17:52:55 +00:00
|
|
|
populate_namespaces_cb(ctx, j, 0);
|
2019-03-05 06:13:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-24 02:05:17 +00:00
|
|
|
static int
|
2022-08-23 08:58:37 +00:00
|
|
|
bdev_nvme_check_secondary_trid(struct nvme_ctrlr *nvme_ctrlr,
|
|
|
|
struct spdk_nvme_ctrlr *new_ctrlr,
|
|
|
|
struct spdk_nvme_transport_id *trid)
|
2020-06-12 22:14:49 +00:00
|
|
|
{
|
2021-09-14 18:26:50 +00:00
|
|
|
struct nvme_path_id *tmp_trid;
|
2020-06-12 22:14:49 +00:00
|
|
|
|
2020-09-24 02:10:11 +00:00
|
|
|
if (trid->trtype == SPDK_NVME_TRANSPORT_PCIE) {
|
|
|
|
SPDK_ERRLOG("PCIe failover is not supported.\n");
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2020-06-12 22:14:49 +00:00
|
|
|
/* Currently we only support failover to the same transport type. */
|
2021-09-21 19:17:12 +00:00
|
|
|
if (nvme_ctrlr->active_path_id->trid.trtype != trid->trtype) {
|
2022-08-23 08:58:37 +00:00
|
|
|
SPDK_WARNLOG("Failover from trtype: %s to a different trtype: %s is not supported currently\n",
|
|
|
|
spdk_nvme_transport_id_trtype_str(nvme_ctrlr->active_path_id->trid.trtype),
|
|
|
|
spdk_nvme_transport_id_trtype_str(trid->trtype));
|
2021-03-26 09:20:04 +00:00
|
|
|
return -EINVAL;
|
2020-06-12 22:14:49 +00:00
|
|
|
}
|
|
|
|
|
2022-08-23 08:58:37 +00:00
|
|
|
|
2020-06-12 22:14:49 +00:00
|
|
|
/* Currently we only support failover to the same NQN. */
|
2021-09-21 19:17:12 +00:00
|
|
|
if (strncmp(trid->subnqn, nvme_ctrlr->active_path_id->trid.subnqn, SPDK_NVMF_NQN_MAX_LEN)) {
|
2022-08-23 08:58:37 +00:00
|
|
|
SPDK_WARNLOG("Failover from subnqn: %s to a different subnqn: %s is not supported currently\n",
|
|
|
|
nvme_ctrlr->active_path_id->trid.subnqn, trid->subnqn);
|
2021-03-26 09:20:04 +00:00
|
|
|
return -EINVAL;
|
2020-06-12 22:14:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip all the other checks if we've already registered this path. */
|
2021-07-06 19:42:41 +00:00
|
|
|
TAILQ_FOREACH(tmp_trid, &nvme_ctrlr->trids, link) {
|
2021-03-26 09:20:04 +00:00
|
|
|
if (!spdk_nvme_transport_id_compare(&tmp_trid->trid, trid)) {
|
2022-08-23 08:58:37 +00:00
|
|
|
SPDK_WARNLOG("This path (traddr: %s subnqn: %s) is already registered\n", trid->traddr,
|
|
|
|
trid->subnqn);
|
2021-03-26 09:20:04 +00:00
|
|
|
return -EEXIST;
|
2020-06-12 22:14:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-26 09:20:04 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2022-08-23 08:58:37 +00:00
|
|
|
bdev_nvme_check_secondary_namespace(struct nvme_ctrlr *nvme_ctrlr,
|
|
|
|
struct spdk_nvme_ctrlr *new_ctrlr)
|
2021-03-26 09:20:04 +00:00
|
|
|
{
|
2021-06-30 01:08:29 +00:00
|
|
|
struct nvme_ns *nvme_ns;
|
2021-03-26 09:20:04 +00:00
|
|
|
struct spdk_nvme_ns *new_ns;
|
|
|
|
|
2021-08-25 23:18:18 +00:00
|
|
|
nvme_ns = nvme_ctrlr_get_first_active_ns(nvme_ctrlr);
|
|
|
|
while (nvme_ns != NULL) {
|
|
|
|
new_ns = spdk_nvme_ctrlr_get_ns(new_ctrlr, nvme_ns->id);
|
2020-06-12 22:14:49 +00:00
|
|
|
assert(new_ns != NULL);
|
|
|
|
|
2021-05-16 21:47:51 +00:00
|
|
|
if (!bdev_nvme_compare_ns(nvme_ns->ns, new_ns)) {
|
2021-03-26 09:20:04 +00:00
|
|
|
return -EINVAL;
|
2020-06-12 22:14:49 +00:00
|
|
|
}
|
2021-08-25 23:18:18 +00:00
|
|
|
|
|
|
|
nvme_ns = nvme_ctrlr_get_next_active_ns(nvme_ctrlr, nvme_ns);
|
2020-06-12 22:14:49 +00:00
|
|
|
}
|
|
|
|
|
2021-03-26 09:20:04 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2021-07-06 19:42:41 +00:00
|
|
|
_bdev_nvme_add_secondary_trid(struct nvme_ctrlr *nvme_ctrlr,
|
2021-03-26 09:20:04 +00:00
|
|
|
struct spdk_nvme_transport_id *trid)
|
|
|
|
{
|
2021-09-14 18:26:50 +00:00
|
|
|
struct nvme_path_id *new_trid, *tmp_trid;
|
2021-03-26 09:20:04 +00:00
|
|
|
|
2020-06-12 22:14:49 +00:00
|
|
|
new_trid = calloc(1, sizeof(*new_trid));
|
|
|
|
if (new_trid == NULL) {
|
2021-03-26 09:20:04 +00:00
|
|
|
return -ENOMEM;
|
2020-06-12 22:14:49 +00:00
|
|
|
}
|
|
|
|
new_trid->trid = *trid;
|
2020-12-22 12:50:29 +00:00
|
|
|
new_trid->is_failed = false;
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
TAILQ_FOREACH(tmp_trid, &nvme_ctrlr->trids, link) {
|
2021-12-30 07:45:06 +00:00
|
|
|
if (tmp_trid->is_failed && tmp_trid != nvme_ctrlr->active_path_id) {
|
2020-12-22 12:50:29 +00:00
|
|
|
TAILQ_INSERT_BEFORE(tmp_trid, new_trid, link);
|
2021-03-26 09:20:04 +00:00
|
|
|
return 0;
|
2020-12-22 12:50:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
TAILQ_INSERT_TAIL(&nvme_ctrlr->trids, new_trid, link);
|
2021-03-26 09:20:04 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-26 09:32:12 +00:00
|
|
|
/* This is the case that a secondary path is added to an existing
|
2021-07-06 19:42:41 +00:00
|
|
|
* nvme_ctrlr for failover. After checking if it can access the same
|
2021-03-26 09:32:12 +00:00
|
|
|
* namespaces as the primary path, it is disconnected until failover occurs.
|
|
|
|
*/
|
2021-06-13 19:56:22 +00:00
|
|
|
static int
|
2021-07-06 19:42:41 +00:00
|
|
|
bdev_nvme_add_secondary_trid(struct nvme_ctrlr *nvme_ctrlr,
|
2021-03-26 09:20:04 +00:00
|
|
|
struct spdk_nvme_ctrlr *new_ctrlr,
|
2021-06-13 19:56:22 +00:00
|
|
|
struct spdk_nvme_transport_id *trid)
|
2021-03-26 09:20:04 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
assert(nvme_ctrlr != NULL);
|
2021-03-26 09:20:04 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
2021-03-26 09:20:04 +00:00
|
|
|
|
2022-08-23 08:58:37 +00:00
|
|
|
rc = bdev_nvme_check_secondary_trid(nvme_ctrlr, new_ctrlr, trid);
|
2021-03-26 09:20:04 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2022-08-23 08:58:37 +00:00
|
|
|
rc = bdev_nvme_check_secondary_namespace(nvme_ctrlr, new_ctrlr);
|
2021-03-26 09:20:04 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
rc = _bdev_nvme_add_secondary_trid(nvme_ctrlr, trid);
|
2020-06-12 22:14:49 +00:00
|
|
|
|
2020-12-22 12:26:39 +00:00
|
|
|
exit:
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2021-03-26 09:32:12 +00:00
|
|
|
|
|
|
|
spdk_nvme_detach(new_ctrlr);
|
|
|
|
|
2021-06-13 19:56:22 +00:00
|
|
|
return rc;
|
2020-06-12 22:14:49 +00:00
|
|
|
}
|
|
|
|
|
2020-11-27 17:38:18 +00:00
|
|
|
static void
|
|
|
|
connect_attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
|
2020-06-25 17:06:56 +00:00
|
|
|
{
|
2020-11-27 17:38:18 +00:00
|
|
|
struct spdk_nvme_ctrlr_opts *user_opts = cb_ctx;
|
2021-08-18 10:23:44 +00:00
|
|
|
struct nvme_async_probe_ctx *ctx;
|
|
|
|
int rc;
|
|
|
|
|
2022-03-08 08:56:35 +00:00
|
|
|
ctx = SPDK_CONTAINEROF(user_opts, struct nvme_async_probe_ctx, drv_opts);
|
2021-08-18 10:23:44 +00:00
|
|
|
ctx->ctrlr_attached = true;
|
|
|
|
|
2021-11-28 15:20:29 +00:00
|
|
|
rc = nvme_ctrlr_create(ctrlr, ctx->base_name, &ctx->trid, ctx);
|
2021-08-18 10:23:44 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
populate_namespaces_cb(ctx, 0, rc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
connect_set_failover_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr,
|
|
|
|
const struct spdk_nvme_ctrlr_opts *opts)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_ctrlr_opts *user_opts = cb_ctx;
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr;
|
2020-11-27 17:38:18 +00:00
|
|
|
struct nvme_async_probe_ctx *ctx;
|
2021-06-13 19:56:22 +00:00
|
|
|
int rc;
|
2020-06-25 17:06:56 +00:00
|
|
|
|
2022-03-08 08:56:35 +00:00
|
|
|
ctx = SPDK_CONTAINEROF(user_opts, struct nvme_async_probe_ctx, drv_opts);
|
2021-01-07 07:41:32 +00:00
|
|
|
ctx->ctrlr_attached = true;
|
2020-11-27 17:38:18 +00:00
|
|
|
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr = nvme_ctrlr_get_by_name(ctx->base_name);
|
|
|
|
if (nvme_ctrlr) {
|
|
|
|
rc = bdev_nvme_add_secondary_trid(nvme_ctrlr, ctrlr, &ctx->trid);
|
2021-06-13 19:56:22 +00:00
|
|
|
} else {
|
2021-08-18 10:23:44 +00:00
|
|
|
rc = -ENODEV;
|
2020-06-25 17:06:56 +00:00
|
|
|
}
|
|
|
|
|
2021-06-13 19:56:22 +00:00
|
|
|
populate_namespaces_cb(ctx, 0, rc);
|
2020-11-27 17:38:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bdev_nvme_async_poll(void *arg)
|
|
|
|
{
|
|
|
|
struct nvme_async_probe_ctx *ctx = arg;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = spdk_nvme_probe_poll_async(ctx->probe_ctx);
|
2021-01-07 07:41:32 +00:00
|
|
|
if (spdk_unlikely(rc != -EAGAIN)) {
|
|
|
|
ctx->probe_done = true;
|
2020-11-27 17:38:18 +00:00
|
|
|
spdk_poller_unregister(&ctx->poller);
|
2021-01-07 07:41:32 +00:00
|
|
|
if (!ctx->ctrlr_attached) {
|
|
|
|
/* The probe is done, but no controller was attached.
|
|
|
|
* That means we had a failure, so report -EIO back to
|
|
|
|
* the caller (usually the RPC). populate_namespaces_cb()
|
|
|
|
* will take care of freeing the nvme_async_probe_ctx.
|
|
|
|
*/
|
|
|
|
populate_namespaces_cb(ctx, 0, -EIO);
|
|
|
|
} else if (ctx->namespaces_populated) {
|
|
|
|
/* The namespaces for the attached controller were all
|
|
|
|
* populated and the response was already sent to the
|
|
|
|
* caller (usually the RPC). So free the context here.
|
|
|
|
*/
|
|
|
|
free(ctx);
|
|
|
|
}
|
2020-06-25 17:06:56 +00:00
|
|
|
}
|
|
|
|
|
2020-11-27 17:38:18 +00:00
|
|
|
return SPDK_POLLER_BUSY;
|
2020-06-25 17:06:56 +00:00
|
|
|
}
|
|
|
|
|
2022-01-13 07:03:36 +00:00
|
|
|
static bool
|
2022-03-28 02:06:42 +00:00
|
|
|
bdev_nvme_check_io_error_resiliency_params(int32_t ctrlr_loss_timeout_sec,
|
|
|
|
uint32_t reconnect_delay_sec,
|
|
|
|
uint32_t fast_io_fail_timeout_sec)
|
2022-01-13 07:03:36 +00:00
|
|
|
{
|
|
|
|
if (ctrlr_loss_timeout_sec < -1) {
|
|
|
|
SPDK_ERRLOG("ctrlr_loss_timeout_sec can't be less than -1.\n");
|
|
|
|
return false;
|
|
|
|
} else if (ctrlr_loss_timeout_sec == -1) {
|
|
|
|
if (reconnect_delay_sec == 0) {
|
|
|
|
SPDK_ERRLOG("reconnect_delay_sec can't be 0 if ctrlr_loss_timeout_sec is not 0.\n");
|
|
|
|
return false;
|
2022-01-14 02:02:31 +00:00
|
|
|
} else if (fast_io_fail_timeout_sec != 0 &&
|
|
|
|
fast_io_fail_timeout_sec < reconnect_delay_sec) {
|
|
|
|
SPDK_ERRLOG("reconnect_delay_sec can't be more than fast_io-fail_timeout_sec.\n");
|
|
|
|
return false;
|
2022-01-13 07:03:36 +00:00
|
|
|
}
|
|
|
|
} else if (ctrlr_loss_timeout_sec != 0) {
|
|
|
|
if (reconnect_delay_sec == 0) {
|
|
|
|
SPDK_ERRLOG("reconnect_delay_sec can't be 0 if ctrlr_loss_timeout_sec is not 0.\n");
|
|
|
|
return false;
|
|
|
|
} else if (reconnect_delay_sec > (uint32_t)ctrlr_loss_timeout_sec) {
|
|
|
|
SPDK_ERRLOG("reconnect_delay_sec can't be more than ctrlr_loss_timeout_sec.\n");
|
|
|
|
return false;
|
2022-01-14 02:02:31 +00:00
|
|
|
} else if (fast_io_fail_timeout_sec != 0) {
|
|
|
|
if (fast_io_fail_timeout_sec < reconnect_delay_sec) {
|
|
|
|
SPDK_ERRLOG("reconnect_delay_sec can't be more than fast_io_fail_timeout_sec.\n");
|
|
|
|
return false;
|
|
|
|
} else if (fast_io_fail_timeout_sec > (uint32_t)ctrlr_loss_timeout_sec) {
|
|
|
|
SPDK_ERRLOG("fast_io_fail_timeout_sec can't be more than ctrlr_loss_timeout_sec.\n");
|
|
|
|
return false;
|
|
|
|
}
|
2022-01-13 07:03:36 +00:00
|
|
|
}
|
2022-01-14 02:02:31 +00:00
|
|
|
} else if (reconnect_delay_sec != 0 || fast_io_fail_timeout_sec != 0) {
|
|
|
|
SPDK_ERRLOG("Both reconnect_delay_sec and fast_io_fail_timeout_sec must be 0 if ctrlr_loss_timeout_sec is 0.\n");
|
2022-01-13 07:03:36 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-10-10 03:54:38 +00:00
|
|
|
int
|
2020-05-10 07:46:07 +00:00
|
|
|
bdev_nvme_create(struct spdk_nvme_transport_id *trid,
|
|
|
|
const char *base_name,
|
|
|
|
const char **names,
|
|
|
|
uint32_t count,
|
|
|
|
spdk_bdev_create_nvme_fn cb_fn,
|
2021-01-21 11:53:16 +00:00
|
|
|
void *cb_ctx,
|
2022-03-08 08:56:35 +00:00
|
|
|
struct spdk_nvme_ctrlr_opts *drv_opts,
|
2022-03-04 04:51:53 +00:00
|
|
|
struct nvme_ctrlr_opts *bdev_opts,
|
|
|
|
bool multipath)
|
2016-10-10 03:54:38 +00:00
|
|
|
{
|
2019-02-13 05:08:22 +00:00
|
|
|
struct nvme_probe_skip_entry *entry, *tmp;
|
2019-03-05 07:26:58 +00:00
|
|
|
struct nvme_async_probe_ctx *ctx;
|
2021-08-18 10:23:44 +00:00
|
|
|
spdk_nvme_attach_cb attach_cb;
|
2016-10-25 23:19:53 +00:00
|
|
|
|
2020-09-24 01:47:54 +00:00
|
|
|
/* TODO expand this check to include both the host and target TRIDs.
|
|
|
|
* Only if both are the same should we fail.
|
|
|
|
*/
|
2021-07-06 19:42:41 +00:00
|
|
|
if (nvme_ctrlr_get(trid) != NULL) {
|
2020-09-24 01:47:54 +00:00
|
|
|
SPDK_ERRLOG("A controller with the provided trid (traddr: %s) already exists.\n", trid->traddr);
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
|
2022-03-04 04:51:53 +00:00
|
|
|
if (bdev_opts != NULL &&
|
2022-03-28 02:06:42 +00:00
|
|
|
!bdev_nvme_check_io_error_resiliency_params(bdev_opts->ctrlr_loss_timeout_sec,
|
|
|
|
bdev_opts->reconnect_delay_sec,
|
|
|
|
bdev_opts->fast_io_fail_timeout_sec)) {
|
2022-01-13 07:03:36 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-09-24 01:54:00 +00:00
|
|
|
ctx = calloc(1, sizeof(*ctx));
|
|
|
|
if (!ctx) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
ctx->base_name = base_name;
|
|
|
|
ctx->names = names;
|
|
|
|
ctx->count = count;
|
|
|
|
ctx->cb_fn = cb_fn;
|
|
|
|
ctx->cb_ctx = cb_ctx;
|
|
|
|
ctx->trid = *trid;
|
2022-03-04 04:51:53 +00:00
|
|
|
|
|
|
|
if (bdev_opts) {
|
|
|
|
memcpy(&ctx->bdev_opts, bdev_opts, sizeof(*bdev_opts));
|
2022-03-09 12:04:14 +00:00
|
|
|
} else {
|
|
|
|
bdev_nvme_get_default_ctrlr_opts(&ctx->bdev_opts);
|
2022-03-04 04:51:53 +00:00
|
|
|
}
|
2020-09-24 01:54:00 +00:00
|
|
|
|
2019-02-13 05:08:22 +00:00
|
|
|
if (trid->trtype == SPDK_NVME_TRANSPORT_PCIE) {
|
|
|
|
TAILQ_FOREACH_SAFE(entry, &g_skipped_nvme_ctrlrs, tailq, tmp) {
|
|
|
|
if (spdk_nvme_transport_id_compare(trid, &entry->trid) == 0) {
|
|
|
|
TAILQ_REMOVE(&g_skipped_nvme_ctrlrs, entry, tailq);
|
|
|
|
free(entry);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-08 08:56:35 +00:00
|
|
|
if (drv_opts) {
|
|
|
|
memcpy(&ctx->drv_opts, drv_opts, sizeof(*drv_opts));
|
2021-01-21 11:53:16 +00:00
|
|
|
} else {
|
2022-03-08 08:56:35 +00:00
|
|
|
spdk_nvme_ctrlr_get_default_ctrlr_opts(&ctx->drv_opts, sizeof(ctx->drv_opts));
|
2021-01-21 11:53:16 +00:00
|
|
|
}
|
|
|
|
|
2022-03-08 08:56:35 +00:00
|
|
|
ctx->drv_opts.transport_retry_count = g_opts.transport_retry_count;
|
|
|
|
ctx->drv_opts.transport_ack_timeout = g_opts.transport_ack_timeout;
|
|
|
|
ctx->drv_opts.keep_alive_timeout_ms = g_opts.keep_alive_timeout_ms;
|
|
|
|
ctx->drv_opts.disable_read_ana_log_page = true;
|
2022-12-14 20:24:27 +00:00
|
|
|
ctx->drv_opts.transport_tos = g_opts.transport_tos;
|
2018-12-18 23:09:14 +00:00
|
|
|
|
2021-11-10 02:05:00 +00:00
|
|
|
if (nvme_bdev_ctrlr_get_by_name(base_name) == NULL || multipath) {
|
2021-08-18 10:23:44 +00:00
|
|
|
attach_cb = connect_attach_cb;
|
|
|
|
} else {
|
|
|
|
attach_cb = connect_set_failover_cb;
|
|
|
|
}
|
|
|
|
|
2022-03-08 08:56:35 +00:00
|
|
|
ctx->probe_ctx = spdk_nvme_connect_async(trid, &ctx->drv_opts, attach_cb);
|
2019-03-05 07:26:58 +00:00
|
|
|
if (ctx->probe_ctx == NULL) {
|
|
|
|
SPDK_ERRLOG("No controller was found with provided trid (traddr: %s)\n", trid->traddr);
|
|
|
|
free(ctx);
|
2019-07-15 11:07:12 +00:00
|
|
|
return -ENODEV;
|
2017-05-01 23:54:11 +00:00
|
|
|
}
|
2020-04-14 06:49:46 +00:00
|
|
|
ctx->poller = SPDK_POLLER_REGISTER(bdev_nvme_async_poll, ctx, 1000);
|
2017-05-01 23:54:11 +00:00
|
|
|
|
2019-03-05 07:26:58 +00:00
|
|
|
return 0;
|
2016-10-10 03:54:38 +00:00
|
|
|
}
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2020-11-27 17:38:18 +00:00
|
|
|
int
|
2021-10-11 19:29:36 +00:00
|
|
|
bdev_nvme_delete(const char *name, const struct nvme_path_id *path_id)
|
2020-11-27 17:38:18 +00:00
|
|
|
{
|
2021-09-07 16:13:07 +00:00
|
|
|
struct nvme_bdev_ctrlr *nbdev_ctrlr;
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr, *tmp_nvme_ctrlr;
|
2021-10-11 19:29:36 +00:00
|
|
|
struct nvme_path_id *p, *t;
|
2021-09-22 18:56:56 +00:00
|
|
|
int rc = -ENXIO;
|
2020-11-27 17:38:18 +00:00
|
|
|
|
2021-10-11 19:29:36 +00:00
|
|
|
if (name == NULL || path_id == NULL) {
|
2020-11-27 17:38:18 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-11-10 02:05:00 +00:00
|
|
|
nbdev_ctrlr = nvme_bdev_ctrlr_get_by_name(name);
|
2021-09-07 16:13:07 +00:00
|
|
|
if (nbdev_ctrlr == NULL) {
|
|
|
|
SPDK_ERRLOG("Failed to find NVMe bdev controller\n");
|
2020-11-27 17:38:18 +00:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
TAILQ_FOREACH_SAFE(nvme_ctrlr, &nbdev_ctrlr->ctrlrs, tailq, tmp_nvme_ctrlr) {
|
2021-10-11 19:29:36 +00:00
|
|
|
TAILQ_FOREACH_REVERSE_SAFE(p, &nvme_ctrlr->trids, nvme_paths, link, t) {
|
|
|
|
if (path_id->trid.trtype != 0) {
|
|
|
|
if (path_id->trid.trtype == SPDK_NVME_TRANSPORT_CUSTOM) {
|
|
|
|
if (strcasecmp(path_id->trid.trstring, p->trid.trstring) != 0) {
|
2021-09-22 18:56:56 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
2021-10-11 19:29:36 +00:00
|
|
|
if (path_id->trid.trtype != p->trid.trtype) {
|
2021-09-22 18:56:56 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 19:29:36 +00:00
|
|
|
if (!spdk_mem_all_zero(path_id->trid.traddr, sizeof(path_id->trid.traddr))) {
|
|
|
|
if (strcasecmp(path_id->trid.traddr, p->trid.traddr) != 0) {
|
2021-09-22 18:56:56 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 19:29:36 +00:00
|
|
|
if (path_id->trid.adrfam != 0) {
|
|
|
|
if (path_id->trid.adrfam != p->trid.adrfam) {
|
2021-09-22 18:56:56 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 19:29:36 +00:00
|
|
|
if (!spdk_mem_all_zero(path_id->trid.trsvcid, sizeof(path_id->trid.trsvcid))) {
|
|
|
|
if (strcasecmp(path_id->trid.trsvcid, p->trid.trsvcid) != 0) {
|
2021-09-22 18:56:56 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 19:29:36 +00:00
|
|
|
if (!spdk_mem_all_zero(path_id->trid.subnqn, sizeof(path_id->trid.subnqn))) {
|
|
|
|
if (strcmp(path_id->trid.subnqn, p->trid.subnqn) != 0) {
|
2021-09-22 18:56:56 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 20:35:39 +00:00
|
|
|
if (!spdk_mem_all_zero(path_id->hostid.hostaddr, sizeof(path_id->hostid.hostaddr))) {
|
|
|
|
if (strcmp(path_id->hostid.hostaddr, p->hostid.hostaddr) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!spdk_mem_all_zero(path_id->hostid.hostsvcid, sizeof(path_id->hostid.hostsvcid))) {
|
|
|
|
if (strcmp(path_id->hostid.hostsvcid, p->hostid.hostsvcid) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-22 18:56:56 +00:00
|
|
|
/* If we made it here, then this path is a match! Now we need to remove it. */
|
2021-10-11 19:29:36 +00:00
|
|
|
if (p == nvme_ctrlr->active_path_id) {
|
2021-09-22 18:56:56 +00:00
|
|
|
/* This is the active path in use right now. The active path is always the first in the list. */
|
|
|
|
|
2021-10-11 19:29:36 +00:00
|
|
|
if (!TAILQ_NEXT(p, link)) {
|
2021-09-22 18:56:56 +00:00
|
|
|
/* The current path is the only path. */
|
|
|
|
rc = _bdev_nvme_delete(nvme_ctrlr, false);
|
|
|
|
} else {
|
|
|
|
/* There is an alternative path. */
|
|
|
|
rc = bdev_nvme_failover(nvme_ctrlr, true);
|
|
|
|
}
|
2021-09-07 16:13:07 +00:00
|
|
|
} else {
|
2021-09-22 18:56:56 +00:00
|
|
|
/* We are not using the specified path. */
|
2021-10-11 19:39:22 +00:00
|
|
|
TAILQ_REMOVE(&nvme_ctrlr->trids, p, link);
|
|
|
|
free(p);
|
|
|
|
rc = 0;
|
2021-09-07 16:13:07 +00:00
|
|
|
}
|
2021-09-22 18:56:56 +00:00
|
|
|
|
|
|
|
if (rc < 0 && rc != -ENXIO) {
|
2021-09-07 16:13:07 +00:00
|
|
|
return rc;
|
|
|
|
}
|
2021-09-22 18:56:56 +00:00
|
|
|
|
|
|
|
|
2020-11-27 17:38:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
/* All nvme_ctrlrs were deleted or no nvme_ctrlr which had the trid was found. */
|
|
|
|
return rc;
|
2020-11-27 17:38:18 +00:00
|
|
|
}
|
|
|
|
|
2022-03-10 18:50:44 +00:00
|
|
|
#define DISCOVERY_INFOLOG(ctx, format, ...) \
|
|
|
|
SPDK_INFOLOG(bdev_nvme, "Discovery[%s:%s] " format, ctx->trid.traddr, ctx->trid.trsvcid, ##__VA_ARGS__);
|
2022-02-24 15:20:20 +00:00
|
|
|
|
|
|
|
#define DISCOVERY_ERRLOG(ctx, format, ...) \
|
|
|
|
SPDK_ERRLOG("Discovery[%s:%s] " format, ctx->trid.traddr, ctx->trid.trsvcid, ##__VA_ARGS__);
|
|
|
|
|
2022-02-10 13:27:07 +00:00
|
|
|
struct discovery_entry_ctx {
|
2021-12-07 22:43:07 +00:00
|
|
|
char name[128];
|
|
|
|
struct spdk_nvme_transport_id trid;
|
2022-03-08 08:56:35 +00:00
|
|
|
struct spdk_nvme_ctrlr_opts drv_opts;
|
2021-12-07 22:43:07 +00:00
|
|
|
struct spdk_nvmf_discovery_log_page_entry entry;
|
2022-02-10 13:27:07 +00:00
|
|
|
TAILQ_ENTRY(discovery_entry_ctx) tailq;
|
2021-12-07 22:43:07 +00:00
|
|
|
struct discovery_ctx *ctx;
|
|
|
|
};
|
|
|
|
|
2021-12-04 05:49:54 +00:00
|
|
|
struct discovery_ctx {
|
2021-12-07 22:43:07 +00:00
|
|
|
char *name;
|
2022-03-25 19:08:00 +00:00
|
|
|
spdk_bdev_nvme_start_discovery_fn start_cb_fn;
|
2021-12-04 05:49:54 +00:00
|
|
|
spdk_bdev_nvme_stop_discovery_fn stop_cb_fn;
|
|
|
|
void *cb_ctx;
|
|
|
|
struct spdk_nvme_probe_ctx *probe_ctx;
|
|
|
|
struct spdk_nvme_detach_ctx *detach_ctx;
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr;
|
2022-02-24 14:52:47 +00:00
|
|
|
struct spdk_nvme_transport_id trid;
|
2022-02-25 01:26:48 +00:00
|
|
|
struct discovery_entry_ctx *entry_ctx_in_use;
|
2021-12-04 05:49:54 +00:00
|
|
|
struct spdk_poller *poller;
|
2022-03-08 08:56:35 +00:00
|
|
|
struct spdk_nvme_ctrlr_opts drv_opts;
|
2022-03-12 05:02:11 +00:00
|
|
|
struct nvme_ctrlr_opts bdev_opts;
|
2022-02-25 00:22:54 +00:00
|
|
|
struct spdk_nvmf_discovery_log_page *log_page;
|
2021-12-04 05:49:54 +00:00
|
|
|
TAILQ_ENTRY(discovery_ctx) tailq;
|
2022-02-10 13:27:07 +00:00
|
|
|
TAILQ_HEAD(, discovery_entry_ctx) nvm_entry_ctxs;
|
2022-02-24 13:28:01 +00:00
|
|
|
TAILQ_HEAD(, discovery_entry_ctx) discovery_entry_ctxs;
|
2021-12-04 05:49:54 +00:00
|
|
|
int rc;
|
2022-03-25 19:08:00 +00:00
|
|
|
bool wait_for_attach;
|
2022-05-12 09:52:58 +00:00
|
|
|
uint64_t timeout_ticks;
|
|
|
|
/* Denotes that the discovery service is being started. We're waiting
|
|
|
|
* for the initial connection to the discovery controller to be
|
|
|
|
* established and attach discovered NVM ctrlrs.
|
|
|
|
*/
|
|
|
|
bool initializing;
|
2021-12-04 05:49:54 +00:00
|
|
|
/* Denotes if a discovery is currently in progress for this context.
|
|
|
|
* That includes connecting to newly discovered subsystems. Used to
|
|
|
|
* ensure we do not start a new discovery until an existing one is
|
|
|
|
* complete.
|
|
|
|
*/
|
|
|
|
bool in_progress;
|
|
|
|
|
|
|
|
/* Denotes if another discovery is needed after the one in progress
|
|
|
|
* completes. Set when we receive an AER completion while a discovery
|
|
|
|
* is already in progress.
|
|
|
|
*/
|
|
|
|
bool pending;
|
|
|
|
|
2022-02-25 01:52:41 +00:00
|
|
|
/* Signal to the discovery context poller that it should stop the
|
|
|
|
* discovery service, including detaching from the current discovery
|
|
|
|
* controller.
|
2021-12-04 05:49:54 +00:00
|
|
|
*/
|
2022-02-25 01:52:41 +00:00
|
|
|
bool stop;
|
2021-12-04 05:49:54 +00:00
|
|
|
|
|
|
|
struct spdk_thread *calling_thread;
|
2021-12-07 22:43:07 +00:00
|
|
|
uint32_t index;
|
|
|
|
uint32_t attach_in_progress;
|
|
|
|
char *hostnqn;
|
nvme: Added support for TP-8009, Auto-discovery of Discovery controllers for NVME initiator using mDNS using Avahi
Approach:
Avahi Daemon needs to be running to provide the mDNS server service. In the SPDK, Avahi-client library based client API is implemented.
The client API will connect to the Avahi-daemon and receive events for new discovery and removal of an existing discovery entry.
Following sets on new RPCs have been introduced.
scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
User shall initiate an mDNS based discovery using this RPC. This will start a Avahi-client based poller
looking for new discovery events from the Avahi server. On a new discovery of the discovery controller,
the existing bdev_nvme_start_discovery API will be invoked with the trid of the discovery controller learnt.
This will enable automatic connection of the initiator to the subsystems discovered from the discovery controller.
Multiple mdns discovery instances can be run by specifying a unique bdev-prefix and a unique servicename to discover as parameters.
scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
This will stop the Avahi poller that was started for the specified service.Internally bdev_nvme_stop_discovery
API will be invoked for each of the discovery controllers learnt automatically by this instance of mdns discovery service.
This will result in termination of connections to all the subsystems learnt by this mdns discovery instance.
scripts/rpc.py bdev_nvme_get_mdns_discovery_info
This RPC will display the list of mdns discovery instances running and the trid of the controllers discovered by these instances.
Test Result:
root@ubuntu-pm-18-226:~/param-spdk/spdk/build/bin# ./nvmf_tgt -i 1 -s 2048 -m 0xF
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[
{
"name": "cdc_auto",
"svcname": "_nvme-disc._tcp",
"referrals": [
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
}
]
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[
{
"name": "cdc_auto02n1",
"aliases": [
"600110d6-1681-1681-0403-000045805c45"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-1681-1681-0403-000045805c45",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T0",
"serial_number": "00-681681dc681681dc",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto00n1",
"aliases": [
"600110da-09a6-09a6-0302-00005eeb19b4"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 2048,
"uuid": "600110da-09a6-09a6-0302-00005eeb19b4",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0"
},
"ctrlr_data": {
"cntlid": 1,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P2T0",
"serial_number": "00-ab09a6f5ab09a6f5",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n1",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8c"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8c",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n2",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8d"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8d",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 2,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
Signed-off-by: Parameswaran Krishnamurthy <parameswaran.krishna@dell.com>
Change-Id: Ic2c2e614e2549a655c7f81ae844b80d8505a4f02
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15703
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Boris Glimcher <Boris.Glimcher@emc.com>
Reviewed-by: <qun.wan@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
2022-11-30 20:11:23 +00:00
|
|
|
|
|
|
|
/* Denotes if the discovery service was started by the mdns discovery.
|
|
|
|
*/
|
|
|
|
bool from_mdns_discovery_service;
|
2021-12-04 05:49:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
TAILQ_HEAD(discovery_ctxs, discovery_ctx);
|
|
|
|
static struct discovery_ctxs g_discovery_ctxs = TAILQ_HEAD_INITIALIZER(g_discovery_ctxs);
|
|
|
|
|
|
|
|
static void get_discovery_log_page(struct discovery_ctx *ctx);
|
|
|
|
|
2021-12-07 22:43:07 +00:00
|
|
|
static void
|
|
|
|
free_discovery_ctx(struct discovery_ctx *ctx)
|
|
|
|
{
|
2022-05-17 12:03:54 +00:00
|
|
|
free(ctx->log_page);
|
2021-12-07 22:43:07 +00:00
|
|
|
free(ctx->hostnqn);
|
|
|
|
free(ctx->name);
|
|
|
|
free(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
discovery_complete(struct discovery_ctx *ctx)
|
|
|
|
{
|
2022-05-12 09:52:58 +00:00
|
|
|
ctx->initializing = false;
|
2021-12-07 22:43:07 +00:00
|
|
|
ctx->in_progress = false;
|
|
|
|
if (ctx->pending) {
|
|
|
|
ctx->pending = false;
|
|
|
|
get_discovery_log_page(ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
build_trid_from_log_page_entry(struct spdk_nvme_transport_id *trid,
|
|
|
|
struct spdk_nvmf_discovery_log_page_entry *entry)
|
|
|
|
{
|
|
|
|
char *space;
|
|
|
|
|
|
|
|
trid->trtype = entry->trtype;
|
|
|
|
trid->adrfam = entry->adrfam;
|
2022-12-13 06:46:03 +00:00
|
|
|
memcpy(trid->traddr, entry->traddr, sizeof(entry->traddr));
|
|
|
|
memcpy(trid->trsvcid, entry->trsvcid, sizeof(entry->trsvcid));
|
2021-12-07 22:43:07 +00:00
|
|
|
memcpy(trid->subnqn, entry->subnqn, sizeof(trid->subnqn));
|
|
|
|
|
|
|
|
/* We want the traddr, trsvcid and subnqn fields to be NULL-terminated.
|
|
|
|
* But the log page entries typically pad them with spaces, not zeroes.
|
|
|
|
* So add a NULL terminator to each of these fields at the appropriate
|
|
|
|
* location.
|
|
|
|
*/
|
|
|
|
space = strchr(trid->traddr, ' ');
|
|
|
|
if (space) {
|
|
|
|
*space = 0;
|
|
|
|
}
|
|
|
|
space = strchr(trid->trsvcid, ' ');
|
|
|
|
if (space) {
|
|
|
|
*space = 0;
|
|
|
|
}
|
|
|
|
space = strchr(trid->subnqn, ' ');
|
|
|
|
if (space) {
|
|
|
|
*space = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-11 15:37:23 +00:00
|
|
|
static void
|
|
|
|
stop_discovery(struct discovery_ctx *ctx, spdk_bdev_nvme_stop_discovery_fn cb_fn, void *cb_ctx)
|
|
|
|
{
|
|
|
|
ctx->stop = true;
|
|
|
|
ctx->stop_cb_fn = cb_fn;
|
|
|
|
ctx->cb_ctx = cb_ctx;
|
|
|
|
|
|
|
|
while (!TAILQ_EMPTY(&ctx->nvm_entry_ctxs)) {
|
|
|
|
struct discovery_entry_ctx *entry_ctx;
|
|
|
|
struct nvme_path_id path = {};
|
|
|
|
|
|
|
|
entry_ctx = TAILQ_FIRST(&ctx->nvm_entry_ctxs);
|
|
|
|
path.trid = entry_ctx->trid;
|
|
|
|
bdev_nvme_delete(entry_ctx->name, &path);
|
|
|
|
TAILQ_REMOVE(&ctx->nvm_entry_ctxs, entry_ctx, tailq);
|
|
|
|
free(entry_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!TAILQ_EMPTY(&ctx->discovery_entry_ctxs)) {
|
|
|
|
struct discovery_entry_ctx *entry_ctx;
|
|
|
|
|
|
|
|
entry_ctx = TAILQ_FIRST(&ctx->discovery_entry_ctxs);
|
|
|
|
TAILQ_REMOVE(&ctx->discovery_entry_ctxs, entry_ctx, tailq);
|
|
|
|
free(entry_ctx);
|
|
|
|
}
|
2022-05-12 13:51:56 +00:00
|
|
|
|
|
|
|
free(ctx->entry_ctx_in_use);
|
|
|
|
ctx->entry_ctx_in_use = NULL;
|
2022-05-11 15:37:23 +00:00
|
|
|
}
|
|
|
|
|
2021-12-07 22:43:07 +00:00
|
|
|
static void
|
2022-02-25 00:22:54 +00:00
|
|
|
discovery_remove_controllers(struct discovery_ctx *ctx)
|
2021-12-04 05:49:54 +00:00
|
|
|
{
|
2022-02-25 00:22:54 +00:00
|
|
|
struct spdk_nvmf_discovery_log_page *log_page = ctx->log_page;
|
2022-02-10 13:27:07 +00:00
|
|
|
struct discovery_entry_ctx *entry_ctx, *tmp;
|
2021-12-07 22:43:07 +00:00
|
|
|
struct spdk_nvmf_discovery_log_page_entry *new_entry, *old_entry;
|
2022-02-24 14:48:33 +00:00
|
|
|
struct spdk_nvme_transport_id old_trid;
|
2021-12-07 22:43:07 +00:00
|
|
|
uint64_t numrec, i;
|
|
|
|
bool found;
|
2021-12-04 05:49:54 +00:00
|
|
|
|
2021-12-07 22:43:07 +00:00
|
|
|
numrec = from_le64(&log_page->numrec);
|
2022-02-10 13:27:07 +00:00
|
|
|
TAILQ_FOREACH_SAFE(entry_ctx, &ctx->nvm_entry_ctxs, tailq, tmp) {
|
2021-12-07 22:43:07 +00:00
|
|
|
found = false;
|
2022-02-10 13:27:07 +00:00
|
|
|
old_entry = &entry_ctx->entry;
|
2022-02-24 14:48:33 +00:00
|
|
|
build_trid_from_log_page_entry(&old_trid, old_entry);
|
2021-12-07 22:43:07 +00:00
|
|
|
for (i = 0; i < numrec; i++) {
|
|
|
|
new_entry = &log_page->entries[i];
|
|
|
|
if (!memcmp(old_entry, new_entry, sizeof(*old_entry))) {
|
2022-03-10 18:50:44 +00:00
|
|
|
DISCOVERY_INFOLOG(ctx, "NVM %s:%s:%s found again\n",
|
|
|
|
old_trid.subnqn, old_trid.traddr, old_trid.trsvcid);
|
2021-12-07 22:43:07 +00:00
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
struct nvme_path_id path = {};
|
|
|
|
|
2022-03-10 18:50:44 +00:00
|
|
|
DISCOVERY_INFOLOG(ctx, "NVM %s:%s:%s not found\n",
|
|
|
|
old_trid.subnqn, old_trid.traddr, old_trid.trsvcid);
|
2021-12-07 22:43:07 +00:00
|
|
|
|
2022-02-10 13:27:07 +00:00
|
|
|
path.trid = entry_ctx->trid;
|
|
|
|
bdev_nvme_delete(entry_ctx->name, &path);
|
|
|
|
TAILQ_REMOVE(&ctx->nvm_entry_ctxs, entry_ctx, tailq);
|
|
|
|
free(entry_ctx);
|
2021-12-07 22:43:07 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-25 00:22:54 +00:00
|
|
|
free(log_page);
|
|
|
|
ctx->log_page = NULL;
|
|
|
|
discovery_complete(ctx);
|
|
|
|
}
|
|
|
|
|
2022-05-12 09:52:58 +00:00
|
|
|
static void
|
|
|
|
complete_discovery_start(struct discovery_ctx *ctx, int status)
|
|
|
|
{
|
|
|
|
ctx->timeout_ticks = 0;
|
|
|
|
ctx->rc = status;
|
|
|
|
if (ctx->start_cb_fn) {
|
|
|
|
ctx->start_cb_fn(ctx->cb_ctx, status);
|
|
|
|
ctx->start_cb_fn = NULL;
|
|
|
|
ctx->cb_ctx = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-25 00:22:54 +00:00
|
|
|
static void
|
|
|
|
discovery_attach_controller_done(void *cb_ctx, size_t bdev_count, int rc)
|
|
|
|
{
|
|
|
|
struct discovery_entry_ctx *entry_ctx = cb_ctx;
|
2022-05-12 09:52:58 +00:00
|
|
|
struct discovery_ctx *ctx = entry_ctx->ctx;
|
2022-02-25 00:22:54 +00:00
|
|
|
|
2022-03-10 18:50:44 +00:00
|
|
|
DISCOVERY_INFOLOG(ctx, "attach %s done\n", entry_ctx->name);
|
2022-02-25 00:22:54 +00:00
|
|
|
ctx->attach_in_progress--;
|
|
|
|
if (ctx->attach_in_progress == 0) {
|
2022-05-12 09:52:58 +00:00
|
|
|
complete_discovery_start(ctx, ctx->rc);
|
|
|
|
if (ctx->initializing && ctx->rc != 0) {
|
|
|
|
DISCOVERY_ERRLOG(ctx, "stopping discovery due to errors: %d\n", ctx->rc);
|
|
|
|
stop_discovery(ctx, NULL, ctx->cb_ctx);
|
|
|
|
} else {
|
|
|
|
discovery_remove_controllers(ctx);
|
2022-03-25 19:08:00 +00:00
|
|
|
}
|
2022-02-25 00:22:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-25 01:16:40 +00:00
|
|
|
static struct discovery_entry_ctx *
|
|
|
|
create_discovery_entry_ctx(struct discovery_ctx *ctx, struct spdk_nvme_transport_id *trid)
|
|
|
|
{
|
|
|
|
struct discovery_entry_ctx *new_ctx;
|
|
|
|
|
|
|
|
new_ctx = calloc(1, sizeof(*new_ctx));
|
|
|
|
if (new_ctx == NULL) {
|
|
|
|
DISCOVERY_ERRLOG(ctx, "could not allocate new entry_ctx\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_ctx->ctx = ctx;
|
|
|
|
memcpy(&new_ctx->trid, trid, sizeof(*trid));
|
|
|
|
spdk_nvme_ctrlr_get_default_ctrlr_opts(&new_ctx->drv_opts, sizeof(new_ctx->drv_opts));
|
|
|
|
snprintf(new_ctx->drv_opts.hostnqn, sizeof(new_ctx->drv_opts.hostnqn), "%s", ctx->hostnqn);
|
|
|
|
return new_ctx;
|
|
|
|
}
|
|
|
|
|
2022-02-25 00:22:54 +00:00
|
|
|
static void
|
|
|
|
discovery_log_page_cb(void *cb_arg, int rc, const struct spdk_nvme_cpl *cpl,
|
|
|
|
struct spdk_nvmf_discovery_log_page *log_page)
|
|
|
|
{
|
|
|
|
struct discovery_ctx *ctx = cb_arg;
|
|
|
|
struct discovery_entry_ctx *entry_ctx, *tmp;
|
|
|
|
struct spdk_nvmf_discovery_log_page_entry *new_entry, *old_entry;
|
|
|
|
uint64_t numrec, i;
|
|
|
|
bool found;
|
|
|
|
|
|
|
|
if (rc || spdk_nvme_cpl_is_error(cpl)) {
|
|
|
|
DISCOVERY_ERRLOG(ctx, "could not get discovery log page\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->log_page = log_page;
|
|
|
|
assert(ctx->attach_in_progress == 0);
|
|
|
|
numrec = from_le64(&log_page->numrec);
|
2022-02-24 13:28:01 +00:00
|
|
|
TAILQ_FOREACH_SAFE(entry_ctx, &ctx->discovery_entry_ctxs, tailq, tmp) {
|
|
|
|
TAILQ_REMOVE(&ctx->discovery_entry_ctxs, entry_ctx, tailq);
|
|
|
|
free(entry_ctx);
|
|
|
|
}
|
2021-12-07 22:43:07 +00:00
|
|
|
for (i = 0; i < numrec; i++) {
|
|
|
|
found = false;
|
|
|
|
new_entry = &log_page->entries[i];
|
2022-02-10 13:07:31 +00:00
|
|
|
if (new_entry->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY) {
|
2022-02-24 13:28:01 +00:00
|
|
|
struct discovery_entry_ctx *new_ctx;
|
2022-05-13 09:21:04 +00:00
|
|
|
struct spdk_nvme_transport_id trid = {};
|
2022-02-24 13:28:01 +00:00
|
|
|
|
2022-02-25 01:16:40 +00:00
|
|
|
build_trid_from_log_page_entry(&trid, new_entry);
|
|
|
|
new_ctx = create_discovery_entry_ctx(ctx, &trid);
|
2022-02-24 13:28:01 +00:00
|
|
|
if (new_ctx == NULL) {
|
2022-02-24 15:20:20 +00:00
|
|
|
DISCOVERY_ERRLOG(ctx, "could not allocate new entry_ctx\n");
|
2022-02-24 13:28:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&ctx->discovery_entry_ctxs, new_ctx, tailq);
|
2022-02-10 13:07:31 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-02-10 13:27:07 +00:00
|
|
|
TAILQ_FOREACH(entry_ctx, &ctx->nvm_entry_ctxs, tailq) {
|
|
|
|
old_entry = &entry_ctx->entry;
|
2021-12-07 22:43:07 +00:00
|
|
|
if (!memcmp(new_entry, old_entry, sizeof(*new_entry))) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) {
|
2022-02-10 13:27:07 +00:00
|
|
|
struct discovery_entry_ctx *subnqn_ctx, *new_ctx;
|
2021-12-07 22:43:07 +00:00
|
|
|
|
2022-02-10 13:27:07 +00:00
|
|
|
TAILQ_FOREACH(subnqn_ctx, &ctx->nvm_entry_ctxs, tailq) {
|
2021-12-07 22:43:07 +00:00
|
|
|
if (!memcmp(subnqn_ctx->entry.subnqn, new_entry->subnqn,
|
|
|
|
sizeof(new_entry->subnqn))) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-10 13:27:07 +00:00
|
|
|
new_ctx = calloc(1, sizeof(*new_ctx));
|
2021-12-07 22:43:07 +00:00
|
|
|
if (new_ctx == NULL) {
|
2022-02-24 15:20:20 +00:00
|
|
|
DISCOVERY_ERRLOG(ctx, "could not allocate new entry_ctx\n");
|
2021-12-07 22:43:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_ctx->ctx = ctx;
|
|
|
|
memcpy(&new_ctx->entry, new_entry, sizeof(*new_entry));
|
|
|
|
build_trid_from_log_page_entry(&new_ctx->trid, new_entry);
|
|
|
|
if (subnqn_ctx) {
|
|
|
|
snprintf(new_ctx->name, sizeof(new_ctx->name), "%s", subnqn_ctx->name);
|
2022-03-10 18:50:44 +00:00
|
|
|
DISCOVERY_INFOLOG(ctx, "NVM %s:%s:%s new path for %s\n",
|
|
|
|
new_ctx->trid.subnqn, new_ctx->trid.traddr, new_ctx->trid.trsvcid,
|
|
|
|
new_ctx->name);
|
2021-12-07 22:43:07 +00:00
|
|
|
} else {
|
|
|
|
snprintf(new_ctx->name, sizeof(new_ctx->name), "%s%d", ctx->name, ctx->index++);
|
2022-03-10 18:50:44 +00:00
|
|
|
DISCOVERY_INFOLOG(ctx, "NVM %s:%s:%s new subsystem %s\n",
|
|
|
|
new_ctx->trid.subnqn, new_ctx->trid.traddr, new_ctx->trid.trsvcid,
|
|
|
|
new_ctx->name);
|
2021-12-07 22:43:07 +00:00
|
|
|
}
|
2022-03-08 08:56:35 +00:00
|
|
|
spdk_nvme_ctrlr_get_default_ctrlr_opts(&new_ctx->drv_opts, sizeof(new_ctx->drv_opts));
|
|
|
|
snprintf(new_ctx->drv_opts.hostnqn, sizeof(new_ctx->drv_opts.hostnqn), "%s", ctx->hostnqn);
|
2022-03-04 04:51:53 +00:00
|
|
|
rc = bdev_nvme_create(&new_ctx->trid, new_ctx->name, NULL, 0,
|
2021-12-07 22:43:07 +00:00
|
|
|
discovery_attach_controller_done, new_ctx,
|
2022-03-12 05:02:11 +00:00
|
|
|
&new_ctx->drv_opts, &ctx->bdev_opts, true);
|
2021-12-07 22:43:07 +00:00
|
|
|
if (rc == 0) {
|
2022-02-10 13:27:07 +00:00
|
|
|
TAILQ_INSERT_TAIL(&ctx->nvm_entry_ctxs, new_ctx, tailq);
|
2021-12-07 22:43:07 +00:00
|
|
|
ctx->attach_in_progress++;
|
|
|
|
} else {
|
2022-02-24 15:20:20 +00:00
|
|
|
DISCOVERY_ERRLOG(ctx, "bdev_nvme_create failed (%s)\n", spdk_strerror(-rc));
|
2021-12-07 22:43:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-04 05:49:54 +00:00
|
|
|
|
2021-12-07 22:43:07 +00:00
|
|
|
if (ctx->attach_in_progress == 0) {
|
2022-02-25 00:22:54 +00:00
|
|
|
discovery_remove_controllers(ctx);
|
2021-12-04 05:49:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_discovery_log_page(struct discovery_ctx *ctx)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
assert(ctx->in_progress == false);
|
|
|
|
ctx->in_progress = true;
|
|
|
|
rc = spdk_nvme_ctrlr_get_discovery_log_page(ctx->ctrlr, discovery_log_page_cb, ctx);
|
|
|
|
if (rc != 0) {
|
2022-02-24 15:20:20 +00:00
|
|
|
DISCOVERY_ERRLOG(ctx, "could not get discovery log page\n");
|
2021-12-04 05:49:54 +00:00
|
|
|
}
|
2022-03-10 18:50:44 +00:00
|
|
|
DISCOVERY_INFOLOG(ctx, "sent discovery log page command\n");
|
2021-12-04 05:49:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
discovery_aer_cb(void *arg, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
|
|
|
struct discovery_ctx *ctx = arg;
|
|
|
|
uint32_t log_page_id = (cpl->cdw0 & 0xFF0000) >> 16;
|
|
|
|
|
|
|
|
if (spdk_nvme_cpl_is_error(cpl)) {
|
2022-02-24 15:20:20 +00:00
|
|
|
DISCOVERY_ERRLOG(ctx, "aer failed\n");
|
2021-12-04 05:49:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (log_page_id != SPDK_NVME_LOG_DISCOVERY) {
|
2022-02-24 15:20:20 +00:00
|
|
|
DISCOVERY_ERRLOG(ctx, "unexpected log page 0x%x\n", log_page_id);
|
2021-12-04 05:49:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-10 18:50:44 +00:00
|
|
|
DISCOVERY_INFOLOG(ctx, "got aer\n");
|
2021-12-04 05:49:54 +00:00
|
|
|
if (ctx->in_progress) {
|
|
|
|
ctx->pending = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
get_discovery_log_page(ctx);
|
|
|
|
}
|
|
|
|
|
2022-02-24 13:08:55 +00:00
|
|
|
static void
|
|
|
|
discovery_attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_ctrlr_opts *user_opts = cb_ctx;
|
|
|
|
struct discovery_ctx *ctx;
|
|
|
|
|
2022-03-08 08:56:35 +00:00
|
|
|
ctx = SPDK_CONTAINEROF(user_opts, struct discovery_ctx, drv_opts);
|
2022-02-24 13:08:55 +00:00
|
|
|
|
2022-03-10 18:50:44 +00:00
|
|
|
DISCOVERY_INFOLOG(ctx, "discovery ctrlr attached\n");
|
2022-02-24 13:08:55 +00:00
|
|
|
ctx->probe_ctx = NULL;
|
|
|
|
ctx->ctrlr = ctrlr;
|
2022-05-12 09:52:58 +00:00
|
|
|
|
|
|
|
if (ctx->rc != 0) {
|
|
|
|
DISCOVERY_ERRLOG(ctx, "encountered error while attaching discovery ctrlr: %d\n",
|
|
|
|
ctx->rc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-24 13:08:55 +00:00
|
|
|
spdk_nvme_ctrlr_register_aer_callback(ctx->ctrlr, discovery_aer_cb, ctx);
|
|
|
|
}
|
|
|
|
|
2021-12-04 05:49:54 +00:00
|
|
|
static int
|
|
|
|
discovery_poller(void *arg)
|
|
|
|
{
|
|
|
|
struct discovery_ctx *ctx = arg;
|
2022-02-25 01:26:48 +00:00
|
|
|
struct spdk_nvme_transport_id *trid;
|
2021-12-04 05:49:54 +00:00
|
|
|
int rc;
|
|
|
|
|
2022-02-25 02:16:50 +00:00
|
|
|
if (ctx->detach_ctx) {
|
|
|
|
rc = spdk_nvme_detach_poll_async(ctx->detach_ctx);
|
|
|
|
if (rc != -EAGAIN) {
|
|
|
|
ctx->detach_ctx = NULL;
|
|
|
|
ctx->ctrlr = NULL;
|
|
|
|
}
|
|
|
|
} else if (ctx->stop) {
|
|
|
|
if (ctx->ctrlr != NULL) {
|
2021-12-04 05:49:54 +00:00
|
|
|
rc = spdk_nvme_detach_async(ctx->ctrlr, &ctx->detach_ctx);
|
2022-02-25 02:16:50 +00:00
|
|
|
if (rc == 0) {
|
|
|
|
return SPDK_POLLER_BUSY;
|
2021-12-04 05:49:54 +00:00
|
|
|
}
|
2022-02-25 02:16:50 +00:00
|
|
|
DISCOVERY_ERRLOG(ctx, "could not detach discovery ctrlr\n");
|
2021-12-04 05:49:54 +00:00
|
|
|
}
|
2022-02-25 02:16:50 +00:00
|
|
|
spdk_poller_unregister(&ctx->poller);
|
|
|
|
TAILQ_REMOVE(&g_discovery_ctxs, ctx, tailq);
|
2022-05-12 09:52:58 +00:00
|
|
|
assert(ctx->start_cb_fn == NULL);
|
|
|
|
if (ctx->stop_cb_fn != NULL) {
|
|
|
|
ctx->stop_cb_fn(ctx->cb_ctx);
|
|
|
|
}
|
2022-02-25 02:16:50 +00:00
|
|
|
free_discovery_ctx(ctx);
|
2022-02-25 00:56:04 +00:00
|
|
|
} else if (ctx->probe_ctx == NULL && ctx->ctrlr == NULL) {
|
2022-05-12 09:52:58 +00:00
|
|
|
if (ctx->timeout_ticks != 0 && ctx->timeout_ticks < spdk_get_ticks()) {
|
|
|
|
DISCOVERY_ERRLOG(ctx, "timed out while attaching discovery ctrlr\n");
|
|
|
|
assert(ctx->initializing);
|
|
|
|
spdk_poller_unregister(&ctx->poller);
|
|
|
|
TAILQ_REMOVE(&g_discovery_ctxs, ctx, tailq);
|
|
|
|
complete_discovery_start(ctx, -ETIMEDOUT);
|
|
|
|
stop_discovery(ctx, NULL, NULL);
|
|
|
|
free_discovery_ctx(ctx);
|
|
|
|
return SPDK_POLLER_BUSY;
|
|
|
|
}
|
|
|
|
|
2022-02-25 01:26:48 +00:00
|
|
|
assert(ctx->entry_ctx_in_use == NULL);
|
|
|
|
ctx->entry_ctx_in_use = TAILQ_FIRST(&ctx->discovery_entry_ctxs);
|
2022-02-24 08:17:55 +00:00
|
|
|
TAILQ_REMOVE(&ctx->discovery_entry_ctxs, ctx->entry_ctx_in_use, tailq);
|
2022-02-25 01:26:48 +00:00
|
|
|
trid = &ctx->entry_ctx_in_use->trid;
|
|
|
|
ctx->probe_ctx = spdk_nvme_connect_async(trid, &ctx->drv_opts, discovery_attach_cb);
|
2022-02-25 02:51:03 +00:00
|
|
|
if (ctx->probe_ctx) {
|
|
|
|
spdk_poller_unregister(&ctx->poller);
|
|
|
|
ctx->poller = SPDK_POLLER_REGISTER(discovery_poller, ctx, 1000);
|
|
|
|
} else {
|
2022-02-25 00:56:04 +00:00
|
|
|
DISCOVERY_ERRLOG(ctx, "could not start discovery connect\n");
|
2022-02-24 08:17:55 +00:00
|
|
|
TAILQ_INSERT_TAIL(&ctx->discovery_entry_ctxs, ctx->entry_ctx_in_use, tailq);
|
2022-02-25 01:26:48 +00:00
|
|
|
ctx->entry_ctx_in_use = NULL;
|
2022-02-25 00:56:04 +00:00
|
|
|
}
|
2022-02-25 02:00:44 +00:00
|
|
|
} else if (ctx->probe_ctx) {
|
2022-05-12 09:52:58 +00:00
|
|
|
if (ctx->timeout_ticks != 0 && ctx->timeout_ticks < spdk_get_ticks()) {
|
|
|
|
DISCOVERY_ERRLOG(ctx, "timed out while attaching discovery ctrlr\n");
|
|
|
|
complete_discovery_start(ctx, -ETIMEDOUT);
|
|
|
|
return SPDK_POLLER_BUSY;
|
|
|
|
}
|
|
|
|
|
2022-02-25 02:00:44 +00:00
|
|
|
rc = spdk_nvme_probe_poll_async(ctx->probe_ctx);
|
|
|
|
if (rc != -EAGAIN) {
|
2022-05-12 09:52:58 +00:00
|
|
|
if (ctx->rc != 0) {
|
|
|
|
assert(ctx->initializing);
|
|
|
|
stop_discovery(ctx, NULL, ctx->cb_ctx);
|
|
|
|
} else {
|
2022-10-20 15:13:59 +00:00
|
|
|
assert(rc == 0);
|
2022-05-12 09:52:58 +00:00
|
|
|
DISCOVERY_INFOLOG(ctx, "discovery ctrlr connected\n");
|
|
|
|
ctx->rc = rc;
|
2022-10-20 15:13:59 +00:00
|
|
|
get_discovery_log_page(ctx);
|
2022-02-25 02:00:44 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-04 05:49:54 +00:00
|
|
|
} else {
|
2022-05-12 09:52:58 +00:00
|
|
|
if (ctx->timeout_ticks != 0 && ctx->timeout_ticks < spdk_get_ticks()) {
|
|
|
|
DISCOVERY_ERRLOG(ctx, "timed out while attaching NVM ctrlrs\n");
|
|
|
|
complete_discovery_start(ctx, -ETIMEDOUT);
|
|
|
|
/* We need to wait until all NVM ctrlrs are attached before we stop the
|
|
|
|
* discovery service to make sure we don't detach a ctrlr that is still
|
|
|
|
* being attached.
|
|
|
|
*/
|
|
|
|
if (ctx->attach_in_progress == 0) {
|
|
|
|
stop_discovery(ctx, NULL, ctx->cb_ctx);
|
|
|
|
return SPDK_POLLER_BUSY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-24 08:17:55 +00:00
|
|
|
rc = spdk_nvme_ctrlr_process_admin_completions(ctx->ctrlr);
|
|
|
|
if (rc < 0) {
|
2022-02-25 02:51:03 +00:00
|
|
|
spdk_poller_unregister(&ctx->poller);
|
|
|
|
ctx->poller = SPDK_POLLER_REGISTER(discovery_poller, ctx, 1000 * 1000);
|
2022-02-24 08:17:55 +00:00
|
|
|
TAILQ_INSERT_TAIL(&ctx->discovery_entry_ctxs, ctx->entry_ctx_in_use, tailq);
|
|
|
|
ctx->entry_ctx_in_use = NULL;
|
|
|
|
|
|
|
|
rc = spdk_nvme_detach_async(ctx->ctrlr, &ctx->detach_ctx);
|
|
|
|
if (rc != 0) {
|
|
|
|
DISCOVERY_ERRLOG(ctx, "could not detach discovery ctrlr\n");
|
|
|
|
ctx->ctrlr = NULL;
|
|
|
|
}
|
|
|
|
}
|
2021-12-04 05:49:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return SPDK_POLLER_BUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
start_discovery_poller(void *arg)
|
|
|
|
{
|
|
|
|
struct discovery_ctx *ctx = arg;
|
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&g_discovery_ctxs, ctx, tailq);
|
2022-02-25 02:51:03 +00:00
|
|
|
ctx->poller = SPDK_POLLER_REGISTER(discovery_poller, ctx, 1000 * 1000);
|
2021-12-04 05:49:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bdev_nvme_start_discovery(struct spdk_nvme_transport_id *trid,
|
|
|
|
const char *base_name,
|
2022-03-12 05:02:11 +00:00
|
|
|
struct spdk_nvme_ctrlr_opts *drv_opts,
|
2022-03-25 19:08:00 +00:00
|
|
|
struct nvme_ctrlr_opts *bdev_opts,
|
2022-05-12 09:52:58 +00:00
|
|
|
uint64_t attach_timeout,
|
nvme: Added support for TP-8009, Auto-discovery of Discovery controllers for NVME initiator using mDNS using Avahi
Approach:
Avahi Daemon needs to be running to provide the mDNS server service. In the SPDK, Avahi-client library based client API is implemented.
The client API will connect to the Avahi-daemon and receive events for new discovery and removal of an existing discovery entry.
Following sets on new RPCs have been introduced.
scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
User shall initiate an mDNS based discovery using this RPC. This will start a Avahi-client based poller
looking for new discovery events from the Avahi server. On a new discovery of the discovery controller,
the existing bdev_nvme_start_discovery API will be invoked with the trid of the discovery controller learnt.
This will enable automatic connection of the initiator to the subsystems discovered from the discovery controller.
Multiple mdns discovery instances can be run by specifying a unique bdev-prefix and a unique servicename to discover as parameters.
scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
This will stop the Avahi poller that was started for the specified service.Internally bdev_nvme_stop_discovery
API will be invoked for each of the discovery controllers learnt automatically by this instance of mdns discovery service.
This will result in termination of connections to all the subsystems learnt by this mdns discovery instance.
scripts/rpc.py bdev_nvme_get_mdns_discovery_info
This RPC will display the list of mdns discovery instances running and the trid of the controllers discovered by these instances.
Test Result:
root@ubuntu-pm-18-226:~/param-spdk/spdk/build/bin# ./nvmf_tgt -i 1 -s 2048 -m 0xF
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[
{
"name": "cdc_auto",
"svcname": "_nvme-disc._tcp",
"referrals": [
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
}
]
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[
{
"name": "cdc_auto02n1",
"aliases": [
"600110d6-1681-1681-0403-000045805c45"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-1681-1681-0403-000045805c45",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T0",
"serial_number": "00-681681dc681681dc",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto00n1",
"aliases": [
"600110da-09a6-09a6-0302-00005eeb19b4"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 2048,
"uuid": "600110da-09a6-09a6-0302-00005eeb19b4",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0"
},
"ctrlr_data": {
"cntlid": 1,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P2T0",
"serial_number": "00-ab09a6f5ab09a6f5",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n1",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8c"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8c",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n2",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8d"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8d",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 2,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
Signed-off-by: Parameswaran Krishnamurthy <parameswaran.krishna@dell.com>
Change-Id: Ic2c2e614e2549a655c7f81ae844b80d8505a4f02
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15703
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Boris Glimcher <Boris.Glimcher@emc.com>
Reviewed-by: <qun.wan@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
2022-11-30 20:11:23 +00:00
|
|
|
bool from_mdns,
|
2022-03-25 19:08:00 +00:00
|
|
|
spdk_bdev_nvme_start_discovery_fn cb_fn, void *cb_ctx)
|
2021-12-04 05:49:54 +00:00
|
|
|
{
|
|
|
|
struct discovery_ctx *ctx;
|
2022-02-25 01:26:48 +00:00
|
|
|
struct discovery_entry_ctx *discovery_entry_ctx;
|
2021-12-04 05:49:54 +00:00
|
|
|
|
2022-05-11 11:15:31 +00:00
|
|
|
snprintf(trid->subnqn, sizeof(trid->subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN);
|
2022-05-11 09:45:08 +00:00
|
|
|
TAILQ_FOREACH(ctx, &g_discovery_ctxs, tailq) {
|
|
|
|
if (strcmp(ctx->name, base_name) == 0) {
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
2022-05-11 11:15:31 +00:00
|
|
|
|
|
|
|
if (ctx->entry_ctx_in_use != NULL) {
|
|
|
|
if (!spdk_nvme_transport_id_compare(trid, &ctx->entry_ctx_in_use->trid)) {
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_FOREACH(discovery_entry_ctx, &ctx->discovery_entry_ctxs, tailq) {
|
|
|
|
if (!spdk_nvme_transport_id_compare(trid, &discovery_entry_ctx->trid)) {
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
}
|
2022-05-11 09:45:08 +00:00
|
|
|
}
|
|
|
|
|
2021-12-04 05:49:54 +00:00
|
|
|
ctx = calloc(1, sizeof(*ctx));
|
|
|
|
if (ctx == NULL) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2021-12-07 22:43:07 +00:00
|
|
|
ctx->name = strdup(base_name);
|
|
|
|
if (ctx->name == NULL) {
|
|
|
|
free_discovery_ctx(ctx);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2022-03-08 08:56:35 +00:00
|
|
|
memcpy(&ctx->drv_opts, drv_opts, sizeof(*drv_opts));
|
2022-03-12 05:02:11 +00:00
|
|
|
memcpy(&ctx->bdev_opts, bdev_opts, sizeof(*bdev_opts));
|
nvme: Added support for TP-8009, Auto-discovery of Discovery controllers for NVME initiator using mDNS using Avahi
Approach:
Avahi Daemon needs to be running to provide the mDNS server service. In the SPDK, Avahi-client library based client API is implemented.
The client API will connect to the Avahi-daemon and receive events for new discovery and removal of an existing discovery entry.
Following sets on new RPCs have been introduced.
scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
User shall initiate an mDNS based discovery using this RPC. This will start a Avahi-client based poller
looking for new discovery events from the Avahi server. On a new discovery of the discovery controller,
the existing bdev_nvme_start_discovery API will be invoked with the trid of the discovery controller learnt.
This will enable automatic connection of the initiator to the subsystems discovered from the discovery controller.
Multiple mdns discovery instances can be run by specifying a unique bdev-prefix and a unique servicename to discover as parameters.
scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
This will stop the Avahi poller that was started for the specified service.Internally bdev_nvme_stop_discovery
API will be invoked for each of the discovery controllers learnt automatically by this instance of mdns discovery service.
This will result in termination of connections to all the subsystems learnt by this mdns discovery instance.
scripts/rpc.py bdev_nvme_get_mdns_discovery_info
This RPC will display the list of mdns discovery instances running and the trid of the controllers discovered by these instances.
Test Result:
root@ubuntu-pm-18-226:~/param-spdk/spdk/build/bin# ./nvmf_tgt -i 1 -s 2048 -m 0xF
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[
{
"name": "cdc_auto",
"svcname": "_nvme-disc._tcp",
"referrals": [
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
}
]
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[
{
"name": "cdc_auto02n1",
"aliases": [
"600110d6-1681-1681-0403-000045805c45"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-1681-1681-0403-000045805c45",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T0",
"serial_number": "00-681681dc681681dc",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto00n1",
"aliases": [
"600110da-09a6-09a6-0302-00005eeb19b4"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 2048,
"uuid": "600110da-09a6-09a6-0302-00005eeb19b4",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0"
},
"ctrlr_data": {
"cntlid": 1,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P2T0",
"serial_number": "00-ab09a6f5ab09a6f5",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n1",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8c"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8c",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n2",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8d"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8d",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 2,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
Signed-off-by: Parameswaran Krishnamurthy <parameswaran.krishna@dell.com>
Change-Id: Ic2c2e614e2549a655c7f81ae844b80d8505a4f02
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15703
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Boris Glimcher <Boris.Glimcher@emc.com>
Reviewed-by: <qun.wan@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
2022-11-30 20:11:23 +00:00
|
|
|
ctx->from_mdns_discovery_service = from_mdns;
|
2022-03-04 20:43:23 +00:00
|
|
|
ctx->bdev_opts.from_discovery_service = true;
|
2021-12-04 05:49:54 +00:00
|
|
|
ctx->calling_thread = spdk_get_thread();
|
2022-05-11 11:26:01 +00:00
|
|
|
ctx->start_cb_fn = cb_fn;
|
|
|
|
ctx->cb_ctx = cb_ctx;
|
2022-05-12 09:52:58 +00:00
|
|
|
ctx->initializing = true;
|
2022-03-25 19:08:00 +00:00
|
|
|
if (ctx->start_cb_fn) {
|
|
|
|
/* We can use this when dumping json to denote if this RPC parameter
|
|
|
|
* was specified or not.
|
|
|
|
*/
|
|
|
|
ctx->wait_for_attach = true;
|
|
|
|
}
|
2022-05-12 09:52:58 +00:00
|
|
|
if (attach_timeout != 0) {
|
|
|
|
ctx->timeout_ticks = spdk_get_ticks() + attach_timeout *
|
|
|
|
spdk_get_ticks_hz() / 1000ull;
|
|
|
|
}
|
2022-02-10 13:27:07 +00:00
|
|
|
TAILQ_INIT(&ctx->nvm_entry_ctxs);
|
2022-02-24 13:28:01 +00:00
|
|
|
TAILQ_INIT(&ctx->discovery_entry_ctxs);
|
2022-02-24 14:52:47 +00:00
|
|
|
memcpy(&ctx->trid, trid, sizeof(*trid));
|
2021-12-07 22:43:07 +00:00
|
|
|
/* Even if user did not specify hostnqn, we can still strdup("\0"); */
|
2022-03-08 08:56:35 +00:00
|
|
|
ctx->hostnqn = strdup(ctx->drv_opts.hostnqn);
|
2021-12-07 22:43:07 +00:00
|
|
|
if (ctx->hostnqn == NULL) {
|
|
|
|
free_discovery_ctx(ctx);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2022-02-25 01:26:48 +00:00
|
|
|
discovery_entry_ctx = create_discovery_entry_ctx(ctx, trid);
|
|
|
|
if (discovery_entry_ctx == NULL) {
|
|
|
|
DISCOVERY_ERRLOG(ctx, "could not allocate new entry_ctx\n");
|
|
|
|
free_discovery_ctx(ctx);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&ctx->discovery_entry_ctxs, discovery_entry_ctx, tailq);
|
2021-12-04 05:49:54 +00:00
|
|
|
spdk_thread_send_msg(g_bdev_nvme_init_thread, start_discovery_poller, ctx);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-12-22 22:33:25 +00:00
|
|
|
int
|
|
|
|
bdev_nvme_stop_discovery(const char *name, spdk_bdev_nvme_stop_discovery_fn cb_fn, void *cb_ctx)
|
|
|
|
{
|
|
|
|
struct discovery_ctx *ctx;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(ctx, &g_discovery_ctxs, tailq) {
|
|
|
|
if (strcmp(name, ctx->name) == 0) {
|
2022-02-25 01:52:41 +00:00
|
|
|
if (ctx->stop) {
|
2021-12-22 22:33:25 +00:00
|
|
|
return -EALREADY;
|
|
|
|
}
|
2022-05-12 09:52:58 +00:00
|
|
|
/* If we're still starting the discovery service and ->rc is non-zero, we're
|
|
|
|
* going to stop it as soon as we can
|
|
|
|
*/
|
|
|
|
if (ctx->initializing && ctx->rc != 0) {
|
|
|
|
return -EALREADY;
|
|
|
|
}
|
2022-05-11 15:37:23 +00:00
|
|
|
stop_discovery(ctx, cb_fn, cb_ctx);
|
2021-12-22 22:33:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2017-07-13 17:36:19 +00:00
|
|
|
static int
|
2017-02-28 17:51:25 +00:00
|
|
|
bdev_nvme_library_init(void)
|
2016-07-20 18:16:23 +00:00
|
|
|
{
|
2018-07-12 12:26:19 +00:00
|
|
|
g_bdev_nvme_init_thread = spdk_get_thread();
|
2018-07-09 21:04:33 +00:00
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
spdk_io_device_register(&g_nvme_bdev_ctrlrs, bdev_nvme_create_poll_group_cb,
|
2021-07-06 17:20:32 +00:00
|
|
|
bdev_nvme_destroy_poll_group_cb,
|
|
|
|
sizeof(struct nvme_poll_group), "nvme_poll_groups");
|
2020-02-07 00:20:35 +00:00
|
|
|
|
2020-10-14 14:51:18 +00:00
|
|
|
return 0;
|
2016-07-20 18:16:23 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 06:05:10 +00:00
|
|
|
static void
|
2021-12-07 21:10:54 +00:00
|
|
|
bdev_nvme_fini_destruct_ctrlrs(void)
|
2016-07-20 18:16:23 +00:00
|
|
|
{
|
2021-09-07 16:13:07 +00:00
|
|
|
struct nvme_bdev_ctrlr *nbdev_ctrlr;
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr;
|
2019-02-13 05:08:22 +00:00
|
|
|
|
2018-11-21 10:45:31 +00:00
|
|
|
pthread_mutex_lock(&g_bdev_nvme_mutex);
|
2021-09-07 16:13:07 +00:00
|
|
|
TAILQ_FOREACH(nbdev_ctrlr, &g_nvme_bdev_ctrlrs, tailq) {
|
|
|
|
TAILQ_FOREACH(nvme_ctrlr, &nbdev_ctrlr->ctrlrs, tailq) {
|
|
|
|
pthread_mutex_lock(&nvme_ctrlr->mutex);
|
|
|
|
if (nvme_ctrlr->destruct) {
|
|
|
|
/* This controller's destruction was already started
|
|
|
|
* before the application started shutting down
|
|
|
|
*/
|
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
nvme_ctrlr->destruct = true;
|
2021-07-06 19:42:41 +00:00
|
|
|
pthread_mutex_unlock(&nvme_ctrlr->mutex);
|
2018-11-21 10:45:31 +00:00
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
spdk_thread_send_msg(nvme_ctrlr->thread, _nvme_ctrlr_destruct,
|
|
|
|
nvme_ctrlr);
|
|
|
|
}
|
2018-11-21 10:45:31 +00:00
|
|
|
}
|
2020-03-05 10:45:00 +00:00
|
|
|
|
|
|
|
g_bdev_nvme_module_finish = true;
|
2021-09-07 16:13:07 +00:00
|
|
|
if (TAILQ_EMPTY(&g_nvme_bdev_ctrlrs)) {
|
2020-03-05 10:45:00 +00:00
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
2021-09-07 16:13:07 +00:00
|
|
|
spdk_io_device_unregister(&g_nvme_bdev_ctrlrs, NULL);
|
2021-08-10 13:30:42 +00:00
|
|
|
spdk_bdev_module_fini_done();
|
2020-03-05 10:45:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-21 10:45:31 +00:00
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
2017-01-25 01:04:14 +00:00
|
|
|
}
|
|
|
|
|
2021-12-04 05:49:54 +00:00
|
|
|
static void
|
|
|
|
check_discovery_fini(void *arg)
|
|
|
|
{
|
|
|
|
if (TAILQ_EMPTY(&g_discovery_ctxs)) {
|
|
|
|
bdev_nvme_fini_destruct_ctrlrs();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-07 21:10:54 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_library_fini(void)
|
|
|
|
{
|
|
|
|
struct nvme_probe_skip_entry *entry, *entry_tmp;
|
2021-12-04 05:49:54 +00:00
|
|
|
struct discovery_ctx *ctx;
|
2021-12-07 21:10:54 +00:00
|
|
|
|
|
|
|
spdk_poller_unregister(&g_hotplug_poller);
|
|
|
|
free(g_hotplug_probe_ctx);
|
|
|
|
g_hotplug_probe_ctx = NULL;
|
|
|
|
|
|
|
|
TAILQ_FOREACH_SAFE(entry, &g_skipped_nvme_ctrlrs, tailq, entry_tmp) {
|
|
|
|
TAILQ_REMOVE(&g_skipped_nvme_ctrlrs, entry, tailq);
|
|
|
|
free(entry);
|
|
|
|
}
|
|
|
|
|
2021-12-04 05:49:54 +00:00
|
|
|
assert(spdk_get_thread() == g_bdev_nvme_init_thread);
|
|
|
|
if (TAILQ_EMPTY(&g_discovery_ctxs)) {
|
|
|
|
bdev_nvme_fini_destruct_ctrlrs();
|
|
|
|
} else {
|
|
|
|
TAILQ_FOREACH(ctx, &g_discovery_ctxs, tailq) {
|
2022-05-12 14:24:14 +00:00
|
|
|
stop_discovery(ctx, check_discovery_fini, NULL);
|
2021-12-04 05:49:54 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-07 21:10:54 +00:00
|
|
|
}
|
|
|
|
|
2019-02-05 01:56:15 +00:00
|
|
|
static void
|
2021-05-28 01:49:18 +00:00
|
|
|
bdev_nvme_verify_pi_error(struct nvme_bdev_io *bio)
|
2019-02-05 01:56:15 +00:00
|
|
|
{
|
2021-05-28 01:49:18 +00:00
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
2019-02-05 01:56:15 +00:00
|
|
|
struct spdk_bdev *bdev = bdev_io->bdev;
|
|
|
|
struct spdk_dif_ctx dif_ctx;
|
|
|
|
struct spdk_dif_error err_blk = {};
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = spdk_dif_ctx_init(&dif_ctx,
|
|
|
|
bdev->blocklen, bdev->md_len, bdev->md_interleave,
|
|
|
|
bdev->dif_is_head_of_md, bdev->dif_type, bdev->dif_check_flags,
|
2019-06-04 05:52:24 +00:00
|
|
|
bdev_io->u.bdev.offset_blocks, 0, 0, 0, 0);
|
2019-02-05 01:56:15 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Initialization of DIF context failed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-16 08:17:08 +00:00
|
|
|
if (bdev->md_interleave) {
|
|
|
|
rc = spdk_dif_verify(bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
|
|
|
|
bdev_io->u.bdev.num_blocks, &dif_ctx, &err_blk);
|
|
|
|
} else {
|
|
|
|
struct iovec md_iov = {
|
|
|
|
.iov_base = bdev_io->u.bdev.md_buf,
|
|
|
|
.iov_len = bdev_io->u.bdev.num_blocks * bdev->md_len,
|
|
|
|
};
|
|
|
|
|
|
|
|
rc = spdk_dix_verify(bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
|
|
|
|
&md_iov, bdev_io->u.bdev.num_blocks, &dif_ctx, &err_blk);
|
|
|
|
}
|
|
|
|
|
2019-02-05 01:56:15 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("DIF error detected. type=%d, offset=%" PRIu32 "\n",
|
|
|
|
err_blk.err_type, err_blk.err_offset);
|
|
|
|
} else {
|
|
|
|
SPDK_ERRLOG("Hardware reported PI error but SPDK could not find any.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-08 05:42:18 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_no_pi_readv_done(void *ref, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_io *bio = ref;
|
|
|
|
|
|
|
|
if (spdk_nvme_cpl_is_success(cpl)) {
|
|
|
|
/* Run PI verification for read data buffer. */
|
2021-05-28 01:49:18 +00:00
|
|
|
bdev_nvme_verify_pi_error(bio);
|
2019-02-08 05:42:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Return original completion status */
|
2021-05-12 20:56:42 +00:00
|
|
|
bdev_nvme_io_complete_nvme_status(bio, &bio->cpl);
|
2019-02-08 05:42:18 +00:00
|
|
|
}
|
|
|
|
|
2019-02-05 01:47:25 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_readv_done(void *ref, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
2019-02-08 05:42:18 +00:00
|
|
|
struct nvme_bdev_io *bio = ref;
|
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (spdk_unlikely(spdk_nvme_cpl_is_pi_error(cpl))) {
|
|
|
|
SPDK_ERRLOG("readv completed with PI error (sct=%d, sc=%d)\n",
|
|
|
|
cpl->status.sct, cpl->status.sc);
|
|
|
|
|
|
|
|
/* Save completion status to use after verifying PI error. */
|
|
|
|
bio->cpl = *cpl;
|
|
|
|
|
2021-09-16 11:10:56 +00:00
|
|
|
if (spdk_likely(nvme_io_path_is_available(bio->io_path))) {
|
2021-02-28 22:07:32 +00:00
|
|
|
/* Read without PI checking to verify PI error. */
|
2021-09-16 11:10:56 +00:00
|
|
|
ret = bdev_nvme_no_pi_readv(bio,
|
2021-02-28 22:07:32 +00:00
|
|
|
bdev_io->u.bdev.iovs,
|
|
|
|
bdev_io->u.bdev.iovcnt,
|
|
|
|
bdev_io->u.bdev.md_buf,
|
|
|
|
bdev_io->u.bdev.num_blocks,
|
|
|
|
bdev_io->u.bdev.offset_blocks);
|
|
|
|
if (ret == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2019-02-08 05:42:18 +00:00
|
|
|
}
|
|
|
|
}
|
2019-02-05 01:47:25 +00:00
|
|
|
|
2021-05-12 20:56:42 +00:00
|
|
|
bdev_nvme_io_complete_nvme_status(bio, cpl);
|
2019-02-05 01:47:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_writev_done(void *ref, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
2021-05-12 20:56:42 +00:00
|
|
|
struct nvme_bdev_io *bio = ref;
|
2019-02-05 01:47:25 +00:00
|
|
|
|
2019-02-05 01:56:15 +00:00
|
|
|
if (spdk_nvme_cpl_is_pi_error(cpl)) {
|
|
|
|
SPDK_ERRLOG("writev completed with PI error (sct=%d, sc=%d)\n",
|
|
|
|
cpl->status.sct, cpl->status.sc);
|
|
|
|
/* Run PI verification for write data buffer if PI error is detected. */
|
2021-05-28 01:49:18 +00:00
|
|
|
bdev_nvme_verify_pi_error(bio);
|
2019-02-05 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
2021-05-12 20:56:42 +00:00
|
|
|
bdev_nvme_io_complete_nvme_status(bio, cpl);
|
2019-02-05 01:47:25 +00:00
|
|
|
}
|
|
|
|
|
2021-03-03 18:38:38 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_zone_appendv_done(void *ref, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
2021-05-12 20:56:42 +00:00
|
|
|
struct nvme_bdev_io *bio = ref;
|
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
2021-03-03 18:38:38 +00:00
|
|
|
|
|
|
|
/* spdk_bdev_io_get_append_location() requires that the ALBA is stored in offset_blocks.
|
|
|
|
* Additionally, offset_blocks has to be set before calling bdev_nvme_verify_pi_error().
|
|
|
|
*/
|
|
|
|
bdev_io->u.bdev.offset_blocks = *(uint64_t *)&cpl->cdw0;
|
|
|
|
|
|
|
|
if (spdk_nvme_cpl_is_pi_error(cpl)) {
|
|
|
|
SPDK_ERRLOG("zone append completed with PI error (sct=%d, sc=%d)\n",
|
|
|
|
cpl->status.sct, cpl->status.sc);
|
|
|
|
/* Run PI verification for zone append data buffer if PI error is detected. */
|
2021-05-28 01:49:18 +00:00
|
|
|
bdev_nvme_verify_pi_error(bio);
|
2021-03-03 18:38:38 +00:00
|
|
|
}
|
|
|
|
|
2021-05-12 20:56:42 +00:00
|
|
|
bdev_nvme_io_complete_nvme_status(bio, cpl);
|
2021-03-03 18:38:38 +00:00
|
|
|
}
|
|
|
|
|
2019-12-13 08:40:54 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_comparev_done(void *ref, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
2021-05-12 20:56:42 +00:00
|
|
|
struct nvme_bdev_io *bio = ref;
|
2019-12-13 08:40:54 +00:00
|
|
|
|
|
|
|
if (spdk_nvme_cpl_is_pi_error(cpl)) {
|
|
|
|
SPDK_ERRLOG("comparev completed with PI error (sct=%d, sc=%d)\n",
|
|
|
|
cpl->status.sct, cpl->status.sc);
|
|
|
|
/* Run PI verification for compare data buffer if PI error is detected. */
|
2021-05-28 01:49:18 +00:00
|
|
|
bdev_nvme_verify_pi_error(bio);
|
2019-12-13 08:40:54 +00:00
|
|
|
}
|
|
|
|
|
2021-05-12 20:56:42 +00:00
|
|
|
bdev_nvme_io_complete_nvme_status(bio, cpl);
|
2019-12-13 08:40:54 +00:00
|
|
|
}
|
|
|
|
|
2019-12-20 11:29:48 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_comparev_and_writev_done(void *ref, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_io *bio = ref;
|
|
|
|
|
2020-01-17 13:06:24 +00:00
|
|
|
/* Compare operation completion */
|
2022-04-06 12:43:21 +00:00
|
|
|
if (!bio->first_fused_completed) {
|
2020-01-17 13:06:24 +00:00
|
|
|
/* Save compare result for write callback */
|
|
|
|
bio->cpl = *cpl;
|
2022-04-06 12:43:21 +00:00
|
|
|
bio->first_fused_completed = true;
|
2020-01-17 13:06:24 +00:00
|
|
|
return;
|
2019-12-20 11:29:48 +00:00
|
|
|
}
|
|
|
|
|
2020-01-17 13:06:24 +00:00
|
|
|
/* Write operation completion */
|
|
|
|
if (spdk_nvme_cpl_is_error(&bio->cpl)) {
|
|
|
|
/* If bio->cpl is already an error, it means the compare operation failed. In that case,
|
|
|
|
* complete the IO with the compare operation's status.
|
|
|
|
*/
|
|
|
|
if (!spdk_nvme_cpl_is_error(cpl)) {
|
|
|
|
SPDK_ERRLOG("Unexpected write success after compare failure.\n");
|
|
|
|
}
|
2019-12-20 11:29:48 +00:00
|
|
|
|
2021-05-12 20:56:42 +00:00
|
|
|
bdev_nvme_io_complete_nvme_status(bio, &bio->cpl);
|
2020-01-17 13:06:24 +00:00
|
|
|
} else {
|
2021-05-12 20:56:42 +00:00
|
|
|
bdev_nvme_io_complete_nvme_status(bio, cpl);
|
2020-01-17 13:06:24 +00:00
|
|
|
}
|
2019-12-20 11:29:48 +00:00
|
|
|
}
|
|
|
|
|
2016-07-20 18:16:23 +00:00
|
|
|
static void
|
2017-02-28 17:51:25 +00:00
|
|
|
bdev_nvme_queued_done(void *ref, const struct spdk_nvme_cpl *cpl)
|
2016-07-20 18:16:23 +00:00
|
|
|
{
|
2021-05-12 20:56:42 +00:00
|
|
|
struct nvme_bdev_io *bio = ref;
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2021-05-12 20:56:42 +00:00
|
|
|
bdev_nvme_io_complete_nvme_status(bio, cpl);
|
2016-07-20 18:16:23 +00:00
|
|
|
}
|
|
|
|
|
2021-03-03 18:38:38 +00:00
|
|
|
static int
|
|
|
|
fill_zone_from_report(struct spdk_bdev_zone_info *info, struct spdk_nvme_zns_zone_desc *desc)
|
|
|
|
{
|
2022-09-15 14:47:15 +00:00
|
|
|
switch (desc->zt) {
|
|
|
|
case SPDK_NVME_ZONE_TYPE_SEQWR:
|
|
|
|
info->type = SPDK_BDEV_ZONE_TYPE_SEQWR;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SPDK_ERRLOG("Invalid zone type: %#x in zone report\n", desc->zt);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2021-03-03 18:38:38 +00:00
|
|
|
switch (desc->zs) {
|
|
|
|
case SPDK_NVME_ZONE_STATE_EMPTY:
|
|
|
|
info->state = SPDK_BDEV_ZONE_STATE_EMPTY;
|
|
|
|
break;
|
|
|
|
case SPDK_NVME_ZONE_STATE_IOPEN:
|
|
|
|
info->state = SPDK_BDEV_ZONE_STATE_IMP_OPEN;
|
|
|
|
break;
|
|
|
|
case SPDK_NVME_ZONE_STATE_EOPEN:
|
|
|
|
info->state = SPDK_BDEV_ZONE_STATE_EXP_OPEN;
|
|
|
|
break;
|
|
|
|
case SPDK_NVME_ZONE_STATE_CLOSED:
|
|
|
|
info->state = SPDK_BDEV_ZONE_STATE_CLOSED;
|
|
|
|
break;
|
|
|
|
case SPDK_NVME_ZONE_STATE_RONLY:
|
|
|
|
info->state = SPDK_BDEV_ZONE_STATE_READ_ONLY;
|
|
|
|
break;
|
|
|
|
case SPDK_NVME_ZONE_STATE_FULL:
|
|
|
|
info->state = SPDK_BDEV_ZONE_STATE_FULL;
|
|
|
|
break;
|
|
|
|
case SPDK_NVME_ZONE_STATE_OFFLINE:
|
|
|
|
info->state = SPDK_BDEV_ZONE_STATE_OFFLINE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SPDK_ERRLOG("Invalid zone state: %#x in zone report\n", desc->zs);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
info->zone_id = desc->zslba;
|
|
|
|
info->write_pointer = desc->wp;
|
|
|
|
info->capacity = desc->zcap;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_get_zone_info_done(void *ref, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_io *bio = ref;
|
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
|
|
|
uint64_t zone_id = bdev_io->u.zone_mgmt.zone_id;
|
|
|
|
uint32_t zones_to_copy = bdev_io->u.zone_mgmt.num_zones;
|
|
|
|
struct spdk_bdev_zone_info *info = bdev_io->u.zone_mgmt.buf;
|
|
|
|
uint64_t max_zones_per_buf, i;
|
|
|
|
uint32_t zone_report_bufsize;
|
2021-06-01 17:49:43 +00:00
|
|
|
struct spdk_nvme_ns *ns;
|
2021-03-03 18:38:38 +00:00
|
|
|
struct spdk_nvme_qpair *qpair;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (spdk_nvme_cpl_is_error(cpl)) {
|
|
|
|
goto out_complete_io_nvme_cpl;
|
|
|
|
}
|
|
|
|
|
2021-09-16 11:10:56 +00:00
|
|
|
if (spdk_unlikely(!nvme_io_path_is_available(bio->io_path))) {
|
2021-04-20 22:54:59 +00:00
|
|
|
ret = -ENXIO;
|
|
|
|
goto out_complete_io_ret;
|
2021-03-03 18:38:38 +00:00
|
|
|
}
|
|
|
|
|
2021-09-16 11:10:56 +00:00
|
|
|
ns = bio->io_path->nvme_ns->ns;
|
2022-03-09 06:44:18 +00:00
|
|
|
qpair = bio->io_path->qpair->qpair;
|
2021-08-25 03:53:41 +00:00
|
|
|
|
2021-06-01 17:49:43 +00:00
|
|
|
zone_report_bufsize = spdk_nvme_ns_get_max_io_xfer_size(ns);
|
2021-03-03 18:38:38 +00:00
|
|
|
max_zones_per_buf = (zone_report_bufsize - sizeof(*bio->zone_report_buf)) /
|
|
|
|
sizeof(bio->zone_report_buf->descs[0]);
|
|
|
|
|
|
|
|
if (bio->zone_report_buf->nr_zones > max_zones_per_buf) {
|
2021-04-20 22:54:59 +00:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_complete_io_ret;
|
2021-03-03 18:38:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!bio->zone_report_buf->nr_zones) {
|
2021-04-20 22:54:59 +00:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out_complete_io_ret;
|
2021-03-03 18:38:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < bio->zone_report_buf->nr_zones && bio->handled_zones < zones_to_copy; i++) {
|
|
|
|
ret = fill_zone_from_report(&info[bio->handled_zones],
|
|
|
|
&bio->zone_report_buf->descs[i]);
|
|
|
|
if (ret) {
|
2021-04-20 22:54:59 +00:00
|
|
|
goto out_complete_io_ret;
|
2021-03-03 18:38:38 +00:00
|
|
|
}
|
|
|
|
bio->handled_zones++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bio->handled_zones < zones_to_copy) {
|
2021-06-01 17:49:43 +00:00
|
|
|
uint64_t zone_size_lba = spdk_nvme_zns_ns_get_zone_size_sectors(ns);
|
2021-03-03 18:38:38 +00:00
|
|
|
uint64_t slba = zone_id + (zone_size_lba * bio->handled_zones);
|
|
|
|
|
|
|
|
memset(bio->zone_report_buf, 0, zone_report_bufsize);
|
2021-06-01 17:49:43 +00:00
|
|
|
ret = spdk_nvme_zns_report_zones(ns, qpair,
|
2021-03-03 18:38:38 +00:00
|
|
|
bio->zone_report_buf, zone_report_bufsize,
|
|
|
|
slba, SPDK_NVME_ZRA_LIST_ALL, true,
|
|
|
|
bdev_nvme_get_zone_info_done, bio);
|
|
|
|
if (!ret) {
|
|
|
|
return;
|
|
|
|
} else {
|
2021-04-20 22:54:59 +00:00
|
|
|
goto out_complete_io_ret;
|
2021-03-03 18:38:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out_complete_io_nvme_cpl:
|
|
|
|
free(bio->zone_report_buf);
|
|
|
|
bio->zone_report_buf = NULL;
|
2021-05-12 20:56:42 +00:00
|
|
|
bdev_nvme_io_complete_nvme_status(bio, cpl);
|
2021-03-03 18:38:38 +00:00
|
|
|
return;
|
|
|
|
|
2021-04-20 22:54:59 +00:00
|
|
|
out_complete_io_ret:
|
2021-03-03 18:38:38 +00:00
|
|
|
free(bio->zone_report_buf);
|
|
|
|
bio->zone_report_buf = NULL;
|
2021-04-20 22:54:59 +00:00
|
|
|
bdev_nvme_io_complete(bio, ret);
|
2021-03-03 18:38:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_zone_management_done(void *ref, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
2021-05-12 20:56:42 +00:00
|
|
|
struct nvme_bdev_io *bio = ref;
|
2021-03-03 18:38:38 +00:00
|
|
|
|
2021-05-12 20:56:42 +00:00
|
|
|
bdev_nvme_io_complete_nvme_status(bio, cpl);
|
2021-03-03 18:38:38 +00:00
|
|
|
}
|
|
|
|
|
2017-05-13 20:12:13 +00:00
|
|
|
static void
|
2021-10-18 13:15:32 +00:00
|
|
|
bdev_nvme_admin_passthru_complete_nvme_status(void *ctx)
|
2017-05-13 20:12:13 +00:00
|
|
|
{
|
2017-06-15 20:51:31 +00:00
|
|
|
struct nvme_bdev_io *bio = ctx;
|
2021-10-18 13:15:32 +00:00
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
|
|
|
const struct spdk_nvme_cpl *cpl = &bio->cpl;
|
2021-10-19 03:54:14 +00:00
|
|
|
|
|
|
|
assert(bdev_nvme_io_type_is_admin(bdev_io->type));
|
|
|
|
|
2022-08-11 00:21:53 +00:00
|
|
|
__bdev_nvme_io_complete(bdev_io, 0, cpl);
|
2017-05-13 20:12:13 +00:00
|
|
|
}
|
|
|
|
|
2020-07-08 08:03:49 +00:00
|
|
|
static void
|
2021-10-18 13:15:32 +00:00
|
|
|
bdev_nvme_abort_complete(void *ctx)
|
2020-07-08 08:03:49 +00:00
|
|
|
{
|
|
|
|
struct nvme_bdev_io *bio = ctx;
|
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
|
|
|
|
|
|
|
if (spdk_nvme_cpl_is_abort_success(&bio->cpl)) {
|
2022-08-11 00:21:53 +00:00
|
|
|
__bdev_nvme_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS, NULL);
|
2020-07-08 08:03:49 +00:00
|
|
|
} else {
|
2022-08-11 00:21:53 +00:00
|
|
|
__bdev_nvme_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED, NULL);
|
2020-07-08 08:03:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_abort_done(void *ref, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_io *bio = ref;
|
|
|
|
|
|
|
|
bio->cpl = *cpl;
|
2021-10-18 13:15:32 +00:00
|
|
|
spdk_thread_send_msg(bio->orig_thread, bdev_nvme_abort_complete, bio);
|
2020-07-08 08:03:49 +00:00
|
|
|
}
|
|
|
|
|
2017-05-13 20:12:13 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_admin_passthru_done(void *ref, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_io *bio = ref;
|
|
|
|
|
|
|
|
bio->cpl = *cpl;
|
2021-10-18 13:15:32 +00:00
|
|
|
spdk_thread_send_msg(bio->orig_thread,
|
|
|
|
bdev_nvme_admin_passthru_complete_nvme_status, bio);
|
2017-05-13 20:12:13 +00:00
|
|
|
}
|
|
|
|
|
2016-10-04 14:39:27 +00:00
|
|
|
static void
|
2017-02-28 17:51:25 +00:00
|
|
|
bdev_nvme_queued_reset_sgl(void *ref, uint32_t sgl_offset)
|
2016-10-04 14:39:27 +00:00
|
|
|
{
|
2017-02-28 17:51:25 +00:00
|
|
|
struct nvme_bdev_io *bio = ref;
|
2016-10-04 14:39:27 +00:00
|
|
|
struct iovec *iov;
|
|
|
|
|
|
|
|
bio->iov_offset = sgl_offset;
|
|
|
|
for (bio->iovpos = 0; bio->iovpos < bio->iovcnt; bio->iovpos++) {
|
|
|
|
iov = &bio->iovs[bio->iovpos];
|
2017-12-07 23:23:48 +00:00
|
|
|
if (bio->iov_offset < iov->iov_len) {
|
2016-10-04 14:39:27 +00:00
|
|
|
break;
|
2017-12-07 23:23:48 +00:00
|
|
|
}
|
2016-10-04 14:39:27 +00:00
|
|
|
|
|
|
|
bio->iov_offset -= iov->iov_len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-02-28 17:51:25 +00:00
|
|
|
bdev_nvme_queued_next_sge(void *ref, void **address, uint32_t *length)
|
2016-10-04 14:39:27 +00:00
|
|
|
{
|
2017-02-28 17:51:25 +00:00
|
|
|
struct nvme_bdev_io *bio = ref;
|
2016-10-04 14:39:27 +00:00
|
|
|
struct iovec *iov;
|
|
|
|
|
|
|
|
assert(bio->iovpos < bio->iovcnt);
|
|
|
|
|
|
|
|
iov = &bio->iovs[bio->iovpos];
|
|
|
|
|
2016-11-03 17:12:16 +00:00
|
|
|
*address = iov->iov_base;
|
2016-10-04 14:39:27 +00:00
|
|
|
*length = iov->iov_len;
|
|
|
|
|
|
|
|
if (bio->iov_offset) {
|
|
|
|
assert(bio->iov_offset <= iov->iov_len);
|
|
|
|
*address += bio->iov_offset;
|
|
|
|
*length -= bio->iov_offset;
|
2016-11-09 06:00:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bio->iov_offset += *length;
|
|
|
|
if (bio->iov_offset == iov->iov_len) {
|
|
|
|
bio->iovpos++;
|
2016-10-04 14:39:27 +00:00
|
|
|
bio->iov_offset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-16 10:10:53 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_queued_reset_fused_sgl(void *ref, uint32_t sgl_offset)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_io *bio = ref;
|
|
|
|
struct iovec *iov;
|
|
|
|
|
|
|
|
bio->fused_iov_offset = sgl_offset;
|
|
|
|
for (bio->fused_iovpos = 0; bio->fused_iovpos < bio->fused_iovcnt; bio->fused_iovpos++) {
|
|
|
|
iov = &bio->fused_iovs[bio->fused_iovpos];
|
|
|
|
if (bio->fused_iov_offset < iov->iov_len) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bio->fused_iov_offset -= iov->iov_len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bdev_nvme_queued_next_fused_sge(void *ref, void **address, uint32_t *length)
|
|
|
|
{
|
|
|
|
struct nvme_bdev_io *bio = ref;
|
|
|
|
struct iovec *iov;
|
|
|
|
|
|
|
|
assert(bio->fused_iovpos < bio->fused_iovcnt);
|
|
|
|
|
|
|
|
iov = &bio->fused_iovs[bio->fused_iovpos];
|
|
|
|
|
|
|
|
*address = iov->iov_base;
|
|
|
|
*length = iov->iov_len;
|
|
|
|
|
|
|
|
if (bio->fused_iov_offset) {
|
|
|
|
assert(bio->fused_iov_offset <= iov->iov_len);
|
|
|
|
*address += bio->fused_iov_offset;
|
|
|
|
*length -= bio->fused_iov_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
bio->fused_iov_offset += *length;
|
|
|
|
if (bio->fused_iov_offset == iov->iov_len) {
|
|
|
|
bio->fused_iovpos++;
|
|
|
|
bio->fused_iov_offset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-02-08 05:42:18 +00:00
|
|
|
static int
|
2021-09-16 11:10:56 +00:00
|
|
|
bdev_nvme_no_pi_readv(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
|
2019-04-16 08:17:08 +00:00
|
|
|
void *md, uint64_t lba_count, uint64_t lba)
|
2019-02-08 05:42:18 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
2020-11-17 16:29:21 +00:00
|
|
|
SPDK_DEBUGLOG(bdev_nvme, "read %" PRIu64 " blocks with offset %#" PRIx64 " without PI check\n",
|
2019-02-08 05:42:18 +00:00
|
|
|
lba_count, lba);
|
|
|
|
|
|
|
|
bio->iovs = iov;
|
|
|
|
bio->iovcnt = iovcnt;
|
|
|
|
bio->iovpos = 0;
|
|
|
|
bio->iov_offset = 0;
|
|
|
|
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = spdk_nvme_ns_cmd_readv_with_md(bio->io_path->nvme_ns->ns,
|
2022-03-09 06:44:18 +00:00
|
|
|
bio->io_path->qpair->qpair,
|
2021-08-25 03:53:41 +00:00
|
|
|
lba, lba_count,
|
2019-04-16 08:17:08 +00:00
|
|
|
bdev_nvme_no_pi_readv_done, bio, 0,
|
|
|
|
bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge,
|
|
|
|
md, 0, 0);
|
2019-02-08 05:42:18 +00:00
|
|
|
|
|
|
|
if (rc != 0 && rc != -ENOMEM) {
|
|
|
|
SPDK_ERRLOG("no_pi_readv failed: rc = %d\n", rc);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-02-28 17:51:25 +00:00
|
|
|
static int
|
2021-09-16 11:10:56 +00:00
|
|
|
bdev_nvme_readv(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
|
2021-08-25 03:18:56 +00:00
|
|
|
void *md, uint64_t lba_count, uint64_t lba, uint32_t flags,
|
|
|
|
struct spdk_bdev_ext_io_opts *ext_opts)
|
2016-07-20 18:16:23 +00:00
|
|
|
{
|
2021-09-16 11:10:56 +00:00
|
|
|
struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
|
2022-03-09 06:44:18 +00:00
|
|
|
struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
|
2016-07-20 18:16:23 +00:00
|
|
|
int rc;
|
|
|
|
|
2020-11-17 16:29:21 +00:00
|
|
|
SPDK_DEBUGLOG(bdev_nvme, "read %" PRIu64 " blocks with offset %#" PRIx64 "\n",
|
2019-02-05 01:47:25 +00:00
|
|
|
lba_count, lba);
|
|
|
|
|
2016-10-04 14:39:27 +00:00
|
|
|
bio->iovs = iov;
|
|
|
|
bio->iovcnt = iovcnt;
|
|
|
|
bio->iovpos = 0;
|
|
|
|
bio->iov_offset = 0;
|
|
|
|
|
2021-08-25 03:18:56 +00:00
|
|
|
if (ext_opts) {
|
2021-01-09 15:10:18 +00:00
|
|
|
bio->ext_opts.size = sizeof(struct spdk_nvme_ns_cmd_ext_io_opts);
|
2021-08-25 03:18:56 +00:00
|
|
|
bio->ext_opts.memory_domain = ext_opts->memory_domain;
|
|
|
|
bio->ext_opts.memory_domain_ctx = ext_opts->memory_domain_ctx;
|
2021-01-09 15:10:18 +00:00
|
|
|
bio->ext_opts.io_flags = flags;
|
|
|
|
bio->ext_opts.metadata = md;
|
|
|
|
|
|
|
|
rc = spdk_nvme_ns_cmd_readv_ext(ns, qpair, lba, lba_count,
|
|
|
|
bdev_nvme_readv_done, bio,
|
|
|
|
bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge,
|
|
|
|
&bio->ext_opts);
|
|
|
|
} else if (iovcnt == 1) {
|
2020-11-23 04:48:51 +00:00
|
|
|
rc = spdk_nvme_ns_cmd_read_with_md(ns, qpair, iov[0].iov_base, md, lba,
|
2020-09-18 17:31:23 +00:00
|
|
|
lba_count,
|
|
|
|
bdev_nvme_readv_done, bio,
|
2020-09-23 20:37:27 +00:00
|
|
|
flags,
|
2020-09-18 17:31:23 +00:00
|
|
|
0, 0);
|
|
|
|
} else {
|
2020-11-23 04:48:51 +00:00
|
|
|
rc = spdk_nvme_ns_cmd_readv_with_md(ns, qpair, lba, lba_count,
|
2020-09-23 20:37:27 +00:00
|
|
|
bdev_nvme_readv_done, bio, flags,
|
2020-09-18 17:31:23 +00:00
|
|
|
bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge,
|
|
|
|
md, 0, 0);
|
|
|
|
}
|
2019-02-05 01:47:25 +00:00
|
|
|
|
|
|
|
if (rc != 0 && rc != -ENOMEM) {
|
|
|
|
SPDK_ERRLOG("readv failed: rc = %d\n", rc);
|
2016-07-20 18:16:23 +00:00
|
|
|
}
|
2019-02-05 01:47:25 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2021-09-16 11:10:56 +00:00
|
|
|
bdev_nvme_writev(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
|
|
|
|
void *md, uint64_t lba_count, uint64_t lba,
|
2021-08-25 03:18:56 +00:00
|
|
|
uint32_t flags, struct spdk_bdev_ext_io_opts *ext_opts)
|
2019-02-05 01:47:25 +00:00
|
|
|
{
|
2021-09-16 11:10:56 +00:00
|
|
|
struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
|
2022-03-09 06:44:18 +00:00
|
|
|
struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
|
2019-02-05 01:47:25 +00:00
|
|
|
int rc;
|
|
|
|
|
2020-11-17 16:29:21 +00:00
|
|
|
SPDK_DEBUGLOG(bdev_nvme, "write %" PRIu64 " blocks with offset %#" PRIx64 "\n",
|
2019-02-05 01:47:25 +00:00
|
|
|
lba_count, lba);
|
|
|
|
|
|
|
|
bio->iovs = iov;
|
|
|
|
bio->iovcnt = iovcnt;
|
|
|
|
bio->iovpos = 0;
|
|
|
|
bio->iov_offset = 0;
|
|
|
|
|
2021-08-25 03:18:56 +00:00
|
|
|
if (ext_opts) {
|
2021-01-09 15:10:18 +00:00
|
|
|
bio->ext_opts.size = sizeof(struct spdk_nvme_ns_cmd_ext_io_opts);
|
2021-08-25 03:18:56 +00:00
|
|
|
bio->ext_opts.memory_domain = ext_opts->memory_domain;
|
|
|
|
bio->ext_opts.memory_domain_ctx = ext_opts->memory_domain_ctx;
|
2021-01-09 15:10:18 +00:00
|
|
|
bio->ext_opts.io_flags = flags;
|
|
|
|
bio->ext_opts.metadata = md;
|
|
|
|
|
|
|
|
rc = spdk_nvme_ns_cmd_writev_ext(ns, qpair, lba, lba_count,
|
2021-09-22 13:03:23 +00:00
|
|
|
bdev_nvme_writev_done, bio,
|
2021-01-09 15:10:18 +00:00
|
|
|
bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge,
|
|
|
|
&bio->ext_opts);
|
|
|
|
} else if (iovcnt == 1) {
|
2020-11-23 04:48:51 +00:00
|
|
|
rc = spdk_nvme_ns_cmd_write_with_md(ns, qpair, iov[0].iov_base, md, lba,
|
2020-09-18 17:46:03 +00:00
|
|
|
lba_count,
|
2021-01-26 08:17:11 +00:00
|
|
|
bdev_nvme_writev_done, bio,
|
2020-09-23 20:37:27 +00:00
|
|
|
flags,
|
2020-09-18 17:46:03 +00:00
|
|
|
0, 0);
|
|
|
|
} else {
|
2020-11-23 04:48:51 +00:00
|
|
|
rc = spdk_nvme_ns_cmd_writev_with_md(ns, qpair, lba, lba_count,
|
2020-09-23 20:37:27 +00:00
|
|
|
bdev_nvme_writev_done, bio, flags,
|
2020-09-18 17:46:03 +00:00
|
|
|
bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge,
|
|
|
|
md, 0, 0);
|
|
|
|
}
|
2016-07-20 18:16:23 +00:00
|
|
|
|
bdev: add ENOMEM handling
At very high queue depths, bdev modules may not have enough
internal resources to track all of the incoming I/O. For example,
we allocate a finite number of nvme_request objects per allocated
queue pair. Currently if these resources are exhausted, the
bdev module will return failure (with no indication why) which
gets propagated all the way back to the application.
So instead, add SPDK_BDEV_IO_STATUS_NOMEM to allow bdev modules
to indicate this type of failure. Also add handling for this
status type in the generic bdev layer, involving queuing these
I/O for later retry after other I/O on the failing channel have
completed.
This does place an expectation on the bdev module that these
internal resources are allocated per io_channel. Otherwise we
cannot guarantee forward progress solely on reception of
completions. For example, without this guarantee, a bdev
module could theoretically return ENOMEM even if there were
no I/O oustanding for that io_channel. nvme, aio, rbd,
virtio and null drivers comply with this expectation already.
malloc only complies though when not using copy offload.
This patch will fix malloc w/ copy engine to at least
return ENOMEM when no copy descriptors are available. If the
condition above occurs, I/O waiting for resources will get
failed as part of a subsequent reset which matches the
behavior it has today.
Signed-off-by: Jim Harris <james.r.harris@intel.com>
Change-Id: Iea7cd51a611af8abe882794d0b2361fdbb74e84e
Reviewed-on: https://review.gerrithub.io/378853
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
2017-09-15 20:47:17 +00:00
|
|
|
if (rc != 0 && rc != -ENOMEM) {
|
2019-02-05 01:47:25 +00:00
|
|
|
SPDK_ERRLOG("writev failed: rc = %d\n", rc);
|
2016-07-20 18:16:23 +00:00
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-03-03 18:38:38 +00:00
|
|
|
static int
|
2021-09-16 11:10:56 +00:00
|
|
|
bdev_nvme_zone_appendv(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
|
|
|
|
void *md, uint64_t lba_count, uint64_t zslba,
|
2021-03-03 18:38:38 +00:00
|
|
|
uint32_t flags)
|
|
|
|
{
|
2021-09-16 11:10:56 +00:00
|
|
|
struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
|
2022-03-09 06:44:18 +00:00
|
|
|
struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
|
2021-03-03 18:38:38 +00:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
SPDK_DEBUGLOG(bdev_nvme, "zone append %" PRIu64 " blocks to zone start lba %#" PRIx64 "\n",
|
|
|
|
lba_count, zslba);
|
|
|
|
|
|
|
|
bio->iovs = iov;
|
|
|
|
bio->iovcnt = iovcnt;
|
|
|
|
bio->iovpos = 0;
|
|
|
|
bio->iov_offset = 0;
|
|
|
|
|
|
|
|
if (iovcnt == 1) {
|
|
|
|
rc = spdk_nvme_zns_zone_append_with_md(ns, qpair, iov[0].iov_base, md, zslba,
|
|
|
|
lba_count,
|
|
|
|
bdev_nvme_zone_appendv_done, bio,
|
|
|
|
flags,
|
|
|
|
0, 0);
|
|
|
|
} else {
|
|
|
|
rc = spdk_nvme_zns_zone_appendv_with_md(ns, qpair, zslba, lba_count,
|
|
|
|
bdev_nvme_zone_appendv_done, bio, flags,
|
|
|
|
bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge,
|
|
|
|
md, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc != 0 && rc != -ENOMEM) {
|
|
|
|
SPDK_ERRLOG("zone append failed: rc = %d\n", rc);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2019-12-13 08:40:54 +00:00
|
|
|
static int
|
2021-09-16 11:10:56 +00:00
|
|
|
bdev_nvme_comparev(struct nvme_bdev_io *bio, struct iovec *iov, int iovcnt,
|
|
|
|
void *md, uint64_t lba_count, uint64_t lba,
|
2020-09-23 20:37:27 +00:00
|
|
|
uint32_t flags)
|
2019-12-13 08:40:54 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
2020-11-17 16:29:21 +00:00
|
|
|
SPDK_DEBUGLOG(bdev_nvme, "compare %" PRIu64 " blocks with offset %#" PRIx64 "\n",
|
2019-12-13 08:40:54 +00:00
|
|
|
lba_count, lba);
|
|
|
|
|
|
|
|
bio->iovs = iov;
|
|
|
|
bio->iovcnt = iovcnt;
|
|
|
|
bio->iovpos = 0;
|
|
|
|
bio->iov_offset = 0;
|
|
|
|
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = spdk_nvme_ns_cmd_comparev_with_md(bio->io_path->nvme_ns->ns,
|
2022-03-09 06:44:18 +00:00
|
|
|
bio->io_path->qpair->qpair,
|
2021-08-25 03:53:41 +00:00
|
|
|
lba, lba_count,
|
2020-09-23 20:37:27 +00:00
|
|
|
bdev_nvme_comparev_done, bio, flags,
|
2019-12-13 08:40:54 +00:00
|
|
|
bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge,
|
|
|
|
md, 0, 0);
|
|
|
|
|
|
|
|
if (rc != 0 && rc != -ENOMEM) {
|
|
|
|
SPDK_ERRLOG("comparev failed: rc = %d\n", rc);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2019-12-20 11:29:48 +00:00
|
|
|
static int
|
2021-09-16 11:10:56 +00:00
|
|
|
bdev_nvme_comparev_and_writev(struct nvme_bdev_io *bio, struct iovec *cmp_iov, int cmp_iovcnt,
|
2020-09-23 20:37:27 +00:00
|
|
|
struct iovec *write_iov, int write_iovcnt,
|
|
|
|
void *md, uint64_t lba_count, uint64_t lba, uint32_t flags)
|
2019-12-20 11:29:48 +00:00
|
|
|
{
|
2021-09-16 11:10:56 +00:00
|
|
|
struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
|
2022-03-09 06:44:18 +00:00
|
|
|
struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
|
2019-12-20 11:29:48 +00:00
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
|
|
|
int rc;
|
|
|
|
|
2020-11-17 16:29:21 +00:00
|
|
|
SPDK_DEBUGLOG(bdev_nvme, "compare and write %" PRIu64 " blocks with offset %#" PRIx64 "\n",
|
2019-12-20 11:29:48 +00:00
|
|
|
lba_count, lba);
|
|
|
|
|
2020-01-16 10:10:53 +00:00
|
|
|
bio->iovs = cmp_iov;
|
|
|
|
bio->iovcnt = cmp_iovcnt;
|
2019-12-20 11:29:48 +00:00
|
|
|
bio->iovpos = 0;
|
|
|
|
bio->iov_offset = 0;
|
2020-01-16 10:10:53 +00:00
|
|
|
bio->fused_iovs = write_iov;
|
|
|
|
bio->fused_iovcnt = write_iovcnt;
|
|
|
|
bio->fused_iovpos = 0;
|
|
|
|
bio->fused_iov_offset = 0;
|
2019-12-20 11:29:48 +00:00
|
|
|
|
|
|
|
if (bdev_io->num_retries == 0) {
|
|
|
|
bio->first_fused_submitted = false;
|
2022-04-06 12:43:21 +00:00
|
|
|
bio->first_fused_completed = false;
|
2019-12-20 11:29:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!bio->first_fused_submitted) {
|
|
|
|
flags |= SPDK_NVME_IO_FLAGS_FUSE_FIRST;
|
|
|
|
memset(&bio->cpl, 0, sizeof(bio->cpl));
|
|
|
|
|
2020-11-23 04:48:51 +00:00
|
|
|
rc = spdk_nvme_ns_cmd_comparev_with_md(ns, qpair, lba, lba_count,
|
2019-12-20 11:29:48 +00:00
|
|
|
bdev_nvme_comparev_and_writev_done, bio, flags,
|
|
|
|
bdev_nvme_queued_reset_sgl, bdev_nvme_queued_next_sge, md, 0, 0);
|
|
|
|
if (rc == 0) {
|
|
|
|
bio->first_fused_submitted = true;
|
|
|
|
flags &= ~SPDK_NVME_IO_FLAGS_FUSE_FIRST;
|
|
|
|
} else {
|
|
|
|
if (rc != -ENOMEM) {
|
|
|
|
SPDK_ERRLOG("compare failed: rc = %d\n", rc);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
flags |= SPDK_NVME_IO_FLAGS_FUSE_SECOND;
|
|
|
|
|
2020-11-23 04:48:51 +00:00
|
|
|
rc = spdk_nvme_ns_cmd_writev_with_md(ns, qpair, lba, lba_count,
|
2019-12-20 11:29:48 +00:00
|
|
|
bdev_nvme_comparev_and_writev_done, bio, flags,
|
2020-01-16 10:10:53 +00:00
|
|
|
bdev_nvme_queued_reset_fused_sgl, bdev_nvme_queued_next_fused_sge, md, 0, 0);
|
2019-12-20 11:29:48 +00:00
|
|
|
if (rc != 0 && rc != -ENOMEM) {
|
|
|
|
SPDK_ERRLOG("write failed: rc = %d\n", rc);
|
|
|
|
rc = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2016-07-20 18:16:23 +00:00
|
|
|
static int
|
2021-09-16 11:10:56 +00:00
|
|
|
bdev_nvme_unmap(struct nvme_bdev_io *bio, uint64_t offset_blocks, uint64_t num_blocks)
|
2016-07-20 18:16:23 +00:00
|
|
|
{
|
2017-09-19 17:59:58 +00:00
|
|
|
struct spdk_nvme_dsm_range dsm_ranges[SPDK_NVME_DATASET_MANAGEMENT_MAX_RANGES];
|
|
|
|
struct spdk_nvme_dsm_range *range;
|
|
|
|
uint64_t offset, remaining;
|
|
|
|
uint64_t num_ranges_u64;
|
|
|
|
uint16_t num_ranges;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
num_ranges_u64 = (num_blocks + SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS - 1) /
|
|
|
|
SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS;
|
|
|
|
if (num_ranges_u64 > SPDK_COUNTOF(dsm_ranges)) {
|
|
|
|
SPDK_ERRLOG("Unmap request for %" PRIu64 " blocks is too large\n", num_blocks);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
num_ranges = (uint16_t)num_ranges_u64;
|
|
|
|
|
|
|
|
offset = offset_blocks;
|
|
|
|
remaining = num_blocks;
|
|
|
|
range = &dsm_ranges[0];
|
|
|
|
|
|
|
|
/* Fill max-size ranges until the remaining blocks fit into one range */
|
|
|
|
while (remaining > SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS) {
|
|
|
|
range->attributes.raw = 0;
|
|
|
|
range->length = SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS;
|
|
|
|
range->starting_lba = offset;
|
|
|
|
|
|
|
|
offset += SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS;
|
|
|
|
remaining -= SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS;
|
|
|
|
range++;
|
|
|
|
}
|
2016-10-03 17:37:48 +00:00
|
|
|
|
2017-09-19 17:59:58 +00:00
|
|
|
/* Final range describes the remaining blocks */
|
|
|
|
range->attributes.raw = 0;
|
|
|
|
range->length = remaining;
|
|
|
|
range->starting_lba = offset;
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2021-09-16 11:10:56 +00:00
|
|
|
rc = spdk_nvme_ns_cmd_dataset_management(bio->io_path->nvme_ns->ns,
|
2022-03-09 06:44:18 +00:00
|
|
|
bio->io_path->qpair->qpair,
|
2016-10-03 17:37:48 +00:00
|
|
|
SPDK_NVME_DSM_ATTR_DEALLOCATE,
|
2017-09-19 17:59:58 +00:00
|
|
|
dsm_ranges, num_ranges,
|
2017-02-28 17:51:25 +00:00
|
|
|
bdev_nvme_queued_done, bio);
|
2016-07-20 18:16:23 +00:00
|
|
|
|
2017-05-20 00:12:39 +00:00
|
|
|
return rc;
|
2016-07-20 18:16:23 +00:00
|
|
|
}
|
|
|
|
|
2021-05-14 11:26:40 +00:00
|
|
|
static int
|
2021-09-16 11:10:56 +00:00
|
|
|
bdev_nvme_write_zeroes(struct nvme_bdev_io *bio, uint64_t offset_blocks, uint64_t num_blocks)
|
2021-05-14 11:26:40 +00:00
|
|
|
{
|
|
|
|
if (num_blocks > UINT16_MAX + 1) {
|
|
|
|
SPDK_ERRLOG("NVMe write zeroes is limited to 16-bit block count\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-09-16 11:10:56 +00:00
|
|
|
return spdk_nvme_ns_cmd_write_zeroes(bio->io_path->nvme_ns->ns,
|
2022-03-09 06:44:18 +00:00
|
|
|
bio->io_path->qpair->qpair,
|
2021-05-14 11:26:40 +00:00
|
|
|
offset_blocks, num_blocks,
|
|
|
|
bdev_nvme_queued_done, bio,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
2021-03-03 18:38:38 +00:00
|
|
|
static int
|
2021-09-16 11:10:56 +00:00
|
|
|
bdev_nvme_get_zone_info(struct nvme_bdev_io *bio, uint64_t zone_id, uint32_t num_zones,
|
2021-03-03 18:38:38 +00:00
|
|
|
struct spdk_bdev_zone_info *info)
|
|
|
|
{
|
2021-09-16 11:10:56 +00:00
|
|
|
struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
|
2022-03-09 06:44:18 +00:00
|
|
|
struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
|
2021-03-03 18:38:38 +00:00
|
|
|
uint32_t zone_report_bufsize = spdk_nvme_ns_get_max_io_xfer_size(ns);
|
|
|
|
uint64_t zone_size = spdk_nvme_zns_ns_get_zone_size_sectors(ns);
|
|
|
|
uint64_t total_zones = spdk_nvme_zns_ns_get_num_zones(ns);
|
|
|
|
|
|
|
|
if (zone_id % zone_size != 0) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_zones > total_zones || !num_zones) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!bio->zone_report_buf);
|
|
|
|
bio->zone_report_buf = calloc(1, zone_report_bufsize);
|
|
|
|
if (!bio->zone_report_buf) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
bio->handled_zones = 0;
|
|
|
|
|
|
|
|
return spdk_nvme_zns_report_zones(ns, qpair, bio->zone_report_buf, zone_report_bufsize,
|
|
|
|
zone_id, SPDK_NVME_ZRA_LIST_ALL, true,
|
|
|
|
bdev_nvme_get_zone_info_done, bio);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2021-09-16 11:10:56 +00:00
|
|
|
bdev_nvme_zone_management(struct nvme_bdev_io *bio, uint64_t zone_id,
|
2021-03-03 18:38:38 +00:00
|
|
|
enum spdk_bdev_zone_action action)
|
|
|
|
{
|
2021-09-16 11:10:56 +00:00
|
|
|
struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
|
2022-03-09 06:44:18 +00:00
|
|
|
struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
|
2021-08-25 03:53:41 +00:00
|
|
|
|
2021-03-03 18:38:38 +00:00
|
|
|
switch (action) {
|
|
|
|
case SPDK_BDEV_ZONE_CLOSE:
|
|
|
|
return spdk_nvme_zns_close_zone(ns, qpair, zone_id, false,
|
|
|
|
bdev_nvme_zone_management_done, bio);
|
|
|
|
case SPDK_BDEV_ZONE_FINISH:
|
|
|
|
return spdk_nvme_zns_finish_zone(ns, qpair, zone_id, false,
|
|
|
|
bdev_nvme_zone_management_done, bio);
|
|
|
|
case SPDK_BDEV_ZONE_OPEN:
|
|
|
|
return spdk_nvme_zns_open_zone(ns, qpair, zone_id, false,
|
|
|
|
bdev_nvme_zone_management_done, bio);
|
|
|
|
case SPDK_BDEV_ZONE_RESET:
|
|
|
|
return spdk_nvme_zns_reset_zone(ns, qpair, zone_id, false,
|
|
|
|
bdev_nvme_zone_management_done, bio);
|
|
|
|
case SPDK_BDEV_ZONE_OFFLINE:
|
|
|
|
return spdk_nvme_zns_offline_zone(ns, qpair, zone_id, false,
|
|
|
|
bdev_nvme_zone_management_done, bio);
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-18 13:15:32 +00:00
|
|
|
static void
|
2021-07-06 17:35:01 +00:00
|
|
|
bdev_nvme_admin_passthru(struct nvme_bdev_channel *nbdev_ch, struct nvme_bdev_io *bio,
|
2017-05-13 20:12:13 +00:00
|
|
|
struct spdk_nvme_cmd *cmd, void *buf, size_t nbytes)
|
|
|
|
{
|
2021-09-27 23:15:02 +00:00
|
|
|
struct nvme_io_path *io_path;
|
2021-07-06 19:42:41 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr;
|
2021-03-28 22:49:49 +00:00
|
|
|
uint32_t max_xfer_size;
|
2021-10-18 13:15:32 +00:00
|
|
|
int rc = -ENXIO;
|
2021-03-28 22:49:49 +00:00
|
|
|
|
2021-09-28 07:54:49 +00:00
|
|
|
/* Choose the first ctrlr which is not failed. */
|
|
|
|
STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_ctrlr = io_path->qpair->ctrlr;
|
2021-10-18 13:15:32 +00:00
|
|
|
|
2021-11-24 02:09:59 +00:00
|
|
|
/* We should skip any unavailable nvme_ctrlr rather than checking
|
|
|
|
* if the return value of spdk_nvme_ctrlr_cmd_admin_raw() is -ENXIO.
|
2021-11-18 17:29:28 +00:00
|
|
|
*/
|
2021-11-24 02:09:59 +00:00
|
|
|
if (!nvme_ctrlr_is_available(nvme_ctrlr)) {
|
2021-10-18 13:15:32 +00:00
|
|
|
continue;
|
2021-09-28 07:54:49 +00:00
|
|
|
}
|
2021-09-27 23:15:02 +00:00
|
|
|
|
2021-10-18 13:15:32 +00:00
|
|
|
max_xfer_size = spdk_nvme_ctrlr_get_max_xfer_size(nvme_ctrlr->ctrlr);
|
2021-03-28 22:49:49 +00:00
|
|
|
|
2021-10-18 13:15:32 +00:00
|
|
|
if (nbytes > max_xfer_size) {
|
|
|
|
SPDK_ERRLOG("nbytes is greater than MDTS %" PRIu32 ".\n", max_xfer_size);
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
2018-05-08 23:07:30 +00:00
|
|
|
|
2021-10-19 03:54:14 +00:00
|
|
|
bio->io_path = io_path;
|
2021-10-18 13:15:32 +00:00
|
|
|
bio->orig_thread = spdk_get_thread();
|
2017-05-13 20:12:13 +00:00
|
|
|
|
2021-10-18 13:15:32 +00:00
|
|
|
rc = spdk_nvme_ctrlr_cmd_admin_raw(nvme_ctrlr->ctrlr, cmd, buf, (uint32_t)nbytes,
|
|
|
|
bdev_nvme_admin_passthru_done, bio);
|
|
|
|
if (rc == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2017-05-13 20:12:13 +00:00
|
|
|
|
2021-10-18 13:15:32 +00:00
|
|
|
err:
|
|
|
|
bdev_nvme_admin_passthru_complete(bio, rc);
|
2017-05-13 20:12:13 +00:00
|
|
|
}
|
|
|
|
|
2017-06-05 18:02:09 +00:00
|
|
|
static int
|
2021-09-16 11:10:56 +00:00
|
|
|
bdev_nvme_io_passthru(struct nvme_bdev_io *bio, struct spdk_nvme_cmd *cmd,
|
|
|
|
void *buf, size_t nbytes)
|
2017-06-05 18:02:09 +00:00
|
|
|
{
|
2021-09-16 11:10:56 +00:00
|
|
|
struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
|
2022-03-09 06:44:18 +00:00
|
|
|
struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
|
2020-11-23 04:48:51 +00:00
|
|
|
uint32_t max_xfer_size = spdk_nvme_ns_get_max_io_xfer_size(ns);
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
|
2017-06-05 18:02:09 +00:00
|
|
|
|
2018-05-08 23:07:30 +00:00
|
|
|
if (nbytes > max_xfer_size) {
|
|
|
|
SPDK_ERRLOG("nbytes is greater than MDTS %" PRIu32 ".\n", max_xfer_size);
|
2017-06-05 18:02:09 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Each NVMe bdev is a specific namespace, and all NVMe I/O commands require a nsid,
|
|
|
|
* so fill it out automatically.
|
|
|
|
*/
|
2020-11-23 04:48:51 +00:00
|
|
|
cmd->nsid = spdk_nvme_ns_get_id(ns);
|
2017-06-05 18:02:09 +00:00
|
|
|
|
2020-11-23 04:48:51 +00:00
|
|
|
return spdk_nvme_ctrlr_cmd_io_raw(ctrlr, qpair, cmd, buf,
|
2017-06-05 18:02:09 +00:00
|
|
|
(uint32_t)nbytes, bdev_nvme_queued_done, bio);
|
|
|
|
}
|
|
|
|
|
2017-11-14 06:33:11 +00:00
|
|
|
static int
|
2021-09-16 11:10:56 +00:00
|
|
|
bdev_nvme_io_passthru_md(struct nvme_bdev_io *bio, struct spdk_nvme_cmd *cmd,
|
|
|
|
void *buf, size_t nbytes, void *md_buf, size_t md_len)
|
2017-11-14 06:33:11 +00:00
|
|
|
{
|
2021-09-16 11:10:56 +00:00
|
|
|
struct spdk_nvme_ns *ns = bio->io_path->nvme_ns->ns;
|
2022-03-09 06:44:18 +00:00
|
|
|
struct spdk_nvme_qpair *qpair = bio->io_path->qpair->qpair;
|
2020-11-23 04:48:51 +00:00
|
|
|
size_t nr_sectors = nbytes / spdk_nvme_ns_get_extended_sector_size(ns);
|
|
|
|
uint32_t max_xfer_size = spdk_nvme_ns_get_max_io_xfer_size(ns);
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
|
2017-11-14 06:33:11 +00:00
|
|
|
|
2018-05-08 23:07:30 +00:00
|
|
|
if (nbytes > max_xfer_size) {
|
|
|
|
SPDK_ERRLOG("nbytes is greater than MDTS %" PRIu32 ".\n", max_xfer_size);
|
2017-11-14 06:33:11 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-11-23 04:48:51 +00:00
|
|
|
if (md_len != nr_sectors * spdk_nvme_ns_get_md_size(ns)) {
|
2017-11-14 06:33:11 +00:00
|
|
|
SPDK_ERRLOG("invalid meta data buffer size\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Each NVMe bdev is a specific namespace, and all NVMe I/O commands require a nsid,
|
|
|
|
* so fill it out automatically.
|
|
|
|
*/
|
2020-11-23 04:48:51 +00:00
|
|
|
cmd->nsid = spdk_nvme_ns_get_id(ns);
|
2017-11-14 06:33:11 +00:00
|
|
|
|
2020-11-23 04:48:51 +00:00
|
|
|
return spdk_nvme_ctrlr_cmd_io_raw_with_md(ctrlr, qpair, cmd, buf,
|
2017-11-14 06:33:11 +00:00
|
|
|
(uint32_t)nbytes, md_buf, bdev_nvme_queued_done, bio);
|
|
|
|
}
|
|
|
|
|
2021-09-28 05:37:36 +00:00
|
|
|
static void
|
2021-07-06 17:35:01 +00:00
|
|
|
bdev_nvme_abort(struct nvme_bdev_channel *nbdev_ch, struct nvme_bdev_io *bio,
|
2020-11-23 06:43:41 +00:00
|
|
|
struct nvme_bdev_io *bio_to_abort)
|
2020-07-08 08:03:49 +00:00
|
|
|
{
|
2021-10-21 20:15:09 +00:00
|
|
|
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
|
2021-09-27 23:15:02 +00:00
|
|
|
struct nvme_io_path *io_path;
|
2021-08-11 08:11:19 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr;
|
2021-09-27 23:15:02 +00:00
|
|
|
int rc = 0;
|
2020-07-08 08:03:49 +00:00
|
|
|
|
2021-03-31 01:26:55 +00:00
|
|
|
bio->orig_thread = spdk_get_thread();
|
2020-07-08 08:03:49 +00:00
|
|
|
|
2023-01-12 04:09:27 +00:00
|
|
|
rc = bdev_nvme_abort_retry_io(nbdev_ch, bio_to_abort);
|
|
|
|
if (rc == 0) {
|
|
|
|
__bdev_nvme_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS, NULL);
|
|
|
|
return;
|
2021-10-21 20:15:09 +00:00
|
|
|
}
|
|
|
|
|
2023-01-12 04:09:27 +00:00
|
|
|
rc = 0;
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
/* Even admin commands, they were submitted to only nvme_ctrlrs which were
|
|
|
|
* on any io_path. So traverse the io_path list for not only I/O commands
|
|
|
|
* but also admin commands.
|
|
|
|
*/
|
|
|
|
STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
|
2022-03-09 06:44:18 +00:00
|
|
|
nvme_ctrlr = io_path->qpair->ctrlr;
|
2021-08-11 08:11:19 +00:00
|
|
|
|
|
|
|
rc = spdk_nvme_ctrlr_cmd_abort_ext(nvme_ctrlr->ctrlr,
|
2022-03-09 06:44:18 +00:00
|
|
|
io_path->qpair->qpair,
|
2021-05-31 07:11:13 +00:00
|
|
|
bio_to_abort,
|
|
|
|
bdev_nvme_abort_done, bio);
|
2021-09-27 23:15:02 +00:00
|
|
|
if (rc == -ENOENT) {
|
|
|
|
/* If no command was found in I/O qpair, the target command may be
|
|
|
|
* admin command.
|
|
|
|
*/
|
|
|
|
rc = spdk_nvme_ctrlr_cmd_abort_ext(nvme_ctrlr->ctrlr,
|
|
|
|
NULL,
|
|
|
|
bio_to_abort,
|
|
|
|
bdev_nvme_abort_done, bio);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc != -ENOENT) {
|
|
|
|
break;
|
|
|
|
}
|
2021-05-31 07:11:13 +00:00
|
|
|
}
|
|
|
|
|
2021-09-28 05:37:36 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
/* If no command was found or there was any error, complete the abort
|
|
|
|
* request with failure.
|
|
|
|
*/
|
2022-08-11 00:21:53 +00:00
|
|
|
__bdev_nvme_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED, NULL);
|
2020-07-08 08:03:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-22 12:47:31 +00:00
|
|
|
static int
|
|
|
|
bdev_nvme_copy(struct nvme_bdev_io *bio, uint64_t dst_offset_blocks, uint64_t src_offset_blocks,
|
|
|
|
uint64_t num_blocks)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_scc_source_range range = {
|
|
|
|
.slba = src_offset_blocks,
|
|
|
|
.nlb = num_blocks - 1
|
|
|
|
};
|
|
|
|
|
|
|
|
return spdk_nvme_ns_cmd_copy(bio->io_path->nvme_ns->ns,
|
|
|
|
bio->io_path->qpair->qpair,
|
|
|
|
&range, 1, dst_offset_blocks,
|
|
|
|
bdev_nvme_queued_done, bio);
|
|
|
|
}
|
|
|
|
|
2020-12-07 18:46:51 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_opts_config_json(struct spdk_json_write_ctx *w)
|
2018-04-05 15:43:55 +00:00
|
|
|
{
|
2020-12-07 18:46:51 +00:00
|
|
|
const char *action;
|
2018-07-09 21:04:33 +00:00
|
|
|
|
|
|
|
if (g_opts.action_on_timeout == SPDK_BDEV_NVME_TIMEOUT_ACTION_RESET) {
|
|
|
|
action = "reset";
|
|
|
|
} else if (g_opts.action_on_timeout == SPDK_BDEV_NVME_TIMEOUT_ACTION_ABORT) {
|
|
|
|
action = "abort";
|
|
|
|
} else {
|
|
|
|
action = "none";
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_json_write_object_begin(w);
|
|
|
|
|
2019-08-22 12:44:02 +00:00
|
|
|
spdk_json_write_named_string(w, "method", "bdev_nvme_set_options");
|
2018-07-09 21:04:33 +00:00
|
|
|
|
|
|
|
spdk_json_write_named_object_begin(w, "params");
|
|
|
|
spdk_json_write_named_string(w, "action_on_timeout", action);
|
|
|
|
spdk_json_write_named_uint64(w, "timeout_us", g_opts.timeout_us);
|
2021-06-02 17:42:34 +00:00
|
|
|
spdk_json_write_named_uint64(w, "timeout_admin_us", g_opts.timeout_admin_us);
|
2020-12-09 21:44:31 +00:00
|
|
|
spdk_json_write_named_uint32(w, "keep_alive_timeout_ms", g_opts.keep_alive_timeout_ms);
|
2021-10-18 19:33:01 +00:00
|
|
|
spdk_json_write_named_uint32(w, "transport_retry_count", g_opts.transport_retry_count);
|
2019-09-03 03:48:49 +00:00
|
|
|
spdk_json_write_named_uint32(w, "arbitration_burst", g_opts.arbitration_burst);
|
|
|
|
spdk_json_write_named_uint32(w, "low_priority_weight", g_opts.low_priority_weight);
|
|
|
|
spdk_json_write_named_uint32(w, "medium_priority_weight", g_opts.medium_priority_weight);
|
|
|
|
spdk_json_write_named_uint32(w, "high_priority_weight", g_opts.high_priority_weight);
|
2018-07-09 21:04:33 +00:00
|
|
|
spdk_json_write_named_uint64(w, "nvme_adminq_poll_period_us", g_opts.nvme_adminq_poll_period_us);
|
2019-03-11 22:26:53 +00:00
|
|
|
spdk_json_write_named_uint64(w, "nvme_ioq_poll_period_us", g_opts.nvme_ioq_poll_period_us);
|
2019-07-10 05:13:31 +00:00
|
|
|
spdk_json_write_named_uint32(w, "io_queue_requests", g_opts.io_queue_requests);
|
2019-11-18 17:11:39 +00:00
|
|
|
spdk_json_write_named_bool(w, "delay_cmd_submit", g_opts.delay_cmd_submit);
|
2021-10-25 02:59:46 +00:00
|
|
|
spdk_json_write_named_int32(w, "bdev_retry_count", g_opts.bdev_retry_count);
|
2022-01-20 12:22:06 +00:00
|
|
|
spdk_json_write_named_uint8(w, "transport_ack_timeout", g_opts.transport_ack_timeout);
|
2022-03-09 12:04:14 +00:00
|
|
|
spdk_json_write_named_int32(w, "ctrlr_loss_timeout_sec", g_opts.ctrlr_loss_timeout_sec);
|
|
|
|
spdk_json_write_named_uint32(w, "reconnect_delay_sec", g_opts.reconnect_delay_sec);
|
|
|
|
spdk_json_write_named_uint32(w, "fast_io_fail_timeout_sec", g_opts.fast_io_fail_timeout_sec);
|
2022-10-24 12:53:22 +00:00
|
|
|
spdk_json_write_named_bool(w, "generate_uuids", g_opts.generate_uuids);
|
2022-12-14 20:24:27 +00:00
|
|
|
spdk_json_write_named_uint8(w, "transport_tos", g_opts.transport_tos);
|
2022-09-29 03:52:43 +00:00
|
|
|
spdk_json_write_named_bool(w, "io_path_stat", g_opts.io_path_stat);
|
2018-07-09 21:04:33 +00:00
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
2020-12-07 18:46:51 +00:00
|
|
|
}
|
2018-04-05 15:43:55 +00:00
|
|
|
|
2022-03-04 20:38:59 +00:00
|
|
|
static void
|
|
|
|
bdev_nvme_discovery_config_json(struct spdk_json_write_ctx *w, struct discovery_ctx *ctx)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_transport_id trid;
|
|
|
|
|
|
|
|
spdk_json_write_object_begin(w);
|
|
|
|
|
|
|
|
spdk_json_write_named_string(w, "method", "bdev_nvme_start_discovery");
|
|
|
|
|
|
|
|
spdk_json_write_named_object_begin(w, "params");
|
|
|
|
spdk_json_write_named_string(w, "name", ctx->name);
|
|
|
|
spdk_json_write_named_string(w, "hostnqn", ctx->hostnqn);
|
|
|
|
|
|
|
|
trid = ctx->trid;
|
|
|
|
memset(trid.subnqn, 0, sizeof(trid.subnqn));
|
|
|
|
nvme_bdev_dump_trid_json(&trid, w);
|
|
|
|
|
2022-03-25 19:08:00 +00:00
|
|
|
spdk_json_write_named_bool(w, "wait_for_attach", ctx->wait_for_attach);
|
2022-03-04 20:38:59 +00:00
|
|
|
spdk_json_write_named_int32(w, "ctrlr_loss_timeout_sec", ctx->bdev_opts.ctrlr_loss_timeout_sec);
|
|
|
|
spdk_json_write_named_uint32(w, "reconnect_delay_sec", ctx->bdev_opts.reconnect_delay_sec);
|
|
|
|
spdk_json_write_named_uint32(w, "fast_io_fail_timeout_sec",
|
|
|
|
ctx->bdev_opts.fast_io_fail_timeout_sec);
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
|
2020-12-07 18:46:51 +00:00
|
|
|
static void
|
2021-07-06 19:42:41 +00:00
|
|
|
nvme_ctrlr_config_json(struct spdk_json_write_ctx *w,
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr)
|
2020-12-07 18:46:51 +00:00
|
|
|
{
|
|
|
|
struct spdk_nvme_transport_id *trid;
|
2018-04-05 15:43:55 +00:00
|
|
|
|
2022-03-04 20:38:59 +00:00
|
|
|
if (nvme_ctrlr->opts.from_discovery_service) {
|
|
|
|
/* Do not emit an RPC for this - it will be implicitly
|
nvme: Added support for TP-8009, Auto-discovery of Discovery controllers for NVME initiator using mDNS using Avahi
Approach:
Avahi Daemon needs to be running to provide the mDNS server service. In the SPDK, Avahi-client library based client API is implemented.
The client API will connect to the Avahi-daemon and receive events for new discovery and removal of an existing discovery entry.
Following sets on new RPCs have been introduced.
scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
User shall initiate an mDNS based discovery using this RPC. This will start a Avahi-client based poller
looking for new discovery events from the Avahi server. On a new discovery of the discovery controller,
the existing bdev_nvme_start_discovery API will be invoked with the trid of the discovery controller learnt.
This will enable automatic connection of the initiator to the subsystems discovered from the discovery controller.
Multiple mdns discovery instances can be run by specifying a unique bdev-prefix and a unique servicename to discover as parameters.
scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
This will stop the Avahi poller that was started for the specified service.Internally bdev_nvme_stop_discovery
API will be invoked for each of the discovery controllers learnt automatically by this instance of mdns discovery service.
This will result in termination of connections to all the subsystems learnt by this mdns discovery instance.
scripts/rpc.py bdev_nvme_get_mdns_discovery_info
This RPC will display the list of mdns discovery instances running and the trid of the controllers discovered by these instances.
Test Result:
root@ubuntu-pm-18-226:~/param-spdk/spdk/build/bin# ./nvmf_tgt -i 1 -s 2048 -m 0xF
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[
{
"name": "cdc_auto",
"svcname": "_nvme-disc._tcp",
"referrals": [
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
}
]
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[
{
"name": "cdc_auto02n1",
"aliases": [
"600110d6-1681-1681-0403-000045805c45"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-1681-1681-0403-000045805c45",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T0",
"serial_number": "00-681681dc681681dc",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto00n1",
"aliases": [
"600110da-09a6-09a6-0302-00005eeb19b4"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 2048,
"uuid": "600110da-09a6-09a6-0302-00005eeb19b4",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0"
},
"ctrlr_data": {
"cntlid": 1,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P2T0",
"serial_number": "00-ab09a6f5ab09a6f5",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n1",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8c"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8c",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n2",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8d"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8d",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 2,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
Signed-off-by: Parameswaran Krishnamurthy <parameswaran.krishna@dell.com>
Change-Id: Ic2c2e614e2549a655c7f81ae844b80d8505a4f02
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15703
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Boris Glimcher <Boris.Glimcher@emc.com>
Reviewed-by: <qun.wan@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
2022-11-30 20:11:23 +00:00
|
|
|
* covered by a separate bdev_nvme_start_discovery or
|
|
|
|
* bdev_nvme_start_mdns_discovery RPC.
|
2022-03-04 20:38:59 +00:00
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-21 19:17:12 +00:00
|
|
|
trid = &nvme_ctrlr->active_path_id->trid;
|
2018-04-05 15:43:55 +00:00
|
|
|
|
2020-12-07 18:46:51 +00:00
|
|
|
spdk_json_write_object_begin(w);
|
2018-04-05 15:43:55 +00:00
|
|
|
|
2020-12-07 18:46:51 +00:00
|
|
|
spdk_json_write_named_string(w, "method", "bdev_nvme_attach_controller");
|
2018-04-05 15:43:55 +00:00
|
|
|
|
2020-12-07 18:46:51 +00:00
|
|
|
spdk_json_write_named_object_begin(w, "params");
|
2021-09-07 16:13:07 +00:00
|
|
|
spdk_json_write_named_string(w, "name", nvme_ctrlr->nbdev_ctrlr->name);
|
2020-12-07 18:46:51 +00:00
|
|
|
nvme_bdev_dump_trid_json(trid, w);
|
|
|
|
spdk_json_write_named_bool(w, "prchk_reftag",
|
2022-03-04 04:51:53 +00:00
|
|
|
(nvme_ctrlr->opts.prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_REFTAG) != 0);
|
2020-12-07 18:46:51 +00:00
|
|
|
spdk_json_write_named_bool(w, "prchk_guard",
|
2022-03-04 04:51:53 +00:00
|
|
|
(nvme_ctrlr->opts.prchk_flags & SPDK_NVME_IO_FLAGS_PRCHK_GUARD) != 0);
|
|
|
|
spdk_json_write_named_int32(w, "ctrlr_loss_timeout_sec", nvme_ctrlr->opts.ctrlr_loss_timeout_sec);
|
|
|
|
spdk_json_write_named_uint32(w, "reconnect_delay_sec", nvme_ctrlr->opts.reconnect_delay_sec);
|
|
|
|
spdk_json_write_named_uint32(w, "fast_io_fail_timeout_sec",
|
|
|
|
nvme_ctrlr->opts.fast_io_fail_timeout_sec);
|
2018-04-05 15:43:55 +00:00
|
|
|
|
2020-12-07 18:46:51 +00:00
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bdev_nvme_hotplug_config_json(struct spdk_json_write_ctx *w)
|
|
|
|
{
|
|
|
|
spdk_json_write_object_begin(w);
|
|
|
|
spdk_json_write_named_string(w, "method", "bdev_nvme_set_hotplug");
|
|
|
|
|
|
|
|
spdk_json_write_named_object_begin(w, "params");
|
|
|
|
spdk_json_write_named_uint64(w, "period_us", g_nvme_hotplug_poll_period_us);
|
|
|
|
spdk_json_write_named_bool(w, "enable", g_nvme_hotplug_enabled);
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bdev_nvme_config_json(struct spdk_json_write_ctx *w)
|
|
|
|
{
|
2021-09-07 16:13:07 +00:00
|
|
|
struct nvme_bdev_ctrlr *nbdev_ctrlr;
|
2021-07-06 19:42:41 +00:00
|
|
|
struct nvme_ctrlr *nvme_ctrlr;
|
2022-03-04 20:38:59 +00:00
|
|
|
struct discovery_ctx *ctx;
|
2020-12-07 18:46:51 +00:00
|
|
|
|
|
|
|
bdev_nvme_opts_config_json(w);
|
|
|
|
|
|
|
|
pthread_mutex_lock(&g_bdev_nvme_mutex);
|
|
|
|
|
2021-09-07 16:13:07 +00:00
|
|
|
TAILQ_FOREACH(nbdev_ctrlr, &g_nvme_bdev_ctrlrs, tailq) {
|
|
|
|
TAILQ_FOREACH(nvme_ctrlr, &nbdev_ctrlr->ctrlrs, tailq) {
|
|
|
|
nvme_ctrlr_config_json(w, nvme_ctrlr);
|
|
|
|
}
|
2018-04-05 15:43:55 +00:00
|
|
|
}
|
|
|
|
|
2022-03-04 20:38:59 +00:00
|
|
|
TAILQ_FOREACH(ctx, &g_discovery_ctxs, tailq) {
|
nvme: Added support for TP-8009, Auto-discovery of Discovery controllers for NVME initiator using mDNS using Avahi
Approach:
Avahi Daemon needs to be running to provide the mDNS server service. In the SPDK, Avahi-client library based client API is implemented.
The client API will connect to the Avahi-daemon and receive events for new discovery and removal of an existing discovery entry.
Following sets on new RPCs have been introduced.
scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
User shall initiate an mDNS based discovery using this RPC. This will start a Avahi-client based poller
looking for new discovery events from the Avahi server. On a new discovery of the discovery controller,
the existing bdev_nvme_start_discovery API will be invoked with the trid of the discovery controller learnt.
This will enable automatic connection of the initiator to the subsystems discovered from the discovery controller.
Multiple mdns discovery instances can be run by specifying a unique bdev-prefix and a unique servicename to discover as parameters.
scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
This will stop the Avahi poller that was started for the specified service.Internally bdev_nvme_stop_discovery
API will be invoked for each of the discovery controllers learnt automatically by this instance of mdns discovery service.
This will result in termination of connections to all the subsystems learnt by this mdns discovery instance.
scripts/rpc.py bdev_nvme_get_mdns_discovery_info
This RPC will display the list of mdns discovery instances running and the trid of the controllers discovered by these instances.
Test Result:
root@ubuntu-pm-18-226:~/param-spdk/spdk/build/bin# ./nvmf_tgt -i 1 -s 2048 -m 0xF
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[
{
"name": "cdc_auto",
"svcname": "_nvme-disc._tcp",
"referrals": [
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
}
]
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[
{
"name": "cdc_auto02n1",
"aliases": [
"600110d6-1681-1681-0403-000045805c45"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-1681-1681-0403-000045805c45",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T0",
"serial_number": "00-681681dc681681dc",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto00n1",
"aliases": [
"600110da-09a6-09a6-0302-00005eeb19b4"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 2048,
"uuid": "600110da-09a6-09a6-0302-00005eeb19b4",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0"
},
"ctrlr_data": {
"cntlid": 1,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P2T0",
"serial_number": "00-ab09a6f5ab09a6f5",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n1",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8c"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8c",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n2",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8d"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8d",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 2,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
Signed-off-by: Parameswaran Krishnamurthy <parameswaran.krishna@dell.com>
Change-Id: Ic2c2e614e2549a655c7f81ae844b80d8505a4f02
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15703
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Boris Glimcher <Boris.Glimcher@emc.com>
Reviewed-by: <qun.wan@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
2022-11-30 20:11:23 +00:00
|
|
|
if (!ctx->from_mdns_discovery_service) {
|
|
|
|
bdev_nvme_discovery_config_json(w, ctx);
|
|
|
|
}
|
2022-03-04 20:38:59 +00:00
|
|
|
}
|
|
|
|
|
nvme: Added support for TP-8009, Auto-discovery of Discovery controllers for NVME initiator using mDNS using Avahi
Approach:
Avahi Daemon needs to be running to provide the mDNS server service. In the SPDK, Avahi-client library based client API is implemented.
The client API will connect to the Avahi-daemon and receive events for new discovery and removal of an existing discovery entry.
Following sets on new RPCs have been introduced.
scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
User shall initiate an mDNS based discovery using this RPC. This will start a Avahi-client based poller
looking for new discovery events from the Avahi server. On a new discovery of the discovery controller,
the existing bdev_nvme_start_discovery API will be invoked with the trid of the discovery controller learnt.
This will enable automatic connection of the initiator to the subsystems discovered from the discovery controller.
Multiple mdns discovery instances can be run by specifying a unique bdev-prefix and a unique servicename to discover as parameters.
scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
This will stop the Avahi poller that was started for the specified service.Internally bdev_nvme_stop_discovery
API will be invoked for each of the discovery controllers learnt automatically by this instance of mdns discovery service.
This will result in termination of connections to all the subsystems learnt by this mdns discovery instance.
scripts/rpc.py bdev_nvme_get_mdns_discovery_info
This RPC will display the list of mdns discovery instances running and the trid of the controllers discovered by these instances.
Test Result:
root@ubuntu-pm-18-226:~/param-spdk/spdk/build/bin# ./nvmf_tgt -i 1 -s 2048 -m 0xF
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_start_mdns_discovery -b cdc_auto -s _nvme-disc._tcp
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[
{
"name": "cdc_auto",
"svcname": "_nvme-disc._tcp",
"referrals": [
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
}
}
]
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[
{
"name": "cdc_auto0",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
},
{
"name": "cdc_auto1",
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.21",
"trsvcid": "8009",
"subnqn": "nqn.2014-08.org.nvmexpress.discovery"
},
"referrals": []
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[
{
"name": "cdc_auto02n1",
"aliases": [
"600110d6-1681-1681-0403-000045805c45"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-1681-1681-0403-000045805c45",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T0",
"serial_number": "00-681681dc681681dc",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto00n1",
"aliases": [
"600110da-09a6-09a6-0302-00005eeb19b4"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 2048,
"uuid": "600110da-09a6-09a6-0302-00005eeb19b4",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.2.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0"
},
"ctrlr_data": {
"cntlid": 1,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P2T0",
"serial_number": "00-ab09a6f5ab09a6f5",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.2.0",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n1",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8c"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8c",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 1,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
},
{
"name": "cdc_auto01n2",
"aliases": [
"600110d6-dce8-dce8-0403-00010b2d3d8d"
],
"product_name": "NVMe disk",
"block_size": 512,
"num_blocks": 32768,
"uuid": "600110d6-dce8-dce8-0403-00010b2d3d8d",
"assigned_rate_limits": {
"rw_ios_per_sec": 0,
"rw_mbytes_per_sec": 0,
"r_mbytes_per_sec": 0,
"w_mbytes_per_sec": 0
},
"claimed": false,
"zoned": false,
"supported_io_types": {
"read": true,
"write": true,
"unmap": true,
"write_zeroes": true,
"flush": true,
"reset": true,
"compare": true,
"compare_and_write": true,
"abort": true,
"nvme_admin": true,
"nvme_io": true
},
"driver_specific": {
"nvme": [
{
"trid": {
"trtype": "TCP",
"adrfam": "IPv4",
"traddr": "66.1.1.40",
"trsvcid": "4420",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1"
},
"ctrlr_data": {
"cntlid": 3,
"vendor_id": "0x0000",
"model_number": "SANBlaze VLUN P3T1",
"serial_number": "01-6ddce86d6ddce86d",
"firmware_revision": "V10.5",
"subnqn": "nqn.2014-08.com.sanblaze:virtualun.virtualun.3.1",
"oacs": {
"security": 0,
"format": 1,
"firmware": 0,
"ns_manage": 1
},
"multi_ctrlr": true,
"ana_reporting": true
},
"vs": {
"nvme_version": "2.0"
},
"ns_data": {
"id": 2,
"ana_state": "optimized",
"can_share": true
}
}
],
"mp_policy": "active_passive"
}
}
]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_stop_mdns_discovery -b cdc_auto
root@ubuntu-pm-18-226:~/param-spdk/spdk#
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_mdns_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_nvme_get_discovery_info
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk# scripts/rpc.py bdev_get_bdevs
[]
root@ubuntu-pm-18-226:~/param-spdk/spdk#
Signed-off-by: Parameswaran Krishnamurthy <parameswaran.krishna@dell.com>
Change-Id: Ic2c2e614e2549a655c7f81ae844b80d8505a4f02
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15703
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Boris Glimcher <Boris.Glimcher@emc.com>
Reviewed-by: <qun.wan@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
2022-11-30 20:11:23 +00:00
|
|
|
bdev_nvme_mdns_discovery_config_json(w);
|
|
|
|
|
2018-07-12 12:26:19 +00:00
|
|
|
/* Dump as last parameter to give all NVMe bdevs chance to be constructed
|
|
|
|
* before enabling hotplug poller.
|
|
|
|
*/
|
2020-12-07 18:46:51 +00:00
|
|
|
bdev_nvme_hotplug_config_json(w);
|
2018-07-12 12:26:19 +00:00
|
|
|
|
2018-04-05 15:43:55 +00:00
|
|
|
pthread_mutex_unlock(&g_bdev_nvme_mutex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-11 23:32:32 +00:00
|
|
|
struct spdk_nvme_ctrlr *
|
2020-05-10 07:46:07 +00:00
|
|
|
bdev_nvme_get_ctrlr(struct spdk_bdev *bdev)
|
2017-07-11 23:32:32 +00:00
|
|
|
{
|
2021-09-27 23:15:02 +00:00
|
|
|
struct nvme_bdev *nbdev;
|
|
|
|
struct nvme_ns *nvme_ns;
|
|
|
|
|
2018-03-06 18:52:46 +00:00
|
|
|
if (!bdev || bdev->module != &nvme_if) {
|
2017-07-11 23:32:32 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-09-27 23:15:02 +00:00
|
|
|
nbdev = SPDK_CONTAINEROF(bdev, struct nvme_bdev, disk);
|
|
|
|
nvme_ns = TAILQ_FIRST(&nbdev->nvme_ns_list);
|
|
|
|
assert(nvme_ns != NULL);
|
|
|
|
|
|
|
|
return nvme_ns->ctrlr->ctrlr;
|
2017-07-11 23:32:32 +00:00
|
|
|
}
|
|
|
|
|
2022-04-06 02:47:33 +00:00
|
|
|
void
|
|
|
|
nvme_io_path_info_json(struct spdk_json_write_ctx *w, struct nvme_io_path *io_path)
|
|
|
|
{
|
|
|
|
struct nvme_ns *nvme_ns = io_path->nvme_ns;
|
|
|
|
struct nvme_ctrlr *nvme_ctrlr = io_path->qpair->ctrlr;
|
|
|
|
const struct spdk_nvme_ctrlr_data *cdata;
|
2022-07-13 06:25:58 +00:00
|
|
|
const struct spdk_nvme_transport_id *trid;
|
|
|
|
const char *adrfam_str;
|
2022-04-06 02:47:33 +00:00
|
|
|
|
|
|
|
spdk_json_write_object_begin(w);
|
|
|
|
|
|
|
|
spdk_json_write_named_string(w, "bdev_name", nvme_ns->bdev->disk.name);
|
|
|
|
|
|
|
|
cdata = spdk_nvme_ctrlr_get_data(nvme_ctrlr->ctrlr);
|
2022-07-13 06:25:58 +00:00
|
|
|
trid = spdk_nvme_ctrlr_get_transport_id(nvme_ctrlr->ctrlr);
|
2022-04-06 02:47:33 +00:00
|
|
|
|
|
|
|
spdk_json_write_named_uint32(w, "cntlid", cdata->cntlid);
|
|
|
|
spdk_json_write_named_bool(w, "current", io_path == io_path->nbdev_ch->current_io_path);
|
|
|
|
spdk_json_write_named_bool(w, "connected", nvme_io_path_is_connected(io_path));
|
|
|
|
spdk_json_write_named_bool(w, "accessible", nvme_ns_is_accessible(nvme_ns));
|
|
|
|
|
2022-07-13 06:25:58 +00:00
|
|
|
spdk_json_write_named_object_begin(w, "transport");
|
|
|
|
spdk_json_write_named_string(w, "trtype", trid->trstring);
|
|
|
|
spdk_json_write_named_string(w, "traddr", trid->traddr);
|
|
|
|
if (trid->trsvcid[0] != '\0') {
|
|
|
|
spdk_json_write_named_string(w, "trsvcid", trid->trsvcid);
|
|
|
|
}
|
|
|
|
adrfam_str = spdk_nvme_transport_id_adrfam_str(trid->adrfam);
|
|
|
|
if (adrfam_str) {
|
|
|
|
spdk_json_write_named_string(w, "adrfam", adrfam_str);
|
|
|
|
}
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
2022-04-06 02:47:33 +00:00
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
|
2022-04-26 10:01:49 +00:00
|
|
|
void
|
|
|
|
bdev_nvme_get_discovery_info(struct spdk_json_write_ctx *w)
|
|
|
|
{
|
|
|
|
struct discovery_ctx *ctx;
|
|
|
|
struct discovery_entry_ctx *entry_ctx;
|
|
|
|
|
|
|
|
spdk_json_write_array_begin(w);
|
|
|
|
TAILQ_FOREACH(ctx, &g_discovery_ctxs, tailq) {
|
|
|
|
spdk_json_write_object_begin(w);
|
|
|
|
spdk_json_write_named_string(w, "name", ctx->name);
|
|
|
|
|
|
|
|
spdk_json_write_named_object_begin(w, "trid");
|
|
|
|
nvme_bdev_dump_trid_json(&ctx->trid, w);
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
|
|
|
|
spdk_json_write_named_array_begin(w, "referrals");
|
|
|
|
TAILQ_FOREACH(entry_ctx, &ctx->discovery_entry_ctxs, tailq) {
|
|
|
|
spdk_json_write_object_begin(w);
|
|
|
|
spdk_json_write_named_object_begin(w, "trid");
|
|
|
|
nvme_bdev_dump_trid_json(&entry_ctx->trid, w);
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
spdk_json_write_array_end(w);
|
|
|
|
|
|
|
|
spdk_json_write_object_end(w);
|
|
|
|
}
|
|
|
|
spdk_json_write_array_end(w);
|
|
|
|
}
|
|
|
|
|
2020-09-04 11:27:29 +00:00
|
|
|
SPDK_LOG_REGISTER_COMPONENT(bdev_nvme)
|
2022-08-11 00:04:56 +00:00
|
|
|
|
|
|
|
SPDK_TRACE_REGISTER_FN(bdev_nvme_trace, "bdev_nvme", TRACE_GROUP_BDEV_NVME)
|
|
|
|
{
|
|
|
|
struct spdk_trace_tpoint_opts opts[] = {
|
|
|
|
{
|
|
|
|
"BDEV_NVME_IO_START", TRACE_BDEV_NVME_IO_START,
|
|
|
|
OWNER_NONE, OBJECT_BDEV_NVME_IO, 1,
|
|
|
|
{{ "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 }}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"BDEV_NVME_IO_DONE", TRACE_BDEV_NVME_IO_DONE,
|
|
|
|
OWNER_NONE, OBJECT_BDEV_NVME_IO, 0,
|
|
|
|
{{ "ctx", SPDK_TRACE_ARG_TYPE_PTR, 8 }}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
spdk_trace_register_object(OBJECT_BDEV_NVME_IO, 'N');
|
|
|
|
spdk_trace_register_description_ext(opts, SPDK_COUNTOF(opts));
|
2022-08-10 22:29:42 +00:00
|
|
|
spdk_trace_tpoint_register_relation(TRACE_NVME_PCIE_SUBMIT, OBJECT_BDEV_NVME_IO, 0);
|
|
|
|
spdk_trace_tpoint_register_relation(TRACE_NVME_TCP_SUBMIT, OBJECT_BDEV_NVME_IO, 0);
|
|
|
|
spdk_trace_tpoint_register_relation(TRACE_NVME_PCIE_COMPLETE, OBJECT_BDEV_NVME_IO, 0);
|
|
|
|
spdk_trace_tpoint_register_relation(TRACE_NVME_TCP_COMPLETE, OBJECT_BDEV_NVME_IO, 0);
|
2022-08-11 00:04:56 +00:00
|
|
|
}
|