diff --git a/block/opal_proto.h b/block/opal_proto.h
index b486b3e..7152aa1 100644
--- a/block/opal_proto.h
+++ b/block/opal_proto.h
@@ -39,7 +39,12 @@ enum opal_response_token {
  #define FIRST_TPER_SESSION_NUM	4096
  
  #define TPER_SYNC_SUPPORTED 0x01
+/* FC_LOCKING features */
+#define LOCKING_SUPPORTED_MASK 0x01
+#define LOCKING_ENABLED_MASK 0x02
+#define LOCKED_MASK 0x04
  #define MBR_ENABLED_MASK 0x10
+#define MBR_DONE_MASK 0x20
  
  #define TINY_ATOM_DATA_MASK 0x3F
  #define TINY_ATOM_SIGNED 0x40
diff --git a/block/sed-opal.c b/block/sed-opal.c
index daafadb..6a67b20 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -75,7 +75,11 @@ struct parsed_resp {
  
  struct opal_dev {
  	bool supported;
+	bool locking_supported;
+	bool locking_enabled;
+	bool locked;
  	bool mbr_enabled;
+	bool mbr_done;
  
  	void *data;
  	sec_send_recv *send_recv;
@@ -280,6 +284,30 @@ static bool check_tper(const void *data)
  	return true;
  }
  
+static bool check_lcksuppt(const void *data)
+{
+	const struct d0_locking_features *lfeat = data;
+	u8 sup_feat = lfeat->supported_features;
+
+	return !!(sup_feat & LOCKING_SUPPORTED_MASK);
+}
+
+static bool check_lckenabled(const void *data)
+{
+	const struct d0_locking_features *lfeat = data;
+	u8 sup_feat = lfeat->supported_features;
+
+	return !!(sup_feat & LOCKING_ENABLED_MASK);
+}
+
+static bool check_locked(const void *data)
+{
+	const struct d0_locking_features *lfeat = data;
+	u8 sup_feat = lfeat->supported_features;
+
+	return !!(sup_feat & LOCKED_MASK);
+}
+
  static bool check_mbrenabled(const void *data)
  {
  	const struct d0_locking_features *lfeat = data;
@@ -288,6 +316,14 @@ static bool check_mbrenabled(const void *data)
  	return !!(sup_feat & MBR_ENABLED_MASK);
  }
  
+static bool check_mbrdone(const void *data)
+{
+	const struct d0_locking_features *lfeat = data;
+	u8 sup_feat = lfeat->supported_features;
+
+	return !!(sup_feat & MBR_DONE_MASK);
+}
+
  static bool check_sum(const void *data)
  {
  	const struct d0_single_user_mode *sum = data;
@@ -435,7 +471,11 @@ static int opal_discovery0_end(struct opal_dev *dev)
  	u32 hlen = be32_to_cpu(hdr->length);
  
  	print_buffer(dev->resp, hlen);
+	dev->locking_supported = false;
+	dev->locking_enabled = false;
+	dev->locked = false;
  	dev->mbr_enabled = false;
+	dev->mbr_done = false;
  
  	if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
  		pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n",
@@ -461,7 +501,11 @@ static int opal_discovery0_end(struct opal_dev *dev)
  			check_geometry(dev, body);
  			break;
  		case FC_LOCKING:
+			dev->locking_supported = check_lcksuppt(body->features);
+			dev->locking_enabled = check_lckenabled(body->features);
+			dev->locked = check_locked(body->features);
  			dev->mbr_enabled = check_mbrenabled(body->features);
+			dev->mbr_done = check_mbrdone(body->features);
  			break;
  		case FC_ENTERPRISE:
  		case FC_DATASTORE:
@@ -2620,6 +2664,29 @@ static int opal_generic_read_write_table(struct opal_dev *dev,
  	return ret;
  }
  
+static int opal_get_status(struct opal_dev *dev, void __user *data)
+{
+	struct opal_status sts = {0};
+
+	/*
+	 * check_opal_support() error is not fatal,
+	 * !dev->supported is a valid condition
+	 */
+	if (!check_opal_support(dev)) {
+		sts.opal_supported = dev->supported;
+		sts.locking_supported = dev->locking_supported;
+		sts.locking_enabled = dev->locking_enabled;
+		sts.locked = dev->locked;
+		sts.mbr_enabled = dev->mbr_enabled;
+		sts.mbr_done = dev->mbr_done;
+	}
+	if (copy_to_user(data, &sts, sizeof(sts))) {
+		pr_debug("Error copying status to userspace\n");
+		return -EFAULT;
+	}
+	return 0;
+}
+
  int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
  {
  	void *p;
@@ -2632,9 +2699,11 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
  	if (!dev->supported)
  		return -ENOTSUPP;
  
-	p = memdup_user(arg, _IOC_SIZE(cmd));
-	if (IS_ERR(p))
-		return PTR_ERR(p);
+	if (cmd & IOC_IN) {
+		p = memdup_user(arg, _IOC_SIZE(cmd));
+		if (IS_ERR(p))
+			return PTR_ERR(p);
+	}
  
  	switch (cmd) {
  	case IOC_OPAL_SAVE:
@@ -2685,11 +2754,15 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
  	case IOC_OPAL_GENERIC_TABLE_RW:
  		ret = opal_generic_read_write_table(dev, p);
  		break;
+	case IOC_OPAL_GET_STATUS:
+		ret = opal_get_status(dev, arg);
+		break;
  	default:
  		break;
  	}
  
-	kfree(p);
+	if (cmd & IOC_IN)
+		kfree(p);
  	return ret;
  }
  EXPORT_SYMBOL_GPL(sed_ioctl);
diff --git a/include/linux/sed-opal.h b/include/linux/sed-opal.h
index 1ac0d71..6f837bb 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -43,6 +43,7 @@ static inline bool is_sed_ioctl(unsigned int cmd)
  	case IOC_OPAL_MBR_DONE:
  	case IOC_OPAL_WRITE_SHADOW_MBR:
  	case IOC_OPAL_GENERIC_TABLE_RW:
+	case IOC_OPAL_GET_STATUS:
  		return true;
  	}
  	return false;
diff --git a/include/uapi/linux/sed-opal.h b/include/uapi/linux/sed-opal.h
index 6f5af1a..535ffc5 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -132,6 +132,16 @@ struct opal_read_write_table {
  	__u64 priv;
  };
  
+struct opal_status {
+	__u8 opal_supported;
+	__u8 locking_supported;
+	__u8 locking_enabled;
+	__u8 locked;
+	__u8 mbr_enabled;
+	__u8 mbr_done;
+	__u8 __align[2];
+};
+
  #define IOC_OPAL_SAVE		    _IOW('p', 220, struct opal_lock_unlock)
  #define IOC_OPAL_LOCK_UNLOCK	    _IOW('p', 221, struct opal_lock_unlock)
  #define IOC_OPAL_TAKE_OWNERSHIP	    _IOW('p', 222, struct opal_key)
@@ -148,5 +158,6 @@ struct opal_read_write_table {
  #define IOC_OPAL_MBR_DONE           _IOW('p', 233, struct opal_mbr_done)
  #define IOC_OPAL_WRITE_SHADOW_MBR   _IOW('p', 234, struct opal_shadow_mbr)
  #define IOC_OPAL_GENERIC_TABLE_RW   _IOW('p', 235, struct opal_read_write_table)
+#define IOC_OPAL_GET_STATUS         _IOR('p', 236, struct opal_status)
  
  #endif /* _UAPI_SED_OPAL_H */
