diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c
index d8da520ae1fa..04a77246c22a 100644
--- a/drivers/s390/crypto/vfio_ap_drv.c
+++ b/drivers/s390/crypto/vfio_ap_drv.c
@@ -22,6 +22,10 @@ MODULE_AUTHOR("IBM Corporation");
 MODULE_DESCRIPTION("VFIO AP device driver, Copyright IBM Corp. 2018");
 MODULE_LICENSE("GPL v2");
 
+uint dbglvl = 3;
+module_param(dbglvl, uint, 0444);
+MODULE_PARM_DESC(dbglvl, "VFIO_AP driver debug level.");
+
 static struct ap_driver vfio_ap_drv;
 
 struct ap_matrix_dev *matrix_dev;
@@ -158,6 +162,21 @@ static void vfio_ap_matrix_dev_destroy(void)
 	root_device_unregister(root_device);
 }
 
+static void vfio_ap_log_queues_in_use(struct ap_matrix_mdev *matrix_mdev,
+				  unsigned long *apm, unsigned long *aqm)
+{
+	unsigned long apid, apqi;
+
+	for_each_set_bit_inv(apid, apm, AP_DEVICES) {
+		for_each_set_bit_inv(apqi, aqm, AP_DOMAINS) {
+			VFIO_AP_DBF(matrix_dev, DBF_ERR,
+				    "queue %02lx.%04lx in use by mdev %s\n",
+				    apid, apqi,
+				    dev_name(mdev_dev(matrix_mdev->mdev)));
+		}
+	}
+}
+
 static bool vfio_ap_resource_in_use(unsigned long *apm, unsigned long *aqm)
 {
 	bool in_use = false;
@@ -179,6 +198,8 @@ static bool vfio_ap_resource_in_use(unsigned long *apm, unsigned long *aqm)
 			continue;
 
 		in_use = true;
+		vfio_ap_log_queues_in_use(matrix_mdev, apm_intrsctn,
+					  aqm_intrsctn);
 	}
 
 	mutex_unlock(&matrix_dev->lock);
@@ -186,6 +207,16 @@ static bool vfio_ap_resource_in_use(unsigned long *apm, unsigned long *aqm)
 	return in_use;
 }
 
+static int __init vfio_ap_debug_init(void)
+{
+	matrix_dev->dbf = debug_register(VFIO_AP_DRV_NAME, 1, 1,
+					 DBF_SPRINTF_MAX_ARGS * sizeof(long));
+	debug_register_view(matrix_dev->dbf, &debug_sprintf_view);
+	debug_set_level(matrix_dev->dbf, dbglvl);
+
+	return 0;
+}
+
 static int __init vfio_ap_init(void)
 {
 	int ret;
@@ -219,6 +250,8 @@ static int __init vfio_ap_init(void)
 		return ret;
 	}
 
+	vfio_ap_debug_init();
+
 	return 0;
 }
 
@@ -227,6 +260,7 @@ static void __exit vfio_ap_exit(void)
 	vfio_ap_mdev_unregister();
 	ap_driver_unregister(&vfio_ap_drv);
 	vfio_ap_matrix_dev_destroy();
+	debug_unregister(matrix_dev->dbf);
 }
 
 module_init(vfio_ap_init);
diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index 0e748819abb6..1aa18eba43d0 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -167,17 +167,23 @@ static struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q)
 		case AP_RESPONSE_INVALID_ADDRESS:
 		default:
 			/* All cases in default means AP not operational */
-			WARN_ONCE(1, "%s: ap_aqic status %d\n", __func__,
-				  status.response_code);
 			goto end_free;
 		}
 	} while (retries--);
 
-	WARN_ONCE(1, "%s: ap_aqic status %d\n", __func__,
-		  status.response_code);
 end_free:
 	vfio_ap_free_aqic_resources(q);
 	q->matrix_mdev = NULL;
