diff --git a/providers/bnxt_re/main.c b/providers/bnxt_re/main.c
index d2c2a6847e3c71..c83baacbb9f749 100644
--- a/providers/bnxt_re/main.c
+++ b/providers/bnxt_re/main.c
@@ -174,43 +174,38 @@ static void bnxt_re_uninit_context(struct verbs_device *vdev,
 	}
 }
 
-static struct verbs_device *bnxt_re_driver_init(const char *uverbs_sys_path,
-						int abi_version)
+static bool bnxt_re_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char value[10];
-	struct bnxt_re_dev *dev;
 	unsigned int vendor, device;
 	int i;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
 				value, sizeof(value)) < 0)
-		return NULL;
+		return false;
 	vendor = strtol(value, NULL, 16);
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
 				value, sizeof(value)) < 0)
-		return NULL;
+		return false;
 	device = strtol(value, NULL, 16);
 
 	for (i = 0; i < sizeof(cna_table) / sizeof(cna_table[0]); ++i)
 		if (vendor == cna_table[i].vendor &&
 		    device == cna_table[i].device)
-			goto found;
-	return NULL;
-found:
-	if (abi_version != BNXT_RE_ABI_VERSION) {
-		fprintf(stderr, DEV "FATAL: Max supported ABI of %s is %d "
-			"check for the latest version of kernel driver and"
-			"user library\n", uverbs_sys_path, abi_version);
-		return NULL;
-	}
+			return true;
+	return false;
+}
+
+static struct verbs_device *
+bnxt_re_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct bnxt_re_dev *dev;
 
 	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		fprintf(stderr, DEV "Failed to allocate device for %s\n",
-			uverbs_sys_path);
+	if (!dev)
 		return NULL;
-	}
 
 	dev->vdev.sz = sizeof(*dev);
 	dev->vdev.size_of_context =
@@ -221,7 +216,10 @@ found:
 
 static const struct verbs_device_ops bnxt_re_dev_ops = {
 	.name = "bnxt_re",
-	.init_device = bnxt_re_driver_init,
+	.match_min_abi_version = BNXT_RE_ABI_VERSION,
+	.match_max_abi_version = BNXT_RE_ABI_VERSION,
+	.match_device = bnxt_re_device_match,
+	.alloc_device = bnxt_re_device_alloc,
 	.init_context = bnxt_re_init_context,
 	.uninit_context = bnxt_re_uninit_context,
 };
diff --git a/providers/cxgb3/iwch.c b/providers/cxgb3/iwch.c
index c2423a7ee2cc32..7eb283bd9a89e1 100644
--- a/providers/cxgb3/iwch.c
+++ b/providers/cxgb3/iwch.c
@@ -61,7 +61,7 @@
 	  .device = PCI_DEVICE_ID_CHELSIO_##d,		\
 	  .type = CHELSIO_##t }
 
-static struct {
+static struct hca_ent {
 	unsigned vendor;
 	unsigned device;
 	enum iwch_hca_type type;
@@ -173,30 +173,31 @@ static void iwch_uninit_device(struct verbs_device *verbs_device)
 	free(dev);
 }
 
-static struct verbs_device *cxgb3_driver_init(const char *uverbs_sys_path,
-					      int abi_version)
+static bool iwch_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
-	char devstr[IBV_SYSFS_PATH_MAX], ibdev[16], value[32], *cp;
-	struct iwch_device *dev;
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
+	char value[32], *cp;
 	unsigned vendor, device, fw_maj, fw_min;
 	int i;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	sscanf(value, "%i", &vendor);
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	sscanf(value, "%i", &device);
 
 	for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i)
 		if (vendor == hca_table[i].vendor &&
-		    device == hca_table[i].device)
+		    device == hca_table[i].device) {
+			sysfs_dev->provider_data = &hca_table[i];
 			goto found;
+		}
 
-	return NULL;
+	return false;
 
 found:
 
@@ -204,15 +205,9 @@ found:
 	 * Verify that the firmware major number matches.  Major number
 	 * mismatches are fatal.  Minor number mismatches are tolerated.
 	 */
-	if (ibv_read_sysfs_file(uverbs_sys_path, "ibdev", 
-				ibdev, sizeof ibdev) < 0)
-		return NULL;
-
-	memset(devstr, 0, sizeof devstr);
-	snprintf(devstr, sizeof devstr, "%s/class/infiniband/%s", 
-		 ibv_get_sysfs_path(), ibdev);
-	if (ibv_read_sysfs_file(devstr, "fw_ver", value, sizeof value) < 0)
-		return NULL;
+	if (ibv_read_sysfs_file(sysfs_dev->ibdev_path, "fw_ver", value,
+				sizeof(value)) < 0)
+		return false;
 
 	cp = strtok(value+1, ".");
 	sscanf(cp, "%i", &fw_maj);
@@ -224,7 +219,7 @@ found:
 			"Firmware major number is %u and libcxgb3 needs %u.\n",
 			fw_maj, FW_MAJ);	
 		fflush(stderr);
-		return NULL;
+		return false;
 	}
 
 	DBGLOG("libcxgb3");
@@ -236,25 +231,21 @@ found:
 		fflush(stderr);
 	}
 
-	if (abi_version > ABI_VERS) {
-		PDBG("libcxgb3: ABI version mismatch.  "
-			"Kernel driver ABI is %u and libcxgb3 needs <= %u.\n",
-			abi_version, ABI_VERS);	
-		fflush(stderr);
-		return NULL;
-	}
+	return true;
+}
 
