diff mbox series

[14/24] bsg: move bsg_scsi_ops to drivers/scsi/

Message ID 20210724072033.1284840-15-hch@lst.de (mailing list archive)
State New, archived
Headers show
Series [01/24] bsg: remove support for SCSI_IOCTL_SEND_COMMAND | expand

Commit Message

Christoph Hellwig July 24, 2021, 7:20 a.m. UTC
Move the SCSI-specific bsg code in the SCSI midlayer instead of in the
common bsg code.  This just keeps the common bsg code block/ and also
allows building it as a module.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 block/Kconfig             | 23 ++--------
 block/Makefile            |  2 +-
 block/bsg.c               | 95 +--------------------------------------
 drivers/scsi/Kconfig      | 13 ++++++
 drivers/scsi/Makefile     |  1 +
 drivers/scsi/scsi_bsg.c   | 95 +++++++++++++++++++++++++++++++++++++++
 drivers/scsi/scsi_priv.h  | 10 +++++
 drivers/scsi/scsi_sysfs.c |  2 +-
 include/linux/blkdev.h    |  2 +-
 include/linux/bsg.h       | 11 ++---
 10 files changed, 129 insertions(+), 125 deletions(-)
 create mode 100644 drivers/scsi/scsi_bsg.c

Comments

Christoph Hellwig July 30, 2021, 7:27 a.m. UTC | #1
On Thu, Jul 29, 2021 at 10:47:45AM +0200, Anders Roxell wrote:
> From: Christoph Hellwig <hch@lst.de>
> 
> > Move the SCSI-specific bsg code in the SCSI midlayer instead of in the
> > common bsg code.  This just keeps the common bsg code block/ and also
> > allows building it as a module.
> > 
> > Signed-off-by: Christoph Hellwig <hch@lst.de>
> 
> [ Please ignore if its already been reported ]
> 
> When building arm's defconfig 'footbridge_defconfig' on linux-next tag next-20210728 I see the following error.

Can you try this patch on top?

---
From d92a8160ce3fbe64a250482522ca0456277781f9 Mon Sep 17 00:00:00 2001
From: Christoph Hellwig <hch@lst.de>
Date: Mon, 5 Jul 2021 15:02:43 +0200
Subject: cdrom: move the guts of cdrom_read_cdda_bpc into the sr driver

cdrom_read_cdda_bpc relies on sending SCSI command to the low level
driver using a REQ_OP_SCSI_IN request.  This isn't generic block
layer functionality, so some the actual low-level code into the sr
driver and call it through a new read_cdda_bpc method in the
cdrom_device_ops structure.

With this the CDROM code does not have to pull in
scsi_normalize_sense and this depend on CONFIG_SCSI_COMMON.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 drivers/cdrom/cdrom.c | 71 +++++--------------------------------------
 drivers/scsi/sr.c     | 56 +++++++++++++++++++++++++++++++++-
 include/linux/cdrom.h |  6 ++--
 3 files changed, 67 insertions(+), 66 deletions(-)

diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 8882b311bafd..bd2e5b1560f5 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -629,7 +629,7 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi)
 	if (CDROM_CAN(CDC_MRW_W))
 		cdi->exit = cdrom_mrw_exit;
 
-	if (cdi->disk)
+	if (cdi->ops->read_cdda_bpc)
 		cdi->cdda_method = CDDA_BPC_FULL;
 	else
 		cdi->cdda_method = CDDA_OLD;