+	if (status.response_code) {
+		VFIO_AP_MDEV_DBF(q->matrix_mdev, DBF_WARN,
+			 "IRQ disable failed for queue %02x.%04x: status response code=%u\n",
+			 AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn),
+			 status.response_code);
+	} else {
+		VFIO_AP_MDEV_DBF(q->matrix_mdev, DBF_INFO,
+				 "IRQ disabled for queue %02x.%04x\n",
+				 AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn));
+	}
 	return status;
 }
 
@@ -215,6 +221,10 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q,
 	case 1:
 		break;
 	default:
+		VFIO_AP_MDEV_DBF(q->matrix_mdev, DBF_ERR,
+				 "IRQ enable failed for queue %02x.%04x: vfio_pin_pages rc=%d\n",
+				 AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn),
+				 ret);
 		status.response_code = AP_RESPONSE_INVALID_ADDRESS;
 		return status;
 	}
@@ -235,16 +245,25 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q,
 		vfio_ap_free_aqic_resources(q);
 		q->saved_pfn = g_pfn;
 		q->saved_isc = isc;
+		VFIO_AP_MDEV_DBF(q->matrix_mdev, DBF_INFO,
+				 "IRQ enabled for queue %02x.%04x",
+				 AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn));
 		break;
 	case AP_RESPONSE_OTHERWISE_CHANGED:
 		/* We could not modify IRQ setings: clear new configuration */
 		vfio_unpin_pages(mdev_dev(q->matrix_mdev->mdev), &g_pfn, 1);
 		kvm_s390_gisc_unregister(kvm, isc);
+		VFIO_AP_MDEV_DBF(q->matrix_mdev, DBF_WARN,
+				 "IRQ enable failed for queue %02x.%04x: status response code=%u",
+				 AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn),
+				 status.response_code);
 		break;
 	default:
-		pr_warn("%s: apqn %04x: response: %02x\n", __func__, q->apqn,
-			status.response_code);
 		vfio_ap_irq_disable(q);
+		VFIO_AP_MDEV_DBF(q->matrix_mdev, DBF_WARN,
+				 "IRQ enable failed for queue %02x.%04x: status response code=%u",
+				 AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn),
+				 status.response_code);
 		break;
 	}
 
@@ -321,8 +340,29 @@ static void vfio_ap_matrix_init(struct ap_config_info *info,
 	matrix->adm_max = info->apxa ? info->Nd : 15;
 }
 
+static int vfio_ap_mdev_debug_init(struct ap_matrix_mdev *matrix_mdev)
+{
+	int ret;
+
+	matrix_mdev->dbf = debug_register(dev_name(mdev_dev(matrix_mdev->mdev)),
+					  1, 1,
+					  DBF_SPRINTF_MAX_ARGS * sizeof(long));
+
+	if (!matrix_mdev->dbf)
+		return -ENOMEM;
+
+	ret = debug_register_view(matrix_mdev->dbf, &debug_sprintf_view);
+	if (ret)
+		return ret;
+
+	debug_set_level(matrix_mdev->dbf, dbglvl);
+
+	return 0;
+}
+
 static int vfio_ap_mdev_create(struct kobject *kobj, struct mdev_device *mdev)
 {
+	int ret;
 	struct ap_matrix_mdev *matrix_mdev;
 
 	if ((atomic_dec_if_positive(&matrix_dev->available_instances) < 0))
@@ -335,6 +375,13 @@ static int vfio_ap_mdev_create(struct kobject *kobj, struct mdev_device *mdev)
 	}
 
 	matrix_mdev->mdev = mdev;
+
+	ret = vfio_ap_mdev_debug_init(matrix_mdev);
+	if (ret) {
+		kfree(matrix_mdev);
+		return ret;
+	}
+
 	vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->matrix);
 	mdev_set_drvdata(mdev, matrix_mdev);
 	matrix_mdev->pqap_hook.hook = handle_pqap;