-	PDBG("%s found vendor %d device %d type %d\n", 
-	     __FUNCTION__, vendor, device, hca_table[i].type);
+static struct verbs_device *iwch_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct iwch_device *dev;
+	struct hca_ent *hca_ent = sysfs_dev->provider_data;
 
 	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
+	if (!dev)
 		return NULL;
-	}
 
 	pthread_spin_init(&dev->lock, PTHREAD_PROCESS_PRIVATE);
-	dev->hca_type = hca_table[i].type;
-	dev->abi_version = abi_version;
+	dev->hca_type = hca_ent->type;
+	dev->abi_version = sysfs_dev->abi_ver;
 
 	iwch_page_size = sysconf(_SC_PAGESIZE);
 	iwch_page_shift = long_log2(iwch_page_size);
@@ -285,7 +276,10 @@ err1:
 
 static const struct verbs_device_ops iwch_dev_ops = {
 	.name = "cxgb3",
-	.init_device = cxgb3_driver_init,
+	.match_min_abi_version = 0,
+	.match_max_abi_version = ABI_VERS,
+	.match_device = iwch_device_match,
+	.alloc_device = iwch_device_alloc,
 	.uninit_device = iwch_uninit_device,
 	.alloc_context = iwch_alloc_context,
 	.free_context = iwch_free_context,
diff --git a/providers/cxgb4/dev.c b/providers/cxgb4/dev.c
index 492b3978995607..43c5a3c97bc864 100644
--- a/providers/cxgb4/dev.c
+++ b/providers/cxgb4/dev.c
@@ -49,7 +49,7 @@
  * Macros needed to support the PCI Device ID Table ...
  */
 #define CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN \
-	static struct { \
+	static struct hca_ent { \
 		unsigned vendor; \
 		unsigned device; \
 	} hca_table[] = {
@@ -399,47 +399,40 @@ void dump_state(void)
  */
 int c4iw_abi_version = 1;
 
-static struct verbs_device *cxgb4_driver_init(const char *uverbs_sys_path,
-					      int abi_version)
+static bool c4iw_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
-	char devstr[IBV_SYSFS_PATH_MAX], ibdev[16], value[32], *cp;
-	struct c4iw_dev *dev;
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
+	char value[32], *cp;
 	unsigned vendor, device, fw_maj, fw_min;
 	int i;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	sscanf(value, "%i", &vendor);
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	sscanf(value, "%i", &device);
 
 	for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i)
 		if (vendor == hca_table[i].vendor &&
-		    device == hca_table[i].device)
+		    device == hca_table[i].device) {
+			sysfs_dev->provider_data = &hca_table[i];
 			goto found;
+		}
 
-	return NULL;
+	return false;
 
 found:
-	c4iw_abi_version = abi_version;	
-
 	/*
 	 * Verify that the firmware major number matches.  Major number
 	 * mismatches are fatal.  Minor number mismatches are tolerated.
 	 */
-	if (ibv_read_sysfs_file(uverbs_sys_path, "ibdev",
-				ibdev, sizeof ibdev) < 0)
-		return NULL;
-
-	memset(devstr, 0, sizeof devstr);
-	snprintf(devstr, sizeof devstr, "%s/class/infiniband/%s",
-		 ibv_get_sysfs_path(), ibdev);
-	if (ibv_read_sysfs_file(devstr, "fw_ver", value, sizeof value) < 0)
-		return NULL;
+	if (ibv_read_sysfs_file(sysfs_dev->ibdev_path, "fw_ver", value,
+				sizeof(value)) < 0)
+		return false;
 
 	cp = strtok(value+1, ".");
 	sscanf(cp, "%i", &fw_maj);
@@ -451,7 +444,7 @@ found:
 			"Firmware major number is %u and libcxgb4 needs %u.\n",
 			fw_maj, FW_MAJ);
 		fflush(stderr);
-		return NULL;
+		return false;
 	}
 
 	DBGLOG("libcxgb4");
@@ -462,22 +455,30 @@ found:
 			fw_min, FW_MIN);
 		fflush(stderr);
 	}
+	return true;
+}
 
-	PDBG("%s found vendor %d device %d type %d\n",
-	     __FUNCTION__, vendor, device, CHELSIO_CHIP_VERSION(hca_table[i].device >> 8));
+static struct verbs_device *c4iw_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct c4iw_dev *dev;
+	struct hca_ent *hca_ent = sysfs_dev->provider_data;
+
+	c4iw_page_size = sysconf(_SC_PAGESIZE);
+	c4iw_page_shift = long_log2(c4iw_page_size);
+	c4iw_page_mask = ~(c4iw_page_size - 1);
 
 	c4iw_page_size = sysconf(_SC_PAGESIZE);
 	c4iw_page_shift = long_log2(c4iw_page_size);
 	c4iw_page_mask = ~(c4iw_page_size - 1);
 
 	dev = calloc(1, sizeof *dev);
-	if (!dev) {
+	if (!dev)
 		return NULL;
-	}
 
 	pthread_spin_init(&dev->lock, PTHREAD_PROCESS_PRIVATE);
