diff --git a/lib/libnvmf/libnvmf.h b/lib/libnvmf/libnvmf.h --- a/lib/libnvmf/libnvmf.h +++ b/lib/libnvmf/libnvmf.h @@ -364,4 +364,9 @@ const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues, struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata); +/* + * Fetch connection status from an existing kernel host. + */ +int nvmf_connection_status(int fd, nvlist_t **nvlp); + #endif /* !__LIBNVMF_H__ */ diff --git a/lib/libnvmf/nvmf_host.c b/lib/libnvmf/nvmf_host.c --- a/lib/libnvmf/nvmf_host.c +++ b/lib/libnvmf/nvmf_host.c @@ -5,6 +5,7 @@ * Written by: John Baldwin */ +#include #include #include #include @@ -980,3 +981,9 @@ (void)nvmf_free_qpair(admin_qp); return (error); } + +int +nvmf_connection_status(int fd, nvlist_t **nvlp) +{ + return (nvmf_read_ioc_nv(fd, NVMF_CONNECTION_STATUS, nvlp)); +} diff --git a/sys/dev/nvmf/host/nvmf.c b/sys/dev/nvmf/host/nvmf.c --- a/sys/dev/nvmf/host/nvmf.c +++ b/sys/dev/nvmf/host/nvmf.c @@ -654,6 +654,7 @@ return; } + nanotime(&sc->last_disconnect); callout_drain(&sc->ka_tx_timer); callout_drain(&sc->ka_rx_timer); sc->ka_traffic = false; @@ -1073,6 +1074,27 @@ return (error); } +static int +nvmf_connection_status(struct nvmf_softc *sc, struct nvmf_ioc_nv *nv) +{ + nvlist_t *nvl, *nvl_ts; + int error; + + nvl = nvlist_create(0); + nvl_ts = nvlist_create(0); + + sx_slock(&sc->connection_lock); + nvlist_add_bool(nvl, "connected", sc->admin != NULL); + nvlist_add_number(nvl_ts, "tv_sec", sc->last_disconnect.tv_sec); + nvlist_add_number(nvl_ts, "tv_nsec", sc->last_disconnect.tv_nsec); + sx_sunlock(&sc->connection_lock); + nvlist_move_nvlist(nvl, "last_disconnect", nvl_ts); + + error = nvmf_pack_ioc_nvlist(nvl, nv); + nvlist_destroy(nvl); + return (error); +} + static int nvmf_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int flag, struct thread *td) @@ -1104,6 +1126,9 @@ case NVMF_RECONNECT_HOST: nv = (struct nvmf_ioc_nv *)arg; return (nvmf_reconnect_host(sc, nv)); + case NVMF_CONNECTION_STATUS: + nv = (struct nvmf_ioc_nv *)arg; + return (nvmf_connection_status(sc, nv)); default: return (ENOTTY); } diff --git a/sys/dev/nvmf/host/nvmf_var.h b/sys/dev/nvmf/host/nvmf_var.h --- a/sys/dev/nvmf/host/nvmf_var.h +++ b/sys/dev/nvmf/host/nvmf_var.h @@ -86,6 +86,8 @@ nvlist_t *rparams; + struct timespec last_disconnect; + eventhandler_tag shutdown_pre_sync_eh; eventhandler_tag shutdown_post_sync_eh; }; diff --git a/sys/dev/nvmf/nvmf.h b/sys/dev/nvmf/nvmf.h --- a/sys/dev/nvmf/nvmf.h +++ b/sys/dev/nvmf/nvmf.h @@ -90,6 +90,15 @@ * bool data_digests */ +/* + * The fields in the nvlist for NVMF_CONNECTION_STATUS are: + * + * bool connected + * timespec nvlist last_disconnect + * number tv_sec + * number tv_nsec + */ + /* * The fields in the nvlist for handing off a controller qpair are: * @@ -107,5 +116,6 @@ /* Operations on /dev/nvmeX */ #define NVMF_RECONNECT_PARAMS _IOWR('n', 203, struct nvmf_ioc_nv) #define NVMF_RECONNECT_HOST _IOW('n', 204, struct nvmf_ioc_nv) +#define NVMF_CONNECTION_STATUS _IOWR('n', 205, struct nvmf_ioc_nv) #endif /* !__NVMF_H__ */