@@ -350,14 +397,19 @@ static int vfio_ap_mdev_remove(struct mdev_device *mdev)
 {
 	struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
 
-	if (matrix_mdev->kvm)
+	if (matrix_mdev->kvm) {
+		VFIO_AP_MDEV_DBF(matrix_mdev, DBF_ERR,
+				 "remove rejected, mdev in use by %s",
+				 matrix_mdev->kvm->debugfs_dentry->d_iname);
 		return -EBUSY;
+	}
 
 	mutex_lock(&matrix_dev->lock);
 	vfio_ap_mdev_reset_queues(mdev);
 	list_del(&matrix_mdev->node);
 	mutex_unlock(&matrix_dev->lock);
 
+	debug_unregister(matrix_mdev->dbf);
 	kfree(matrix_mdev);
 	mdev_set_drvdata(mdev, NULL);
 	atomic_inc(&matrix_dev->available_instances);
@@ -406,6 +458,22 @@ static struct attribute_group *vfio_ap_mdev_type_groups[] = {
 	NULL,
 };
 
+static void vfio_ap_mdev_log_sharing_error(struct ap_matrix_mdev *logdev,
+					   const char *assigned_to,
+					   unsigned long *apm,
+					   unsigned long *aqm)
+{
+	unsigned long apid, apqi;
+
+	for_each_set_bit_inv(apid, apm, AP_DEVICES) {
+		for_each_set_bit_inv(apqi, aqm, AP_DOMAINS) {
+			VFIO_AP_MDEV_DBF(logdev, DBF_ERR,
+					 "queue %02lx.%04lx already assigned to %s\n",
+					 apid, apqi, assigned_to);
+		}
+	}
+}
+
 /**
  * vfio_ap_mdev_verify_no_sharing
  *
@@ -448,22 +516,39 @@ static int vfio_ap_mdev_verify_no_sharing(struct ap_matrix_mdev *matrix_mdev,
 		if (!bitmap_and(aqm, mdev_aqm, lstdev->matrix.aqm, AP_DOMAINS))
 			continue;
 
+		vfio_ap_mdev_log_sharing_error(matrix_mdev,
+					       dev_name(mdev_dev(lstdev->mdev)),
+					       apm, aqm);
+
 		return -EADDRINUSE;
 	}
 
 	return 0;
 }
 
-static int vfio_ap_mdev_validate_masks(struct ap_matrix_mdev *matrix_mdev,
+static int vfio_ap_mdev_validate_masks(struct ap_matrix_mdev *logdev,
 				       unsigned long *apm, unsigned long *aqm)
 {
-	int ret;
+	int ret = 0;
+	unsigned long apid, apqi;
+
+	for_each_set_bit_inv(apid, apm, AP_DEVICES) {
+		for_each_set_bit_inv(apqi, aqm, AP_DEVICES) {
+			if (!ap_owned_by_def_drv(apid, apqi))
+				continue;
+
+			VFIO_AP_MDEV_DBF(logdev, DBF_ERR,
+					 "queue %02lx.%04lx owned by zcrypt\n",
+					 apid, apqi);
+
+			ret = -EADDRNOTAVAIL;
+		}
+	}
 
-	ret = ap_apqn_in_matrix_owned_by_def_drv(apm, aqm);
 	if (ret)
-		return (ret == 1) ? -EADDRNOTAVAIL : ret;
+		return ret;
 
-	return vfio_ap_mdev_verify_no_sharing(matrix_mdev, apm, aqm);
+	return vfio_ap_mdev_verify_no_sharing(logdev, apm, aqm);
 }
 
 static void vfio_ap_mdev_update_crycb(struct ap_matrix_mdev *matrix_mdev)
@@ -536,13 +621,20 @@ static ssize_t assign_adapter_store(struct device *dev,
 					  matrix_mdev->matrix.aqm);
 	if (ret) {
 		mutex_unlock(&matrix_dev->lock);
+		VFIO_AP_MDEV_DBF(matrix_mdev, DBF_ERR,
+				 "failed to assign adapter %lu(%#02lx)\n",
+				 apid, apid);
 		return ret;
 	}
 
+
 	set_bit_inv(apid, matrix_mdev->matrix.apm);
 	vfio_ap_mdev_update_crycb(matrix_mdev);
 	mutex_unlock(&matrix_dev->lock);
 
+	VFIO_AP_MDEV_DBF(matrix_mdev, DBF_INFO,
+			 "assigned adapter %lu(%#02lx)\n", apid, apid);
+
 	return count;
 }
 static DEVICE_ATTR_WO(assign_adapter);
@@ -587,6 +679,9 @@ static ssize_t unassign_adapter_store(struct device *dev,
 	vfio_ap_mdev_update_crycb(matrix_mdev);
 	mutex_unlock(&matrix_dev->lock);
 
+	VFIO_AP_MDEV_DBF(matrix_mdev, DBF_INFO,
+			 "unassigned adapter %lu(%#02lx)\n", apid, apid);
+
 	return count;
 }
 static DEVICE_ATTR_WO(unassign_adapter);
@@ -651,6 +746,9 @@ static ssize_t assign_domain_store(struct device *dev,
 					  aqm);
 	if (ret) {
 		mutex_unlock(&matrix_dev->lock);
+		VFIO_AP_MDEV_DBF(matrix_mdev, DBF_ERR,
+				 "failed to assign domain %lu(%#04lx)\n",
+				 apqi, apqi);
 		return ret;
 	}
 
@@ -658,6 +756,9 @@ static ssize_t assign_domain_store(struct device *dev,
 	vfio_ap_mdev_update_crycb(matrix_mdev);
 	mutex_unlock(&matrix_dev->lock);
 
+	VFIO_AP_MDEV_DBF(matrix_mdev, DBF_INFO,
+			 "assigned domain %lu(%#04lx)\n", apqi, apqi);
+
 	return count;
 }
 static DEVICE_ATTR_WO(assign_domain);
@@ -703,6 +804,9 @@ static ssize_t unassign_domain_store(struct device *dev,
 	vfio_ap_mdev_update_crycb(matrix_mdev);
 	mutex_unlock(&matrix_dev->lock);
 
+	VFIO_AP_MDEV_DBF(matrix_mdev, DBF_INFO,
+			 "unassigned domain %lu(%#02lx)\n", apqi, apqi);
+
 	return count;
 }
 static DEVICE_ATTR_WO(unassign_domain);
@@ -746,6 +850,9 @@ static ssize_t assign_control_domain_store(struct device *dev,
 	vfio_ap_mdev_update_crycb(matrix_mdev);
 	mutex_unlock(&matrix_dev->lock);
 
+	VFIO_AP_MDEV_DBF(matrix_mdev, DBF_INFO,
+			 "assigned control domain %lu(%#02lx)\n", id, id);
+
 	return count;
 }
 static DEVICE_ATTR_WO(assign_control_domain);
@@ -789,6 +896,10 @@ static ssize_t unassign_control_domain_store(struct device *dev,
 	vfio_ap_mdev_update_crycb(matrix_mdev);
 	mutex_unlock(&matrix_dev->lock);
 
+	VFIO_AP_MDEV_DBF(matrix_mdev, DBF_INFO,
+			 "unassigned control domain %lu(%#02lx)\n",
+			 domid, domid);
+
 	return count;
 }
 static DEVICE_ATTR_WO(unassign_control_domain);
@@ -910,6 +1021,9 @@ static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev,
 	list_for_each_entry(m, &matrix_dev->mdev_list, node) {
 		if ((m != matrix_mdev) && (m->kvm == kvm)) {
 			mutex_unlock(&matrix_dev->lock);
+			VFIO_AP_MDEV_DBF(matrix_mdev, DBF_ERR,
+					 "KVM already set for mdev %s\n",
+					 dev_name(mdev_dev(m->mdev)));
 			return -EPERM;
 		}
 	}
@@ -919,6 +1033,8 @@ static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev,
 	kvm->arch.crypto.pqap_hook = &matrix_mdev->pqap_hook;
 	mutex_unlock(&matrix_dev->lock);
 
+	VFIO_AP_MDEV_DBF(matrix_mdev, DBF_INFO, "KVM set for mdev\n");
+
 	return 0;
 }
 
@@ -972,8 +1088,11 @@ static int vfio_ap_mdev_group_notifier(struct notifier_block *nb,
 		return NOTIFY_DONE;
 
 	/* If there is no CRYCB pointer, then we can't copy the masks */
-	if (!matrix_mdev->kvm->arch.crypto.crycbd)
+	if (!matrix_mdev->kvm->arch.crypto.crycbd) {
+		VFIO_AP_MDEV_DBF(matrix_mdev, DBF_INFO,
+				 "Failed to set CRYCB masks: missing CRYCBD\n");
 		return NOTIFY_DONE;
+	}
 
 	kvm_arch_crypto_set_masks(matrix_mdev->kvm, matrix_mdev->matrix.apm,
 				  matrix_mdev->matrix.aqm,
@@ -1013,9 +1132,10 @@ static void vfio_ap_mdev_wait_for_qempty(ap_qid_t qid)
 			msleep(20);
 			break;
 		default:
-			pr_warn("%s: tapq response %02x waiting for queue %04x.%02x empty\n",
-				__func__, status.response_code,
-				AP_QID_CARD(qid), AP_QID_QUEUE(qid));
+			WARN_ONCE(1,
+				  "%s: tapq response %02x waiting for queue %04x.%02x empty\n",
+				  __func__, status.response_code,
+				  AP_QID_CARD(qid), AP_QID_QUEUE(qid));
 			return;
 		}
 	} while (--retry);
