diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index e09fe6a..83ba979 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -109,3 +109,22 @@ config SCSI_UFS_HISI
 
 	  Select this if you have UFS controller on Hisilicon chipset.
 	  If unsure, say N.
+
+config SCSI_UFS_BSG
+	bool "Universal Flash Storage BSG device node"
+	depends on SCSI_UFSHCD
+	select BLK_DEV_BSGLIB
+	help
+	  Universal Flash Storage (UFS) is SCSI transport specification for
+	  accessing flash storage on digital cameras, mobile phones and
+	  consumer electronic devices.
+	  An UFS controller communicates with an UFS device by exchanging
+	  UFS Protocol Information Units (UPIUs).
+	  UPIUs can not only be used as a transport layer for the SCSI protocol
+	  but are also used by the UFS native command set.
+	  This transport driver supports exchanging UFS protocol information units
+	  with an UFS device. See also the ufshcd driver, which is a SCSI driver
+	  that supports UFS devices.
+
+	  Select this if you need a bsg device node for your UFS controller.
+	  If unsure, say N.
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
index 2c50f03..8f7138a 100644
--- a/drivers/scsi/ufs/Makefile
+++ b/drivers/scsi/ufs/Makefile
@@ -8,3 +8,4 @@ ufshcd-core-objs := ufshcd.o ufs-sysfs.o
 obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
 obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
 obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o
