@@ -234,6 +234,7 @@ struct nvme_tcp_ctrl {
static LIST_HEAD(nvme_tcp_ctrl_list);
static DEFINE_MUTEX(nvme_tcp_ctrl_mutex);
+static struct notifier_block nvme_tcp_netdevice_nb;
static struct workqueue_struct *nvme_tcp_wq;
static const struct blk_mq_ops nvme_tcp_mq_ops;
static const struct blk_mq_ops nvme_tcp_admin_mq_ops;
@@ -3193,6 +3194,32 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev,
return ERR_PTR(ret);
}
+static int nvme_tcp_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+#ifdef CONFIG_ULP_DDP
+ struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+ struct nvme_tcp_ctrl *ctrl;
+
+ switch (event) {
+ case NETDEV_GOING_DOWN:
+ mutex_lock(&nvme_tcp_ctrl_mutex);
+ list_for_each_entry(ctrl, &nvme_tcp_ctrl_list, list) {
+ if (ndev == ctrl->ddp_netdev)
+ nvme_tcp_error_recovery(&ctrl->ctrl);
+ }
+ mutex_unlock(&nvme_tcp_ctrl_mutex);
+ flush_workqueue(nvme_reset_wq);
+ /*
+ * The associated controllers teardown has completed,
+ * ddp contexts were also torn down so we should be
+ * safe to continue...
+ */
+ }
+#endif
+ return NOTIFY_DONE;
+}
+
static struct nvmf_transport_ops nvme_tcp_transport = {
.name = "tcp",
.module = THIS_MODULE,
@@ -3208,6 +3235,8 @@ static struct nvmf_transport_ops nvme_tcp_transport = {
static int __init nvme_tcp_init_module(void)
{
+ int ret;
+
BUILD_BUG_ON(sizeof(struct nvme_tcp_hdr) != 8);
BUILD_BUG_ON(sizeof(struct nvme_tcp_cmd_pdu) != 72);
BUILD_BUG_ON(sizeof(struct nvme_tcp_data_pdu) != 24);
@@ -3222,8 +3251,19 @@ static int __init nvme_tcp_init_module(void)
if (!nvme_tcp_wq)
return -ENOMEM;
+ nvme_tcp_netdevice_nb.notifier_call = nvme_tcp_netdev_event;
+ ret = register_netdevice_notifier(&nvme_tcp_netdevice_nb);
+ if (ret) {
+ pr_err("failed to register netdev notifier\n");
+ goto out_free_workqueue;
+ }
+
nvmf_register_transport(&nvme_tcp_transport);
return 0;
+
+out_free_workqueue:
+ destroy_workqueue(nvme_tcp_wq);
+ return ret;
}
static void __exit nvme_tcp_cleanup_module(void)
@@ -3231,6 +3271,7 @@ static void __exit nvme_tcp_cleanup_module(void)
struct nvme_tcp_ctrl *ctrl;
nvmf_unregister_transport(&nvme_tcp_transport);
+ unregister_netdevice_notifier(&nvme_tcp_netdevice_nb);
mutex_lock(&nvme_tcp_ctrl_mutex);
list_for_each_entry(ctrl, &nvme_tcp_ctrl_list, list)