-	dev->chip_version = CHELSIO_CHIP_VERSION(hca_table[i].device >> 8);
-	dev->abi_version = abi_version;
+	c4iw_abi_version = sysfs_dev->abi_ver;
+	dev->chip_version = CHELSIO_CHIP_VERSION(hca_ent->device >> 8);
+	dev->abi_version = sysfs_dev->abi_ver;
 	list_node_init(&dev->list);
 
 	PDBG("%s device claimed\n", __FUNCTION__);
@@ -514,7 +515,10 @@ found:
 
 static const struct verbs_device_ops c4iw_dev_ops = {
 	.name = "cxgb4",
-	.init_device = cxgb4_driver_init,
+	.match_min_abi_version = 0,
+	.match_max_abi_version = INT_MAX,
+	.match_device = c4iw_device_match,
+	.alloc_device = c4iw_device_alloc,
 	.uninit_device = c4iw_uninit_device,
 	.alloc_context = c4iw_alloc_context,
 	.free_context = c4iw_free_context,
diff --git a/providers/hfi1verbs/hfiverbs.c b/providers/hfi1verbs/hfiverbs.c
index 247831eb211804..5bb436593517e1 100644
--- a/providers/hfi1verbs/hfiverbs.c
+++ b/providers/hfi1verbs/hfiverbs.c
@@ -180,47 +180,50 @@ static void hf11_uninit_device(struct verbs_device *verbs_device)
 	free(dev);
 }
 
-static struct verbs_device *hfi1_driver_init(const char *uverbs_sys_path,
-					     int abi_version)
+static bool hfi1_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char			value[8];
-	struct hfi1_device    *dev;
 	unsigned                vendor, device;
 	int                     i;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	sscanf(value, "%i", &vendor);
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	sscanf(value, "%i", &device);
 
 	for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i)
 		if (vendor == hca_table[i].vendor &&
 		    device == hca_table[i].device)
-			goto found;
+			return true;
 
-	return NULL;
+	return false;
+}
+
+static struct verbs_device *hfi1_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct hfi1_device    *dev;
 
-found:
 	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		fprintf(stderr, PFX "Fatal: couldn't allocate device for %s\n",
-			uverbs_sys_path);
+	if (!dev)
 		return NULL;
-	}
 
-	dev->abi_version = abi_version;
+	dev->abi_version = sysfs_dev->abi_ver;
 
 	return &dev->ibv_dev;
 }
 
 static const struct verbs_device_ops hfi1_dev_ops = {
 	.name = "hfi1verbs",
-	.init_device = hfi1_driver_init,
+	.match_min_abi_version = 0,
+	.match_max_abi_version = INT_MAX,
+	.match_device = hfi1_device_match,
+	.alloc_device = hfi1_device_alloc,
 	.uninit_device  = hf11_uninit_device,
 	.alloc_context = hfi1_alloc_context,
 	.free_context = hfi1_free_context,
diff --git a/providers/hns/hns_roce_u.c b/providers/hns/hns_roce_u.c
index fe2d009ebe3737..88389721811fce 100644
--- a/providers/hns/hns_roce_u.c
+++ b/providers/hns/hns_roce_u.c
@@ -44,20 +44,18 @@
 #define HID_LEN			15
 #define DEV_MATCH_LEN		128
 
-static const struct {
-	char	 hid[HID_LEN];
-	void	 *data;
-	int	 version;
-} acpi_table[] = {
+struct hca_ent {
+	const char *str;
+	struct hns_roce_u_hw *data;
+	int version;
+};
+
+static const struct hca_ent acpi_table[] = {
 	 {"acpi:HISI00D1:", &hns_roce_u_hw_v1, HNS_ROCE_HW_VER1},
 	 {},
 };
 
-static const struct {
-	char	 compatible[DEV_MATCH_LEN];
-	void	 *data;
-	int	 version;
-} dt_table[] = {
+static const struct hca_ent dt_table[] = {
 	{"hisilicon,hns-roce-v1", &hns_roce_u_hw_v1, HNS_ROCE_HW_VER1},
 	{},
 };
@@ -180,52 +178,53 @@ static void hns_uninit_device(struct verbs_device *verbs_device)
 	free(dev);
 }
 
-static struct verbs_device *hns_roce_driver_init(const char *uverbs_sys_path,
-						 int abi_version)
+static bool hns_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
-	struct hns_roce_device  *dev;
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char			 value[128];
 	int			 i;
-	void			 *u_hw;
-	int			 hw_version;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/modalias",
 				value, sizeof(value)) > 0)
 		for (i = 0; i < sizeof(acpi_table) / sizeof(acpi_table[0]); ++i)
-			if (!strcmp(value, acpi_table[i].hid)) {
-				u_hw = acpi_table[i].data;
-				hw_version = acpi_table[i].version;
-				goto found;
+			if (!strcmp(value, acpi_table[i].str)) {
+				sysfs_dev->provider_data =
+				    (void *)&acpi_table[i];
+				return true;
 			}
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/of_node/compatible",
 				value, sizeof(value)) > 0)
 		for (i = 0; i < sizeof(dt_table) / sizeof(dt_table[0]); ++i)
-			if (!strcmp(value, dt_table[i].compatible)) {
-				u_hw = dt_table[i].data;
-				hw_version = dt_table[i].version;
-				goto found;
+			if (!strcmp(value, dt_table[i].str)) {
+				sysfs_dev->provider_data = (void *)&dt_table[i];
+				return true;
 			}
 
-	return NULL;
+	return false;
+}
+
+static struct verbs_device *hns_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct hns_roce_device  *dev;
+	const struct hca_ent *hca_ent = sysfs_dev->provider_data;
 