@@ -1062,8 +1182,16 @@ static int vfio_ap_mdev_reset_queues(struct mdev_device *mdev)
 		for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm,
 				     matrix_mdev->matrix.aqm_max + 1) {
 			ret = vfio_ap_mdev_reset_queue(apid, apqi);
-			if (ret)
+			if (ret) {
 				rc = ret;
+				VFIO_AP_MDEV_DBF(matrix_mdev, DBF_ERR,
+						 "queue %02lx.%04lx reset failed: rc=%d\n",
+						 apid, apqi, ret);
+			} else {
+				VFIO_AP_MDEV_DBF(matrix_mdev, DBF_INFO,
+						 "queue %02lx.%04lx reset\n",
+						 apid, apqi);
+			}
 
 			vfio_ap_irq_disable_apqn(AP_MKQID(apid, apqi));
 		}
@@ -1089,6 +1217,9 @@ static int vfio_ap_mdev_open(struct mdev_device *mdev)
 				     &events, &matrix_mdev->group_notifier);
 	if (ret) {
 		module_put(THIS_MODULE);
+		VFIO_AP_MDEV_DBF(matrix_mdev, DBF_ERR,
+				 "failed to open mdev fd: VFIO_GROUP_NOTIFY notifier registration failed with rc=%d\n",
+				 ret);
 		return ret;
 	}
 