@@ -2159,81 +2159,26 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf,
 static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
 			       int lba, int nframes)
 {
-	struct request_queue *q = cdi->disk->queue;
-	struct request *rq;
-	struct scsi_request *req;
-	struct bio *bio;
-	unsigned int len;
+	int max_frames = (queue_max_sectors(cdi->disk->queue) << 9) /
+			  CD_FRAMESIZE_RAW;
 	int nr, ret = 0;
 
-	if (!q)
-		return -ENXIO;
-
-	if (!blk_queue_scsi_passthrough(q)) {
-		WARN_ONCE(true,
-			  "Attempt read CDDA info through a non-SCSI queue\n");
-		return -EINVAL;
-	}
-
 	cdi->last_sense = 0;
 
 	while (nframes) {
-		nr = nframes;
 		if (cdi->cdda_method == CDDA_BPC_SINGLE)
 			nr = 1;
-		if (nr * CD_FRAMESIZE_RAW > (queue_max_sectors(q) << 9))
-			nr = (queue_max_sectors(q) << 9) / CD_FRAMESIZE_RAW;
-
-		len = nr * CD_FRAMESIZE_RAW;
-
-		rq = blk_get_request(q, REQ_OP_DRV_IN, 0);
-		if (IS_ERR(rq)) {
-			ret = PTR_ERR(rq);
-			break;
-		}
-		req = scsi_req(rq);
-
-		ret = blk_rq_map_user(q, rq, NULL, ubuf, len, GFP_KERNEL);
-		if (ret) {
-			blk_put_request(rq);
-			break;
-		}
-
-		req->cmd[0] = GPCMD_READ_CD;
-		req->cmd[1] = 1 << 2;
-		req->cmd[2] = (lba >> 24) & 0xff;
-		req->cmd[3] = (lba >> 16) & 0xff;
-		req->cmd[4] = (lba >>  8) & 0xff;
-		req->cmd[5] = lba & 0xff;
-		req->cmd[6] = (nr >> 16) & 0xff;
-		req->cmd[7] = (nr >>  8) & 0xff;
-		req->cmd[8] = nr & 0xff;
-		req->cmd[9] = 0xf8;
-
-		req->cmd_len = 12;
-		rq->timeout = 60 * HZ;
-		bio = rq->bio;
-
-		blk_execute_rq(cdi->disk, rq, 0);
-		if (scsi_req(rq)->result) {
-			struct scsi_sense_hdr sshdr;
-
-			ret = -EIO;
-			scsi_normalize_sense(req->sense, req->sense_len,
-					     &sshdr);
-			cdi->last_sense = sshdr.sense_key;
-		}
-
-		if (blk_rq_unmap_user(bio))
-			ret = -EFAULT;
-		blk_put_request(rq);
+		else
+			nr = min(nframes, max_frames);
 
+		ret = cdi->ops->read_cdda_bpc(cdi, ubuf, lba, nr,
+					      &cdi->last_sense);
 		if (ret)
 			break;
 
 		nframes -= nr;
 		lba += nr;
-		ubuf += len;
+		ubuf += (nr * CD_FRAMESIZE_RAW);
 	}
 
 	return ret;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index b98e77fe700b..6203a8b58d40 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -120,6 +120,8 @@ static void get_capabilities(struct scsi_cd *);
 static unsigned int sr_check_events(struct cdrom_device_info *cdi,
 				    unsigned int clearing, int slot);
 static int sr_packet(struct cdrom_device_info *, struct packet_command *);
+static int sr_read_cdda_bpc(struct cdrom_device_info *cdi, void __user *ubuf,
+		u32 lba, u32 nr, u8 *last_sense);
 
 static const struct cdrom_device_ops sr_dops = {
 	.open			= sr_open,
@@ -133,8 +135,9 @@ static const struct cdrom_device_ops sr_dops = {
 	.get_mcn		= sr_get_mcn,
 	.reset			= sr_reset,
 	.audio_ioctl		= sr_audio_ioctl,
-	.capability		= SR_CAPABILITIES,
 	.generic_packet		= sr_packet,
+	.read_cdda_bpc		= sr_read_cdda_bpc,
+	.capability		= SR_CAPABILITIES,
 };
 
 static void sr_kref_release(struct kref *kref);
@@ -951,6 +954,57 @@ static int sr_packet(struct cdrom_device_info *cdi,
 	return cgc->stat;
 }
 
+static int sr_read_cdda_bpc(struct cdrom_device_info *cdi, void __user *ubuf,
+		u32 lba, u32 nr, u8 *last_sense)
+{
+	struct gendisk *disk = cdi->disk;
+	u32 len = nr * CD_FRAMESIZE_RAW;
+	struct scsi_request *req;
+	struct request *rq;
+	struct bio *bio;
+	int ret;
+
+	rq = blk_get_request(disk->queue, REQ_OP_DRV_IN, 0);
+	if (IS_ERR(rq))
+		return PTR_ERR(rq);
+	req = scsi_req(rq);
+
+	ret = blk_rq_map_user(disk->queue, rq, NULL, ubuf, len, GFP_KERNEL);
+	if (ret)
+		goto out_put_request;
+
+	req->cmd[0] = GPCMD_READ_CD;
+	req->cmd[1] = 1 << 2;
+	req->cmd[2] = (lba >> 24) & 0xff;
+	req->cmd[3] = (lba >> 16) & 0xff;
+	req->cmd[4] = (lba >>  8) & 0xff;
+	req->cmd[5] = lba & 0xff;
+	req->cmd[6] = (nr >> 16) & 0xff;
+	req->cmd[7] = (nr >>  8) & 0xff;
+	req->cmd[8] = nr & 0xff;
+	req->cmd[9] = 0xf8;
+	req->cmd_len = 12;
+	rq->timeout = 60 * HZ;
+	bio = rq->bio;
+
+	blk_execute_rq(disk, rq, 0);
+	if (scsi_req(rq)->result) {
+		struct scsi_sense_hdr sshdr;
+
+		scsi_normalize_sense(req->sense, req->sense_len,
+				     &sshdr);
+		*last_sense = sshdr.sense_key;
+		ret = -EIO;
+	}
+
+	if (blk_rq_unmap_user(bio))
+		ret = -EFAULT;
+out_put_request:
+	blk_put_request(rq);
+	return ret;
+}
+
+
 /**
  *	sr_kref_release - Called to free the scsi_cd structure
  *	@kref: pointer to embedded kref
diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h
index f48d0a31deae..c4fef00abdf3 100644
--- a/include/linux/cdrom.h
+++ b/include/linux/cdrom.h
@@ -86,11 +86,13 @@ struct cdrom_device_ops {
 	/* play stuff */
 	int (*audio_ioctl) (struct cdrom_device_info *,unsigned int, void *);
 
-/* driver specifications */
-	const int capability;   /* capability flags */
 	/* handle uniform packets for scsi type devices (scsi,atapi) */
 	int (*generic_packet) (struct cdrom_device_info *,
 			       struct packet_command *);
+	int (*read_cdda_bpc)(struct cdrom_device_info *cdi, void __user *ubuf,
+			       u32 lba, u32 nframes, u8 *last_sense);
+/* driver specifications */
+	const int capability;   /* capability flags */
 };
 
 int cdrom_multisession(struct cdrom_device_info *cdi,
Anders Roxell July 30, 2021, 10:25 a.m. UTC | #2
On Fri, 30 Jul 2021 at 09:27, Christoph Hellwig <hch@lst.de> wrote:
>

Hi Christoph,

> On Thu, Jul 29, 2021 at 10:47:45AM +0200, Anders Roxell wrote:
> > From: Christoph Hellwig <hch@lst.de>
> >
> > > Move the SCSI-specific bsg code in the SCSI midlayer instead of in the
> > > common bsg code.  This just keeps the common bsg code block/ and also
> > > allows building it as a module.
> > >
> > > Signed-off-by: Christoph Hellwig <hch@lst.de>
> >
> > [ Please ignore if its already been reported ]
> >
> > When building arm's defconfig 'footbridge_defconfig' on linux-next tag next-20210728 I see the following error.
>
> Can you try this patch on top?

When I applied that patch ontop of tag next-20210728 and built arm's
defconfig 'footbridge_defconfig'
I it builds fine.

Thank you for the fix.

>
> ---
> From d92a8160ce3fbe64a250482522ca0456277781f9 Mon Sep 17 00:00:00 2001
> From: Christoph Hellwig <hch@lst.de>
> Date: Mon, 5 Jul 2021 15:02:43 +0200
> Subject: cdrom: move the guts of cdrom_read_cdda_bpc into the sr driver
>
> cdrom_read_cdda_bpc relies on sending SCSI command to the low level
> driver using a REQ_OP_SCSI_IN request.  This isn't generic block
> layer functionality, so some the actual low-level code into the sr
> driver and call it through a new read_cdda_bpc method in the
> cdrom_device_ops structure.
>
> With this the CDROM code does not have to pull in
> scsi_normalize_sense and this depend on CONFIG_SCSI_COMMON.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>

Tested-by: Anders Roxell <anders.roxell@linaro.org>

Cheers,
Anders

> ---
>  drivers/cdrom/cdrom.c | 71 +++++--------------------------------------
>  drivers/scsi/sr.c     | 56 +++++++++++++++++++++++++++++++++-
>  include/linux/cdrom.h |  6 ++--
>  3 files changed, 67 insertions(+), 66 deletions(-)
>
> diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
> index 8882b311bafd..bd2e5b1560f5 100644
> --- a/drivers/cdrom/cdrom.c
> +++ b/drivers/cdrom/cdrom.c
> @@ -629,7 +629,7 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi)
>         if (CDROM_CAN(CDC_MRW_W))
>                 cdi->exit = cdrom_mrw_exit;
>
> -       if (cdi->disk)
> +       if (cdi->ops->read_cdda_bpc)
>                 cdi->cdda_method = CDDA_BPC_FULL;
>         else
>                 cdi->cdda_method = CDDA_OLD;
> @@ -2159,81 +2159,26 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf,
>  static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
>                                int lba, int nframes)
>  {
> -       struct request_queue *q = cdi->disk->queue;
> -       struct request *rq;
> -       struct scsi_request *req;
> -       struct bio *bio;
> -       unsigned int len;
> +       int max_frames = (queue_max_sectors(cdi->disk->queue) << 9) /
> +                         CD_FRAMESIZE_RAW;
>         int nr, ret = 0;
>
> -       if (!q)
> -               return -ENXIO;
> -
> -       if (!blk_queue_scsi_passthrough(q)) {
> -               WARN_ONCE(true,
> -                         "Attempt read CDDA info through a non-SCSI queue\n");
> -               return -EINVAL;
> -       }
> -
>         cdi->last_sense = 0;
>
>         while (nframes) {
> -               nr = nframes;
>                 if (cdi->cdda_method == CDDA_BPC_SINGLE)
>                         nr = 1;
> -               if (nr * CD_FRAMESIZE_RAW > (queue_max_sectors(q) << 9))
> -                       nr = (queue_max_sectors(q) << 9) / CD_FRAMESIZE_RAW;
> -
> -               len = nr * CD_FRAMESIZE_RAW;
> -
> -               rq = blk_get_request(q, REQ_OP_DRV_IN, 0);
> -               if (IS_ERR(rq)) {
> -                       ret = PTR_ERR(rq);
> -                       break;
> -               }
> -               req = scsi_req(rq);
> -
> -               ret = blk_rq_map_user(q, rq, NULL, ubuf, len, GFP_KERNEL);
> -               if (ret) {
> -                       blk_put_request(rq);
> -                       break;
> -               }
> -
> -               req->cmd[0] = GPCMD_READ_CD;
> -               req->cmd[1] = 1 << 2;
> -               req->cmd[2] = (lba >> 24) & 0xff;
> -               req->cmd[3] = (lba >> 16) & 0xff;
> -               req->cmd[4] = (lba >>  8) & 0xff;
> -               req->cmd[5] = lba & 0xff;
> -               req->cmd[6] = (nr >> 16) & 0xff;
> -               req->cmd[7] = (nr >>  8) & 0xff;
> -               req->cmd[8] = nr & 0xff;
> -               req->cmd[9] = 0xf8;
> -
> -               req->cmd_len = 12;
> -               rq->timeout = 60 * HZ;
> -               bio = rq->bio;
> -
> -               blk_execute_rq(cdi->disk, rq, 0);
> -               if (scsi_req(rq)->result) {
> -                       struct scsi_sense_hdr sshdr;
> -
> -                       ret = -EIO;
> -                       scsi_normalize_sense(req->sense, req->sense_len,
> -                                            &sshdr);
> -                       cdi->last_sense = sshdr.sense_key;
> -               }
> -
> -               if (blk_rq_unmap_user(bio))
> -                       ret = -EFAULT;
> -               blk_put_request(rq);
> +               else
> +                       nr = min(nframes, max_frames);
>
> +               ret = cdi->ops->read_cdda_bpc(cdi, ubuf, lba, nr,
> +                                             &cdi->last_sense);
>                 if (ret)
>                         break;
>
>                 nframes -= nr;
>                 lba += nr;
> -               ubuf += len;
> +               ubuf += (nr * CD_FRAMESIZE_RAW);
>         }
>
>         return ret;
> diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
> index b98e77fe700b..6203a8b58d40 100644
> --- a/drivers/scsi/sr.c
> +++ b/drivers/scsi/sr.c
> @@ -120,6 +120,8 @@ static void get_capabilities(struct scsi_cd *);
>  static unsigned int sr_check_events(struct cdrom_device_info *cdi,
>                                     unsigned int clearing, int slot);
>  static int sr_packet(struct cdrom_device_info *, struct packet_command *);
> +static int sr_read_cdda_bpc(struct cdrom_device_info *cdi, void __user *ubuf,
> +               u32 lba, u32 nr, u8 *last_sense);
>
>  static const struct cdrom_device_ops sr_dops = {
>         .open                   = sr_open,
> @@ -133,8 +135,9 @@ static const struct cdrom_device_ops sr_dops = {
>         .get_mcn                = sr_get_mcn,
>         .reset                  = sr_reset,
>         .audio_ioctl            = sr_audio_ioctl,
> -       .capability             = SR_CAPABILITIES,
>         .generic_packet         = sr_packet,
> +       .read_cdda_bpc          = sr_read_cdda_bpc,
> +       .capability             = SR_CAPABILITIES,
>  };
>
>  static void sr_kref_release(struct kref *kref);
> @@ -951,6 +954,57 @@ static int sr_packet(struct cdrom_device_info *cdi,
>         return cgc->stat;
>  }
>
> +static int sr_read_cdda_bpc(struct cdrom_device_info *cdi, void __user *ubuf,
> +               u32 lba, u32 nr, u8 *last_sense)
> +{
> +       struct gendisk *disk = cdi->disk;
> +       u32 len = nr * CD_FRAMESIZE_RAW;
> +       struct scsi_request *req;
> +       struct request *rq;
> +       struct bio *bio;
> +       int ret;
> +
> +       rq = blk_get_request(disk->queue, REQ_OP_DRV_IN, 0);
> +       if (IS_ERR(rq))
> +               return PTR_ERR(rq);
> +       req = scsi_req(rq);
> +
> +       ret = blk_rq_map_user(disk->queue, rq, NULL, ubuf, len, GFP_KERNEL);
> +       if (ret)
> +               goto out_put_request;
> +
> +       req->cmd[0] = GPCMD_READ_CD;
> +       req->cmd[1] = 1 << 2;
> +       req->cmd[2] = (lba >> 24) & 0xff;
> +       req->cmd[3] = (lba >> 16) & 0xff;
> +       req->cmd[4] = (lba >>  8) & 0xff;
> +       req->cmd[5] = lba & 0xff;
> +       req->cmd[6] = (nr >> 16) & 0xff;
> +       req->cmd[7] = (nr >>  8) & 0xff;
> +       req->cmd[8] = nr & 0xff;
> +       req->cmd[9] = 0xf8;
> +       req->cmd_len = 12;
> +       rq->timeout = 60 * HZ;
> +       bio = rq->bio;
> +
> +       blk_execute_rq(disk, rq, 0);
> +       if (scsi_req(rq)->result) {
> +               struct scsi_sense_hdr sshdr;
> +
> +               scsi_normalize_sense(req->sense, req->sense_len,
> +                                    &sshdr);
> +               *last_sense = sshdr.sense_key;
> +               ret = -EIO;
> +       }
> +
> +       if (blk_rq_unmap_user(bio))
> +               ret = -EFAULT;
> +out_put_request:
> +       blk_put_request(rq);
> +       return ret;
> +}
> +
> +
>  /**
>   *     sr_kref_release - Called to free the scsi_cd structure
>   *     @kref: pointer to embedded kref
> diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h
> index f48d0a31deae..c4fef00abdf3 100644
> --- a/include/linux/cdrom.h
> +++ b/include/linux/cdrom.h
> @@ -86,11 +86,13 @@ struct cdrom_device_ops {
>         /* play stuff */
>         int (*audio_ioctl) (struct cdrom_device_info *,unsigned int, void *);
>
> -/* driver specifications */
> -       const int capability;   /* capability flags */
>         /* handle uniform packets for scsi type devices (scsi,atapi) */
>         int (*generic_packet) (struct cdrom_device_info *,
>                                struct packet_command *);
> +       int (*read_cdda_bpc)(struct cdrom_device_info *cdi, void __user *ubuf,
> +                              u32 lba, u32 nframes, u8 *last_sense);
> +/* driver specifications */
> +       const int capability;   /* capability flags */
>  };
>
>  int cdrom_multisession(struct cdrom_device_info *cdi,
> --
> 2.30.2
>
diff mbox series

Patch

diff --git a/block/Kconfig b/block/Kconfig
index fd732aede922..88aa88241795 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -35,29 +35,12 @@  config BLK_SCSI_REQUEST
 config BLK_CGROUP_RWSTAT
 	bool
 
-config BLK_DEV_BSG
-	bool "Block layer SG support v4"
-	default y
-	select BLK_SCSI_REQUEST
-	help
-	  Saying Y here will enable generic SG (SCSI generic) v4 support
-	  for any block device.
-
-	  Unlike SG v3 (aka block/scsi_ioctl.c drivers/scsi/sg.c), SG v4
-	  can handle complicated SCSI commands: tagged variable length cdbs
-	  with bidirectional data transfers and generic request/response
-	  protocols (e.g. Task Management Functions and SMP in Serial
-	  Attached SCSI).
-
-	  This option is required by recent UDEV versions to properly
-	  access device serial numbers, etc.
-
-	  If unsure, say Y.
+config BLK_DEV_BSG_COMMON
+	tristate
 
 config BLK_DEV_BSGLIB
 	bool "Block layer SG support v4 helper lib"
-	select BLK_DEV_BSG
-	select BLK_SCSI_REQUEST
+	select BLK_DEV_BSG_COMMON
 	help
 	  Subsystems will normally enable this if needed. Users will not
 	  normally need to manually enable this.
diff --git a/block/Makefile b/block/Makefile
index bfbe4e13ca1e..f37d532c8da5 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -13,7 +13,7 @@  obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-sysfs.o \
 
 obj-$(CONFIG_BOUNCE)		+= bounce.o
 obj-$(CONFIG_BLK_SCSI_REQUEST)	+= scsi_ioctl.o
-obj-$(CONFIG_BLK_DEV_BSG)	+= bsg.o
+obj-$(CONFIG_BLK_DEV_BSG_COMMON) += bsg.o
 obj-$(CONFIG_BLK_DEV_BSGLIB)	+= bsg-lib.o
 obj-$(CONFIG_BLK_CGROUP)	+= blk-cgroup.o
 obj-$(CONFIG_BLK_CGROUP_RWSTAT)	+= blk-cgroup-rwstat.o
diff --git a/block/bsg.c b/block/bsg.c
index 38dd434636d8..6a8f518abe39 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -15,9 +15,6 @@ 
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_ioctl.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_driver.h>
 #include <scsi/sg.h>
 
 #define BSG_DESCRIPTION	"Block layer SCSI generic (bsg) driver"
@@ -54,86 +51,6 @@  static inline struct hlist_head *bsg_dev_idx_hash(int index)
 
 #define uptr64(val) ((void __user *)(uintptr_t)(val))
 
-static int bsg_scsi_check_proto(struct sg_io_v4 *hdr)
-{
-	if (hdr->protocol != BSG_PROTOCOL_SCSI  ||
-	    hdr->subprotocol != BSG_SUB_PROTOCOL_SCSI_CMD)
-		return -EINVAL;
-	return 0;
-}
-
-static int bsg_scsi_fill_hdr(struct request *rq, struct sg_io_v4 *hdr,
-		fmode_t mode)
-{
-	struct scsi_request *sreq = scsi_req(rq);
-
-	if (hdr->dout_xfer_len && hdr->din_xfer_len) {
-		pr_warn_once("BIDI support in bsg has been removed.\n");
-		return -EOPNOTSUPP;
-	}
-
-	sreq->cmd_len = hdr->request_len;
-	if (sreq->cmd_len > BLK_MAX_CDB) {
-		sreq->cmd = kzalloc(sreq->cmd_len, GFP_KERNEL);
-		if (!sreq->cmd)
-			return -ENOMEM;
-	}
-
-	if (copy_from_user(sreq->cmd, uptr64(hdr->request), sreq->cmd_len))
-		return -EFAULT;
-	if (blk_verify_command(sreq->cmd, mode))
-		return -EPERM;
-	return 0;
-}
-
-static int bsg_scsi_complete_rq(struct request *rq, struct sg_io_v4 *hdr)
-{
-	struct scsi_request *sreq = scsi_req(rq);
-	int ret = 0;
-
-	/*
-	 * fill in all the output members
-	 */
-	hdr->device_status = sreq->result & 0xff;
-	hdr->transport_status = host_byte(sreq->result);
-	hdr->driver_status = 0;
-	if (scsi_status_is_check_condition(sreq->result))
-		hdr->driver_status = DRIVER_SENSE;
-	hdr->info = 0;
-	if (hdr->device_status || hdr->transport_status || hdr->driver_status)
-		hdr->info |= SG_INFO_CHECK;
-	hdr->response_len = 0;
-
-	if (sreq->sense_len && hdr->response) {
-		int len = min_t(unsigned int, hdr->max_response_len,
-					sreq->sense_len);
-
-		if (copy_to_user(uptr64(hdr->response), sreq->sense, len))
-			ret = -EFAULT;
-		else
-			hdr->response_len = len;
-	}
-
-	if (rq_data_dir(rq) == READ)
-		hdr->din_resid = sreq->resid_len;
-	else
-		hdr->dout_resid = sreq->resid_len;
-
-	return ret;
-}
-
-static void bsg_scsi_free_rq(struct request *rq)
-{
-	scsi_req_free_cmd(scsi_req(rq));
-}
-
-static const struct bsg_ops bsg_scsi_ops = {
-	.check_proto		= bsg_scsi_check_proto,
-	.fill_hdr		= bsg_scsi_fill_hdr,
-	.complete_rq		= bsg_scsi_complete_rq,
-	.free_rq		= bsg_scsi_free_rq,
-};
-
 static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg)
 {
 	struct request *rq;
@@ -487,17 +404,7 @@  int bsg_register_queue(struct request_queue *q, struct device *parent,
 	mutex_unlock(&bsg_mutex);
 	return ret;
 }
-
-int bsg_scsi_register_queue(struct request_queue *q, struct device *parent)
-{
-	if (!blk_queue_scsi_passthrough(q)) {
-		WARN_ONCE(true, "Attempt to register a non-SCSI queue\n");
-		return -EINVAL;
-	}
-
-	return bsg_register_queue(q, parent, dev_name(parent), &bsg_scsi_ops);
-}
-EXPORT_SYMBOL_GPL(bsg_scsi_register_queue);
+EXPORT_SYMBOL_GPL(bsg_register_queue);
 
 static struct cdev bsg_cdev;
 
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 8f44d433e06e..86ecab196dfd 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -20,6 +20,7 @@  config SCSI
 	select SCSI_DMA if HAS_DMA
 	select SG_POOL
 	select BLK_SCSI_REQUEST
+	select BLK_DEV_BSG_COMMON if BLK_DEV_BSG
 	help
 	  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
 	  any other SCSI device under Linux, say Y and make sure that you know
@@ -140,6 +141,18 @@  config CHR_DEV_SG
 
 	  If unsure, say N.
 
+config BLK_DEV_BSG
+	bool "/dev/bsg support (SG v4)"
+	depends on SCSI
+	default y
+	help
+	  Saying Y here will enable generic SG (SCSI generic) v4 support
+	  for any SCSI device.
+
+	  This option is required by UDEV to access device serial numbers, etc.
+
+	  If unsure, say Y.
+
 config CHR_DEV_SCH
 	tristate "SCSI media changer support"
 	depends on SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 1748d1ec1338..240b831b5a11 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -168,6 +168,7 @@  scsi_mod-$(CONFIG_BLK_DEBUG_FS)	+= scsi_debugfs.o
 scsi_mod-y			+= scsi_trace.o scsi_logging.o
 scsi_mod-$(CONFIG_PM)		+= scsi_pm.o
 scsi_mod-$(CONFIG_SCSI_DH)	+= scsi_dh.o
+scsi_mod-$(CONFIG_BLK_DEV_BSG)	+= scsi_bsg.o
 
 hv_storvsc-y			:= storvsc_drv.o
 
diff --git a/drivers/scsi/scsi_bsg.c b/drivers/scsi/scsi_bsg.c
new file mode 100644
index 000000000000..3bdb28940460
--- /dev/null
+++ b/drivers/scsi/scsi_bsg.c
@@ -0,0 +1,95 @@ 
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bsg.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/sg.h>
+#include "scsi_priv.h"
+
+#define uptr64(val) ((void __user *)(uintptr_t)(val))
+
+static int scsi_bsg_check_proto(struct sg_io_v4 *hdr)
+{
+	if (hdr->protocol != BSG_PROTOCOL_SCSI  ||
+	    hdr->subprotocol != BSG_SUB_PROTOCOL_SCSI_CMD)
+		return -EINVAL;
+	return 0;
+}
+
+static int scsi_bsg_fill_hdr(struct request *rq, struct sg_io_v4 *hdr,
+		fmode_t mode)
+{
+	struct scsi_request *sreq = scsi_req(rq);
+
+	if (hdr->dout_xfer_len && hdr->din_xfer_len) {
+		pr_warn_once("BIDI support in bsg has been removed.\n");
+		return -EOPNOTSUPP;
+	}
+
+	sreq->cmd_len = hdr->request_len;
+	if (sreq->cmd_len > BLK_MAX_CDB) {
+		sreq->cmd = kzalloc(sreq->cmd_len, GFP_KERNEL);
+		if (!sreq->cmd)
+			return -ENOMEM;
+	}
+
+	if (copy_from_user(sreq->cmd, uptr64(hdr->request), sreq->cmd_len))
+		return -EFAULT;
+	if (blk_verify_command(sreq->cmd, mode))
+		return -EPERM;
+	return 0;
+}
+
+static int scsi_bsg_complete_rq(struct request *rq, struct sg_io_v4 *hdr)
+{
+	struct scsi_request *sreq = scsi_req(rq);
+	int ret = 0;
+
+	/*
+	 * fill in all the output members
+	 */
+	hdr->device_status = sreq->result & 0xff;
+	hdr->transport_status = host_byte(sreq->result);
+	hdr->driver_status = 0;
+	if (scsi_status_is_check_condition(sreq->result))
+		hdr->driver_status = DRIVER_SENSE;
+	hdr->info = 0;
+	if (hdr->device_status || hdr->transport_status || hdr->driver_status)
+		hdr->info |= SG_INFO_CHECK;
+	hdr->response_len = 0;
+
+	if (sreq->sense_len && hdr->response) {
+		int len = min_t(unsigned int, hdr->max_response_len,
+					sreq->sense_len);
+
+		if (copy_to_user(uptr64(hdr->response), sreq->sense, len))
+			ret = -EFAULT;
+		else
+			hdr->response_len = len;
+	}
+
+	if (rq_data_dir(rq) == READ)
+		hdr->din_resid = sreq->resid_len;
+	else
+		hdr->dout_resid = sreq->resid_len;
+
+	return ret;
+}
+
+static void scsi_bsg_free_rq(struct request *rq)
+{
+	scsi_req_free_cmd(scsi_req(rq));
+}
+
+static const struct bsg_ops scsi_bsg_ops = {
+	.check_proto		= scsi_bsg_check_proto,
+	.fill_hdr		= scsi_bsg_fill_hdr,
+	.complete_rq		= scsi_bsg_complete_rq,
+	.free_rq		= scsi_bsg_free_rq,
+};
+
+int scsi_bsg_register_queue(struct request_queue *q, struct device *parent)
+{
+	return bsg_register_queue(q, parent, dev_name(parent), &scsi_bsg_ops);
+}
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index eae2235f79b5..0a0db35bab04 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -180,6 +180,16 @@  static inline void scsi_dh_add_device(struct scsi_device *sdev) { }
 static inline void scsi_dh_release_device(struct scsi_device *sdev) { }
 #endif
 
+#ifdef CONFIG_BLK_DEV_BSG
+int scsi_bsg_register_queue(struct request_queue *q, struct device *parent);
+#else
+static inline int scsi_bsg_register_queue(struct request_queue *q,
+		struct device *parent)
+{
+	return 0;
+}
+#endif
+
 extern int scsi_device_max_queue_depth(struct scsi_device *sdev);
 
 /* 
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 32489d25158f..4ff9ac3296d8 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1366,7 +1366,7 @@  int scsi_sysfs_add_sdev(struct scsi_device *sdev)
 	transport_add_device(&sdev->sdev_gendev);
 	sdev->is_visible = 1;
 
-	error = bsg_scsi_register_queue(rq, &sdev->sdev_gendev);
+	error = scsi_bsg_register_queue(rq, &sdev->sdev_gendev);
 	if (error)
 		/* we're treating error on bsg register as non-fatal,
 		 * so pretend nothing went wrong */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 9971796819ef..d36b67bd7267 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -537,7 +537,7 @@  struct request_queue {
 
 	int			mq_freeze_depth;
 
-#if defined(CONFIG_BLK_DEV_BSG)
+#if IS_ENABLED(CONFIG_BLK_DEV_BSG_COMMON)
 	struct bsg_class_device bsg_dev;
 #endif
 
diff --git a/include/linux/bsg.h b/include/linux/bsg.h
index dac37b6e00ec..b887da20bd41 100644
--- a/include/linux/bsg.h
+++ b/include/linux/bsg.h
@@ -5,8 +5,9 @@ 
 #include <uapi/linux/bsg.h>
 
 struct request;
+struct request_queue;
 
-#ifdef CONFIG_BLK_DEV_BSG
+#ifdef CONFIG_BLK_DEV_BSG_COMMON
 struct bsg_ops {
 	int	(*check_proto)(struct sg_io_v4 *hdr);
 	int	(*fill_hdr)(struct request *rq, struct sg_io_v4 *hdr,
@@ -24,16 +25,10 @@  struct bsg_class_device {
 
 int bsg_register_queue(struct request_queue *q, struct device *parent,
 		const char *name, const struct bsg_ops *ops);
-int bsg_scsi_register_queue(struct request_queue *q, struct device *parent);
 void bsg_unregister_queue(struct request_queue *q);
 #else
-static inline int bsg_scsi_register_queue(struct request_queue *q,
-		struct device *parent)
-{
-	return 0;
-}
 static inline void bsg_unregister_queue(struct request_queue *q)
 {
 }
-#endif /* CONFIG_BLK_DEV_BSG */
+#endif /* CONFIG_BLK_DEV_BSG_COMMON */
 #endif /* _LINUX_BSG_H */