-found:
 	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		fprintf(stderr, PFX "Fatal: couldn't allocate device for %s\n",
-			uverbs_sys_path);
+	if (!dev)
 		return NULL;
-	}
 
-	dev->u_hw = (struct hns_roce_u_hw *)u_hw;
-	dev->hw_version = hw_version;
+	dev->u_hw = hca_ent->data;
+	dev->hw_version = hca_ent->version;
 	dev->page_size   = sysconf(_SC_PAGESIZE);
 	return &dev->ibv_dev;
 }
 
 static const struct verbs_device_ops hns_roce_dev_ops = {
 	.name = "hns",
-	.init_device = hns_roce_driver_init,
+	.match_min_abi_version = 0,
+	.match_max_abi_version = INT_MAX,
+	.match_device = hns_device_match,
+	.alloc_device = hns_device_alloc,
 	.uninit_device = hns_uninit_device,
 	.alloc_context = hns_roce_alloc_context,
 	.free_context = hns_roce_free_context,
diff --git a/providers/i40iw/i40iw_umain.c b/providers/i40iw/i40iw_umain.c
index 90d37651d1f702..bcba6158e60e40 100644
--- a/providers/i40iw/i40iw_umain.c
+++ b/providers/i40iw/i40iw_umain.c
@@ -55,7 +55,7 @@
 	  .device = d,		\
 	  .type = INTEL_ ## t }
 
-static struct {
+static struct hca_ent {
 	unsigned int vendor;
 	unsigned int device;
 	enum i40iw_uhca_type type;
@@ -220,44 +220,53 @@ static void i40iw_uninit_device(struct verbs_device *verbs_device)
  * @uverbs_sys_path: sys path
  * @abi_version: not used
  */
-static struct verbs_device *i40iw_driver_init(const char *uverbs_sys_path,
-					      int abi_version)
+static bool i40iw_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char value[16];
-	struct i40iw_udevice *dev;
 	unsigned int vendor, device;
 	int i;
 
 	if ((ibv_read_sysfs_file(uverbs_sys_path, "device/vendor", value, sizeof(value)) < 0) ||
 	    (sscanf(value, "%i", &vendor) != 1))
-		return NULL;
+		return false;
 
 	if ((ibv_read_sysfs_file(uverbs_sys_path, "device/device", value, sizeof(value)) < 0) ||
 	    (sscanf(value, "%i", &device) != 1))
-		return NULL;
+		return false;
 
 	for (i = 0; i < sizeof(hca_table) / sizeof(hca_table[0]); ++i) {
 		if (vendor == hca_table[i].vendor &&
-		    device == hca_table[i].device)
-			goto found;
+		    device == hca_table[i].device) {
+			sysfs_dev->provider_data = &hca_table[i];
+			return true;
+		}
 	}
 
-	return NULL;
-found:
+	return false;
+}
+
+static struct verbs_device *
+i40iw_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct i40iw_udevice *dev;
+	struct hca_ent *hca_ent = sysfs_dev->provider_data;
+
 	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		fprintf(stderr, PFX "%s: failed to allocate memory for device object\n", __func__);
+	if (!dev)
 		return NULL;
-	}
 
-	dev->hca_type = hca_table[i].type;
+	dev->hca_type = hca_ent->type;
 	dev->page_size = I40IW_HW_PAGE_SIZE;
 	return &dev->ibv_dev;
 }
 
 static const struct verbs_device_ops i40iw_udev_ops = {
 	.name = "i40iw",
-	.init_device = i40iw_driver_init,
+	.match_min_abi_version = 0,
+	.match_max_abi_version = INT_MAX,
+	.match_device = i40iw_device_match,
+	.alloc_device = i40iw_device_alloc,
 	.uninit_device  = i40iw_uninit_device,
 	.alloc_context = i40iw_ualloc_context,
 	.free_context = i40iw_ufree_context,
diff --git a/providers/ipathverbs/ipathverbs.c b/providers/ipathverbs/ipathverbs.c
index ebdf5b828e1784..3c141263d8ff86 100644
--- a/providers/ipathverbs/ipathverbs.c
+++ b/providers/ipathverbs/ipathverbs.c
@@ -179,47 +179,51 @@ static void ipath_uninit_device(struct verbs_device *verbs_device)
 	free(dev);
 }
 
-static struct verbs_device *ipath_driver_init(const char *uverbs_sys_path,
-					      int abi_version)
+static bool ipath_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char			value[8];
-	struct ipath_device    *dev;
 	unsigned                vendor, device;
 	int                     i;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	sscanf(value, "%i", &vendor);
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	sscanf(value, "%i", &device);
 
 	for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i)
 		if (vendor == hca_table[i].vendor &&
 		    device == hca_table[i].device)
-			goto found;
+			return true;
 
-	return NULL;
+	return false;
+}
+
+static struct verbs_device *
+ipath_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct ipath_device    *dev;
 
-found:
 	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		fprintf(stderr, PFX "Fatal: couldn't allocate device for %s\n",
-			uverbs_sys_path);
+	if (!dev)
 		return NULL;
-	}
 