@@ -1096,12 +1227,19 @@ static int vfio_ap_mdev_open(struct mdev_device *mdev)
 	events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
 	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
 				     &events, &matrix_mdev->iommu_notifier);
-	if (!ret)
+	if (!ret) {
+		VFIO_AP_MDEV_DBF(matrix_mdev, DBF_DEBUG,
+				 "opened mdev fd: guest started\n");
 		return ret;
+	}
 
+	VFIO_AP_MDEV_DBF(matrix_mdev, DBF_ERR,
+			 "failed to open mdev fd: VFIO_IOMMU_NOTIFY notifier registration failed with rc=%d\n",
+			 ret);
 	vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
 				 &matrix_mdev->group_notifier);
 	module_put(THIS_MODULE);
+
 	return ret;
 }
 
@@ -1124,6 +1262,9 @@ static void vfio_ap_mdev_release(struct mdev_device *mdev)
 	vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
 				 &matrix_mdev->group_notifier);
 	module_put(THIS_MODULE);
+
+	VFIO_AP_MDEV_DBF(matrix_mdev, DBF_DEBUG,
+			 "released mdev fd: guest terminated\n");
 }
 
 static int vfio_ap_mdev_get_device_info(unsigned long arg)
@@ -1202,6 +1343,11 @@ int vfio_ap_mdev_probe_queue(struct ap_queue *queue)
 	q->apqn = queue->qid;
 	q->saved_isc = VFIO_AP_ISC_INVALID;
 