+obj-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o
diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c
new file mode 100644
index 0000000..b099ee2
--- /dev/null
+++ b/drivers/scsi/ufs/ufs_bsg.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * bsg endpoint that supports UPIUs
+ *
+ * Copyright (C) 2018 Western Digital Corporation
+ */
+#include "ufs_bsg.h"
+
+struct ufs_bsg_node {
+	struct device		dev;
+	struct request_queue	*q;
+};
+
+struct ufs_bsg {
+	struct ufs_hba *hba;
+	struct ufs_bsg_node *node;
+};
+static struct ufs_bsg *bsg_host;
+
+static inline struct ufs_bsg_node *dev_to_ufs_node(struct device *d)
+{
+	return container_of(d, struct ufs_bsg_node, dev);
+}
+
+static int ufs_bsg_request(struct bsg_job *job)
+{
+	struct ufs_bsg_request *bsg_request = job->request;
+	struct ufs_bsg_reply *bsg_reply = job->reply;
+	int ret = -ENOTSUPP;
+
+	bsg_reply->reply_payload_rcv_len = 0;
+
+	/* Do Nothing for now */
+	dev_err(job->dev, "unsupported message_code 0x%x\n",
+		bsg_request->msgcode);
+
+	bsg_reply->result = ret;
+	if (ret)
+		job->reply_len = sizeof(uint32_t);
+	else
+		job->reply_len = sizeof(struct ufs_bsg_reply) +
+				 bsg_reply->reply_payload_rcv_len;
+
+	bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len);
+
+	return ret;
+}
+
+static void ufs_bsg_node_delete(struct ufs_bsg_node *node)
+{
+	struct device *dev = &node->dev;
+
+	if (node->q)
+		bsg_unregister_queue(node->q);
+
+	device_del(dev);
+
+	put_device(dev);
+}
+
+/**
+ * ufs_bsg_remove - detach and remove the added ufs-bsg node
+ *
+ * Should be called when unloading the driver.
+ */
+void ufs_bsg_remove(void)
+{
+	if (!bsg_host)
+		return;
+
+	if (bsg_host->node)
+		ufs_bsg_node_delete(bsg_host->node);
+
+	kfree(bsg_host);
+}
+
+static void ufs_bsg_node_release(struct device *dev)
+{
+	struct ufs_bsg_node *node = dev_to_ufs_node(dev);
+
+	put_device(dev->parent);
+	kfree(node);
+}
+
+static struct ufs_bsg_node *ufs_bsg_node_alloc(struct Scsi_Host *shost)
+{
+	struct ufs_bsg_node *node;
+	struct device *parent = &shost->shost_gendev;
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node)
+		return NULL;
+
+	device_initialize(&node->dev);
+
+	node->dev.parent = get_device(parent);
+	node->dev.release = ufs_bsg_node_release;
+
+	dev_set_name(&node->dev, "ufs-bsg-%d:0", shost->host_no);
+
+	return node;
+}
+
+static int ufs_bsg_initialize(struct Scsi_Host *shost,
+			      struct ufs_bsg_node *node)
+{
+	struct request_queue *q;
+
+	q = bsg_setup_queue(&node->dev, dev_name(&node->dev),
+			    ufs_bsg_request, 0);
+	if (IS_ERR(q))
+		return PTR_ERR(q);
+	node->q = q;
+
+	return 0;
+}
+
+static int ufs_bsg_node_add(struct ufs_bsg_node *node)
+{
+	struct device *dev = &node->dev;
+	struct Scsi_Host *shost = dev_to_shost(dev->parent);
+	int error;
+
+	error = device_add(dev);
+	if (error)
+		return error;
+
+	if (ufs_bsg_initialize(shost, node))
+		dev_err(dev, "fail to initialize a bsg dev %d\n",
+			shost->host_no);
+
+	return 0;
+}
+
+/**
+ * ufs_bsg_probe - Add ufs bsg device node
+ * @hba: per adapter object
+ *
+ * Called during initial loading of the driver, and before scsi_scan_host.
+ */
+int ufs_bsg_probe(struct ufs_hba *hba)
+{
+	struct ufs_bsg_node *node;
+	int ret;
+
+	bsg_host = kzalloc(sizeof(*bsg_host), GFP_KERNEL);
+	if (!bsg_host) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	node = ufs_bsg_node_alloc(hba->host);
+	if (!node) {
+		ret = -ENOMEM;
+		goto out_free_bsg_host;
+	}
+
+	ret = ufs_bsg_node_add(node);
+	if (ret)
+		goto out_free_node;
+
+	bsg_host->node = node;
+	bsg_host->hba = hba;
+
+	return 0;
+
+out_free_node:
+	put_device(&node->dev);
+out_free_bsg_host:
+	kfree(bsg_host);
+out:
+	return ret;
+}
diff --git a/drivers/scsi/ufs/ufs_bsg.h b/drivers/scsi/ufs/ufs_bsg.h
new file mode 100644
index 0000000..58eda73
--- /dev/null
+++ b/drivers/scsi/ufs/ufs_bsg.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Western Digital Corporation
+ */
+#ifndef UFS_BSG_H
+#define UFS_BSG_H
+
+#include <linux/bsg-lib.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include <uapi/scsi/scsi_bsg_ufs.h>
+#include "ufshcd.h"
+#include "ufs.h"
+
+#define UPIU_TRANSACTION_UIC_CMD 0x1F
+
+enum {
+	REQ_UPIU_SIZE_DWORDS	= 8,
+	RSP_UPIU_SIZE_DWORDS	= 8,
+};
+
+struct ufs_bsg_request {
+	uint32_t msgcode;
+	struct utp_upiu_header header;
+	union {
+		struct utp_upiu_query		qr;
+		struct utp_upiu_task_req	tr;
+		/* use utp_upiu_query to host the 4 dwords of uic command */
+		struct utp_upiu_query		uc;
+	} tsf;
+};
+
+
+struct ufs_bsg_reply {
+	/*
+	 * The completion result. Result exists in two forms:
+	 * if negative, it is an -Exxx system errno value. There will
+	 * be no further reply information supplied.
+	 * else, it's the 4-byte scsi error result, with driver, host,
+	 * msg and status fields. The per-msgcode reply structure
+	 * will contain valid data.
+	 */
+	uint32_t result;
+
+	/* If there was reply_payload, how much was received? */
+	uint32_t reply_payload_rcv_len;
+
+	struct utp_upiu_header header;
+	union {
+		struct utp_upiu_query		qr;
+		struct utp_upiu_task_rsp	tr;
+		struct utp_upiu_query		uc;
+	} tsf;
+};
+
+struct ufs_bsg_raw_upiu {
+	struct ufs_bsg_upiu request;
+	struct ufs_bsg_upiu reply;
+};
+
+#ifdef CONFIG_SCSI_UFS_BSG
+void ufs_bsg_remove(void);
+int ufs_bsg_probe(struct ufs_hba *hba);
+#else
+static inline void ufs_bsg_remove(void) {}
+static inline int ufs_bsg_probe(struct ufs_hba *hba) {return 0; }
+#endif
+
+#endif /* UFS_BSG_H */
diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h
new file mode 100644
index 0000000..5fb37be
--- /dev/null
+++ b/include/uapi/scsi/scsi_bsg_ufs.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * UFS Transport SGIO v4 BSG Message Support
+ *
+ * Copyright (C) 2018 Western Digital Corporation
+ */
+#ifndef SCSI_BSG_UFS_H
+#define SCSI_BSG_UFS_H
+
+/*
+ * This file intended to be included by both kernel and user space
+ */
+
+
+/**
+ * struct ufs_bsg_upiu - upiu transaction structure
+ *
+ * @header: upiu header
+ * @tsf: Transaction Specific Fields
+ * @data: payload pointer
+ *
+ * This structure supports all ufs transaction types per JEDEC UFSv2.1
+ * paragraph 10.7
+ */
+struct ufs_bsg_upiu {
+	uint32_t header[3];
+	uint32_t tsf[5];
+	uint8_t data[0];
+};
+
+/* request (CDB) structure of the sg_io_v4 */
+struct ufs_bsg_upiu_request {
+	uint32_t msgcode;
+	struct ufs_bsg_upiu upiu;
+} __packed;
+
+/* response (request sense data) structure of the sg_io_v4 */
+struct ufs_bsg_upiu_reply {
+	/*
+	 * The completion result. Result exists in two forms:
+	 * if negative, it is an -Exxx system errno value. There will
+	 * be no further reply information supplied.
+	 * else, it's the 4-byte scsi error result, with driver, host,
+	 * msg and status fields. The per-msgcode reply structure
+	 * will contain valid data.
+	 */
+	uint32_t result;
+
+	/* If there was reply_payload, how much was recevied ? */
+	uint32_t reply_payload_rcv_len;
+
+	struct ufs_bsg_upiu upiu;
+
+};
+
+#endif /* SCSI_BSG_UFS_H */