-	dev->abi_version = abi_version;
+	dev->abi_version = sysfs_dev->abi_ver;
 
 	return &dev->ibv_dev;
 }
 
 static const struct verbs_device_ops ipath_dev_ops = {
 	.name = "ipathverbs",
-	.init_device = ipath_driver_init,
+	.match_min_abi_version = 0,
+	.match_max_abi_version = INT_MAX,
+	.match_device = ipath_device_match,
+	.alloc_device = ipath_device_alloc,
 	.uninit_device  = ipath_uninit_device,
 	.alloc_context = ipath_alloc_context,
 	.free_context = ipath_free_context,
diff --git a/providers/mlx4/mlx4.c b/providers/mlx4/mlx4.c
index 0eefa40af16d83..b52684a563b495 100644
--- a/providers/mlx4/mlx4.c
+++ b/providers/mlx4/mlx4.c
@@ -286,50 +286,41 @@ static void mlx4_uninit_device(struct verbs_device *verbs_device)
 	free(dev);
 }
 
-static struct verbs_device *mlx4_driver_init(const char *uverbs_sys_path, int abi_version)
+static bool mlx4_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char			value[8];
-	struct mlx4_device    *dev;
 	unsigned		vendor, device;
 	int			i;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	vendor = strtol(value, NULL, 16);
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	device = strtol(value, NULL, 16);
 
 	for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i)
 		if (vendor == hca_table[i].vendor &&
 		    device == hca_table[i].device)
-			goto found;
-
-	return NULL;
-
-found:
-	if (abi_version < MLX4_UVERBS_MIN_ABI_VERSION ||
-	    abi_version > MLX4_UVERBS_MAX_ABI_VERSION) {
-		fprintf(stderr, PFX "Fatal: ABI version %d of %s is not supported "
-			"(min supported %d, max supported %d)\n",
-			abi_version, uverbs_sys_path,
-			MLX4_UVERBS_MIN_ABI_VERSION,
-			MLX4_UVERBS_MAX_ABI_VERSION);
-		return NULL;
-	}
+			return true;
+
+	return false;
+}
+
+static struct verbs_device *mlx4_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct mlx4_device *dev;
 
 	dev = calloc(1, sizeof *dev);
-	if (!dev) {
-		fprintf(stderr, PFX "Fatal: couldn't allocate device for %s\n",
-			uverbs_sys_path);
+	if (!dev)
 		return NULL;
-	}
 
 	dev->page_size   = sysconf(_SC_PAGESIZE);
-	dev->abi_version = abi_version;
+	dev->abi_version = sysfs_dev->abi_ver;
 
 	dev->verbs_dev.sz = sizeof(*dev);
 	dev->verbs_dev.size_of_context =
@@ -340,7 +331,10 @@ found:
 
 static const struct verbs_device_ops mlx4_dev_ops = {
 	.name = "mlx4",
-	.init_device = mlx4_driver_init,
+	.match_min_abi_version = MLX4_UVERBS_MIN_ABI_VERSION,
+	.match_max_abi_version = MLX4_UVERBS_MAX_ABI_VERSION,
+	.match_device = mlx4_device_match,
+	.alloc_device = mlx4_device_alloc,
 	.uninit_device = mlx4_uninit_device,
 	.init_context = mlx4_init_context,
 	.uninit_context = mlx4_uninit_context,
diff --git a/providers/mlx5/mlx5.c b/providers/mlx5/mlx5.c
index 68cca7cde97ef2..44cfd97b73cbbb 100644
--- a/providers/mlx5/mlx5.c
+++ b/providers/mlx5/mlx5.c
@@ -1026,51 +1026,40 @@ static void mlx5_uninit_device(struct verbs_device *verbs_device)
 	free(dev);
 }
 
-static struct verbs_device *mlx5_driver_init(const char *uverbs_sys_path,
-					     int abi_version)
+static bool mlx5_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char			value[8];
-	struct mlx5_device     *dev;
 	unsigned		vendor, device;
 	int			i;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	sscanf(value, "%i", &vendor);
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	sscanf(value, "%i", &device);
 
 	for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i)
 		if (vendor == hca_table[i].vendor &&
 		    device == hca_table[i].device)
-			goto found;
-
-	return NULL;
-
-found:
-	if (abi_version < MLX5_UVERBS_MIN_ABI_VERSION ||
-	    abi_version > MLX5_UVERBS_MAX_ABI_VERSION) {
-		fprintf(stderr, PFX "Fatal: ABI version %d of %s is not supported "
-			"(min supported %d, max supported %d)\n",
-			abi_version, uverbs_sys_path,
-			MLX5_UVERBS_MIN_ABI_VERSION,
-			MLX5_UVERBS_MAX_ABI_VERSION);
-		return NULL;
-	}
+			return true;
+	return false;
+}
+
+static struct verbs_device *mlx5_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct mlx5_device *dev;
 
 	dev = calloc(1, sizeof *dev);
-	if (!dev) {
-		fprintf(stderr, PFX "Fatal: couldn't allocate device for %s\n",
-			uverbs_sys_path);
+	if (!dev)
 		return NULL;
-	}
 
 	dev->page_size   = sysconf(_SC_PAGESIZE);
-	dev->driver_abi_ver = abi_version;
+	dev->driver_abi_ver = sysfs_dev->abi_ver;
 
 	dev->verbs_dev.sz = sizeof(*dev);
 	dev->verbs_dev.size_of_context = sizeof(struct mlx5_context) -