+	VFIO_AP_DBF(matrix_dev, DBF_DEBUG,
+		    "queue %02x.%04x bound to %s\n",
+		    AP_QID_CARD(queue->qid), AP_QID_QUEUE(queue->qid),
+		    VFIO_AP_DRV_NAME);
+
 	return 0;
 }
 
@@ -1217,4 +1363,9 @@ void vfio_ap_mdev_remove_queue(struct ap_queue *queue)
 	vfio_ap_mdev_reset_queue(apid, apqi);
 	vfio_ap_irq_disable(q);
 	kfree(q);
+
+	VFIO_AP_DBF(matrix_dev, DBF_DEBUG,
+		    "queue %02x.%04x unbound from %s\n",
+		    AP_QID_CARD(queue->qid), AP_QID_QUEUE(queue->qid),
+		    VFIO_AP_DRV_NAME);
 }
diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h
index 5cc3c2ebf151..f717e43e10cf 100644
--- a/drivers/s390/crypto/vfio_ap_private.h
+++ b/drivers/s390/crypto/vfio_ap_private.h
@@ -24,6 +24,21 @@
 #define VFIO_AP_MODULE_NAME "vfio_ap"
 #define VFIO_AP_DRV_NAME "vfio_ap"
 
+#define DBF_ERR		3	/* error conditions   */
+#define DBF_WARN	4	/* warning conditions */
+#define DBF_INFO	5	/* informational      */
+#define DBF_DEBUG	6	/* for debugging only */
+
+#define DBF_SPRINTF_MAX_ARGS 5
+
+#define VFIO_AP_DBF(d_matrix_dev, ...) \
+	debug_sprintf_event(d_matrix_dev->dbf, ##__VA_ARGS__)
+
+#define VFIO_AP_MDEV_DBF(d_matrix_mdev, ...) \
+	debug_sprintf_event(d_matrix_mdev->dbf, ##__VA_ARGS__)
+
+extern uint dbglvl;
+
 /**
  * ap_matrix_dev - the AP matrix device structure
  * @device:	generic device structure associated with the AP matrix device
@@ -43,6 +58,7 @@ struct ap_matrix_dev {
 	struct list_head mdev_list;
 	struct mutex lock;
 	struct ap_driver  *vfio_ap_drv;
+	debug_info_t *dbf;
 };
 
 extern struct ap_matrix_dev *matrix_dev;
@@ -77,6 +93,9 @@ struct ap_matrix {
  * @group_notifier: notifier block used for specifying callback function for
  *		    handling the VFIO_GROUP_NOTIFY_SET_KVM event
  * @kvm:	the struct holding guest's state
+ * @pqap_hook:	handler for PQAP instruction
+ * @mdev:	the matrix mediated device
+ * @dbf:	the debug info log
  */
 struct ap_matrix_mdev {
 	struct list_head node;
@@ -86,6 +105,7 @@ struct ap_matrix_mdev {
 	struct kvm *kvm;
 	struct kvm_s390_module_hook pqap_hook;
 	struct mdev_device *mdev;
+	debug_info_t *dbf;
 };
 
 extern int vfio_ap_mdev_register(void);