@@ -1081,7 +1070,10 @@ found:
 
 static const struct verbs_device_ops mlx5_dev_ops = {
 	.name = "mlx5",
-	.init_device = mlx5_driver_init,
+	.match_min_abi_version = MLX5_UVERBS_MIN_ABI_VERSION,
+	.match_max_abi_version = MLX5_UVERBS_MAX_ABI_VERSION,
+	.match_device = mlx5_device_match,
+	.alloc_device = mlx5_device_alloc,
 	.uninit_device = mlx5_uninit_device,
 	.init_context = mlx5_init_context,
 	.uninit_context = mlx5_cleanup_context,
diff --git a/providers/mthca/mthca.c b/providers/mthca/mthca.c
index 7194539b2d6ab1..521e5b9afe4f2b 100644
--- a/providers/mthca/mthca.c
+++ b/providers/mthca/mthca.c
@@ -77,7 +77,7 @@
 	  .device = PCI_DEVICE_ID_MELLANOX_##d,		\
 	  .type = MTHCA_##t }
 
-static struct {
+static struct hca_ent {
 	unsigned		vendor;
 	unsigned		device;
 	enum mthca_hca_type	type;
@@ -216,46 +216,44 @@ static void mthca_uninit_device(struct verbs_device *verbs_device)
 	free(dev);
 }
 
-static struct verbs_device *mthca_driver_init(const char *uverbs_sys_path,
-					    int abi_version)
+static bool mthca_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char			value[8];
-	struct mthca_device    *dev;
 	unsigned                vendor, device;
 	int                     i;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	sscanf(value, "%i", &vendor);
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
 				value, sizeof value) < 0)
-		return NULL;
+		return false;
 	sscanf(value, "%i", &device);
 
 	for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i)
 		if (vendor == hca_table[i].vendor &&
-		    device == hca_table[i].device)
-			goto found;
+		    device == hca_table[i].device) {
+			sysfs_dev->provider_data = &hca_table[i];
+			return true;
+		}
 
-	return NULL;
+	return false;
+}
 
-found:
-	if (abi_version > MTHCA_UVERBS_ABI_VERSION) {
-		fprintf(stderr, PFX "Fatal: ABI version %d of %s is too new (expected %d)\n",
-			abi_version, uverbs_sys_path, MTHCA_UVERBS_ABI_VERSION);
-		return NULL;
-	}
+static struct verbs_device *
+mthca_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct mthca_device    *dev;
+	struct hca_ent *hca_ent = sysfs_dev->provider_data;
 
 	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		fprintf(stderr, PFX "Fatal: couldn't allocate device for %s\n",
-			uverbs_sys_path);
+	if (!dev)
 		return NULL;
-	}
 
-	dev->hca_type    = hca_table[i].type;
+	dev->hca_type    = hca_ent->type;
 	dev->page_size   = sysconf(_SC_PAGESIZE);
 
 	return &dev->ibv_dev;
@@ -263,7 +261,10 @@ found:
 
 static const struct verbs_device_ops mthca_dev_ops = {
 	.name = "mthca",
-	.init_device = mthca_driver_init,
+	.match_min_abi_version = 0,
+	.match_max_abi_version = MTHCA_UVERBS_ABI_VERSION,
+	.match_device = mthca_device_match,
+	.alloc_device = mthca_device_alloc,
 	.uninit_device = mthca_uninit_device,
 	.alloc_context = mthca_alloc_context,
 	.free_context = mthca_free_context,
diff --git a/providers/nes/nes_umain.c b/providers/nes/nes_umain.c
index d02e010d2524a2..fc021a9196b6ad 100644
--- a/providers/nes/nes_umain.c
+++ b/providers/nes/nes_umain.c
@@ -60,7 +60,7 @@ long int page_size;
 	  .device = d,    \
 	  .type = NETEFFECT_##t }
 
-static struct {
+static struct hca_ent {
 	unsigned vendor;
 	unsigned device;
 	enum nes_uhca_type type;
@@ -191,37 +191,40 @@ static void nes_uninit_device(struct verbs_device *verbs_device)
 	free(dev);
 }
 
-/**
- * nes_driver_init
- */
-static struct verbs_device *nes_driver_init(const char *uverbs_sys_path,
-					    int abi_version)
+static bool nes_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char value[16];
-	struct nes_udevice *dev;
 	unsigned vendor, device;
 	int i;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
-			value, sizeof(value)) < 0) {
-		return NULL;
-	}
+			value, sizeof(value)) < 0)
+		return false;
 	sscanf(value, "%i", &vendor);
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
-			value, sizeof(value)) < 0) {
-		return NULL;
-	}
+			value, sizeof(value)) < 0)
+		return false;
 	sscanf(value, "%i", &device);
 
 	for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i)
 		if (vendor == hca_table[i].vendor &&
-				device == hca_table[i].device)
-			goto found;
+		    device == hca_table[i].device) {
+			sysfs_dev->provider_data = &hca_table[i];
+			return true;
+		}
 
-	return NULL;
+	return false;
+}
+
+static struct verbs_device *
+nes_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct nes_udevice *dev;
+	struct hca_ent *hca_ent = sysfs_dev->provider_data;
+	char value[16];
 
-found:
 	if (ibv_read_sysfs_file("/sys/module/iw_nes", "parameters/debug_level",
 			value, sizeof(value)) > 0) {
 		sscanf(value, "%u", &nes_debug_level);
@@ -231,12 +234,10 @@ found:
 	}
 
 	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		nes_debug(NES_DBG_INIT, "Fatal: couldn't allocate device for libnes\n");
+	if (!dev)
 		return NULL;
-	}
 
-	dev->hca_type = hca_table[i].type;
+	dev->hca_type = hca_ent->type;
 	dev->page_size = sysconf(_SC_PAGESIZE);
 
 	nes_debug(NES_DBG_INIT, "libnes initialized\n");
@@ -246,7 +247,10 @@ found:
 
 static const struct verbs_device_ops nes_udev_ops = {
 	.name = "nes",
-	.init_device = nes_driver_init,
+	.match_min_abi_version = 0,
+	.match_max_abi_version = INT_MAX,
+	.match_device = nes_device_match,
+	.alloc_device = nes_device_alloc,
 	.uninit_device = nes_uninit_device,
 	.alloc_context = nes_ualloc_context,
 	.free_context = nes_ufree_context,
diff --git a/providers/ocrdma/ocrdma_main.c b/providers/ocrdma/ocrdma_main.c
index 09c00d21ce2af6..f08a49fb73e021 100644
--- a/providers/ocrdma/ocrdma_main.c
+++ b/providers/ocrdma/ocrdma_main.c
@@ -168,50 +168,39 @@ static void ocrdma_free_context(struct ibv_context *ibctx)
 	free(ctx);
 }
 
-/**
- * ocrdma_driver_init
- */
-static struct verbs_device *ocrdma_driver_init(const char *uverbs_sys_path,
-					       int abi_version)
+static bool ocrdma_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
-
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char value[16];
-	struct ocrdma_device *dev;
 	unsigned vendor, device;
 	int i;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
-				value, sizeof(value)) < 0) {
-		return NULL;
-	}
+				value, sizeof(value)) < 0)
+		return false;
 	sscanf(value, "%i", &vendor);
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
-				value, sizeof(value)) < 0) {
-		return NULL;
-	}
+				value, sizeof(value)) < 0)
+		return false;
 	sscanf(value, "%i", &device);
 
 	for (i = 0; i < sizeof ucna_table / sizeof ucna_table[0]; ++i) {
 		if (vendor == ucna_table[i].vendor &&
 		    device == ucna_table[i].device)
-			goto found;
-	}
-	return NULL;
-found:
-	if (abi_version != OCRDMA_ABI_VERSION) {
-		fprintf(stderr,
-		  "Fatal: libocrdma ABI version %d of %s is not supported.\n",
-		  abi_version, uverbs_sys_path);
-		return NULL;
+			return true;
 	}
+	return false;
+}
+
+static struct verbs_device *
+ocrdma_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct ocrdma_device *dev;
 
 	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		ocrdma_err("%s() Fatal: fail allocate device for libocrdma\n",
-			   __func__);
+	if (!dev)
 		return NULL;
-	}
 
 	dev->qp_tbl = malloc(OCRDMA_MAX_QP * sizeof(struct ocrdma_qp *));
 	if (!dev->qp_tbl)
@@ -227,7 +216,10 @@ qp_err:
 
 static const struct verbs_device_ops ocrdma_dev_ops = {
 	.name = "ocrdma",
-	.init_device = ocrdma_driver_init,
+	.match_min_abi_version = OCRDMA_ABI_VERSION,
+	.match_max_abi_version = OCRDMA_ABI_VERSION,
+	.match_device = ocrdma_device_match,
+	.alloc_device = ocrdma_device_alloc,
 	.uninit_device = ocrdma_uninit_device,
 	.alloc_context = ocrdma_alloc_context,
 	.free_context = ocrdma_free_context,
diff --git a/providers/qedr/qelr_main.c b/providers/qedr/qelr_main.c
index 0be4a8c82a1e05..4d1b92f40a413a 100644
--- a/providers/qedr/qelr_main.c
+++ b/providers/qedr/qelr_main.c
@@ -227,53 +227,50 @@ static void qelr_free_context(struct ibv_context *ibctx)
 	free(ctx);
 }
 
-static struct verbs_device *qelr_driver_init(const char *uverbs_sys_path,
-					     int abi_version)
+static bool qedr_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char value[16];
-	struct qelr_device *dev;
 	unsigned int vendor, device;
 	int i;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
 				value, sizeof(value)) < 0)
-		return NULL;
+		return false;
 
 	sscanf(value, "%i", &vendor);
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
 				value, sizeof(value)) < 0)
-		return NULL;
+		return false;
 
 	sscanf(value, "%i", &device);
 
 	for (i = 0; i < sizeof(hca_table) / sizeof(hca_table[0]); ++i)
 		if (vendor == hca_table[i].vendor &&
 		    device == hca_table[i].device)
-			goto found;
+			return true;
 
-	return NULL;
-found:
-	if (abi_version != QELR_ABI_VERSION) {
-		fprintf(stderr,
-			"Fatal: libqedr ABI version %d of %s is not supported.\n",
-			abi_version, uverbs_sys_path);
-		return NULL;
-	}
+	return false;
+}
+
+static struct verbs_device *qedr_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct qelr_device *dev;
 
 	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		qelr_err("%s() Fatal: fail allocate device for libqedr\n",
-			 __func__);
+	if (!dev)
 		return NULL;
-	}
 
 	return &dev->ibv_dev;
 }
 
 static const struct verbs_device_ops qelr_dev_ops = {
 	.name = "qelr",
-	.init_device = qelr_driver_init,
+	.match_min_abi_version = QELR_ABI_VERSION,
+	.match_max_abi_version = QELR_ABI_VERSION,
+	.match_device = qedr_device_match,
+	.alloc_device = qedr_device_alloc,
 	.uninit_device = qelr_uninit_device,
 	.alloc_context = qelr_alloc_context,
 	.free_context = qelr_free_context,
diff --git a/providers/rxe/rxe.c b/providers/rxe/rxe.c
index 655800ec3410fd..d9857aac70d745 100644
--- a/providers/rxe/rxe.c
+++ b/providers/rxe/rxe.c
@@ -893,36 +893,40 @@ static void rxe_uninit_device(struct verbs_device *verbs_device)
 	free(dev);
 }
 
-static struct verbs_device *rxe_driver_init(const char *uverbs_sys_path,
-					    int abi_version)
+static bool rxe_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
-	struct rxe_device *dev;
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char value[16];
 
 	/* make sure it is a rxe device */
 	if (ibv_read_sysfs_file(uverbs_sys_path, "ibdev",
 				value, sizeof(value)) < 0)
-		return NULL;
+		return false;
 
 	if (strncmp(value, "rxe", 3))
-		return NULL;
+		return false;
+
+	return true;
+}
 
+static struct verbs_device *rxe_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct rxe_device *dev;
 	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		fprintf(stderr,
-			"rxe: Fatal: couldn't allocate device for %s\n",
-			uverbs_sys_path);
+	if (!dev)
 		return NULL;
-	}
 
-	dev->abi_version = abi_version;
+	dev->abi_version = sysfs_dev->abi_ver;
 
 	return &dev->ibv_dev;
 }
 
 static const struct verbs_device_ops rxe_dev_ops = {
 	.name = "rxe",
-	.init_device = rxe_driver_init,
+	.match_min_abi_version = 0,
+	.match_max_abi_version = INT_MAX,
+	.match_device = rxe_device_match,
+	.alloc_device = rxe_device_alloc,
 	.uninit_device = rxe_uninit_device,
 	.alloc_context = rxe_alloc_context,
 	.free_context = rxe_free_context,
diff --git a/providers/vmw_pvrdma/pvrdma_main.c b/providers/vmw_pvrdma/pvrdma_main.c
index 75b9296c6e24e3..9bcf2ddd172afb 100644
--- a/providers/vmw_pvrdma/pvrdma_main.c
+++ b/providers/vmw_pvrdma/pvrdma_main.c
@@ -169,64 +169,49 @@ static void pvrdma_uninit_device(struct verbs_device *verbs_device)
 	free(dev);
 }
 
-static struct pvrdma_device *pvrdma_driver_init_shared(
-						const char *uverbs_sys_path,
-						int abi_version)
+static bool pvrdma_device_match(struct verbs_sysfs_dev *sysfs_dev)
 {
-	struct pvrdma_device *dev;
+	const char *uverbs_sys_path = sysfs_dev->sysfs_path;
 	char value[8];
 	unsigned int vendor_id, device_id;
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
 				value, sizeof(value)) < 0)
-		return NULL;
+		return false;
 	vendor_id = strtol(value, NULL, 16);
 
 	if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
 				value, sizeof(value)) < 0)
-		return NULL;
+		return false;
 	device_id = strtol(value, NULL, 16);
 
 	if (vendor_id != PCI_VENDOR_ID_VMWARE ||
 	    device_id != PCI_DEVICE_ID_VMWARE_PVRDMA)
-		return NULL;
+		return false;
+	return true;
+}
 
-	/* We support only a single ABI version for now. */
-	if (abi_version != PVRDMA_UVERBS_ABI_VERSION) {
-		fprintf(stderr, PFX "ABI version %d of %s is not "
-			"supported (supported %d)\n",
-			abi_version, uverbs_sys_path,
-			PVRDMA_UVERBS_ABI_VERSION);
-		return NULL;
-	}
+static struct verbs_device *
+pvrdma_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
+{
+	struct pvrdma_device *dev;
 
 	dev = calloc(1, sizeof(*dev));
-	if (!dev) {
-		fprintf(stderr, PFX "couldn't allocate device for %s\n",
-			uverbs_sys_path);
+	if (!dev)
 		return NULL;
-	}
 
-	dev->abi_version = abi_version;
+	dev->abi_version = sysfs_dev->abi_ver;
 	dev->page_size   = sysconf(_SC_PAGESIZE);
 
-	return dev;
-}
-
-static struct verbs_device *pvrdma_driver_init(const char *uverbs_sys_path,
-					       int abi_version)
-{
-	struct pvrdma_device *dev = pvrdma_driver_init_shared(uverbs_sys_path,
-							      abi_version);
-	if (!dev)
-		return NULL;
-
 	return &dev->ibv_dev;
 }
 
 static const struct verbs_device_ops pvrdma_dev_ops = {
 	.name = "pvrdma",
-	.init_device = pvrdma_driver_init,
+	.match_min_abi_version = PVRDMA_UVERBS_ABI_VERSION,
+	.match_max_abi_version = PVRDMA_UVERBS_ABI_VERSION,
+	.match_device = pvrdma_device_match,
+	.alloc_device = pvrdma_device_alloc,
 	.uninit_device = pvrdma_uninit_device,
 	.alloc_context = pvrdma_alloc_context,
 	.free_context  = pvrdma_free_context,
