Skip to content

Commit

Permalink
bsg: move bsg_scsi_ops to drivers/scsi/
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Christoph Hellwig authored and intel-lab-lkp committed Jul 12, 2021
1 parent 127916f commit 7cec3a0
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 124 deletions.
23 changes: 3 additions & 20 deletions block/Kconfig
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion block/Makefile
Expand Up @@ -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
Expand Down
95 changes: 1 addition & 94 deletions block/bsg.c
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -486,17 +403,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;

Expand Down
13 changes: 13 additions & 0 deletions drivers/scsi/Kconfig
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/Makefile
Expand Up @@ -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

Expand Down
95 changes: 95 additions & 0 deletions 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 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,
};

int bsg_scsi_register_queue(struct request_queue *q, struct device *parent)
{
return bsg_register_queue(q, parent, dev_name(parent), &bsg_scsi_ops);
}
10 changes: 10 additions & 0 deletions drivers/scsi/scsi_priv.h
Expand Up @@ -181,6 +181,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 bsg_scsi_register_queue(struct request_queue *q, struct device *parent);
#else
static inline int bsg_scsi_register_queue(struct request_queue *q,
struct device *parent)
{
return 0;
}
#endif

extern int scsi_device_max_queue_depth(struct scsi_device *sdev);

/*
Expand Down
2 changes: 1 addition & 1 deletion include/linux/blkdev.h
Expand Up @@ -537,7 +537,7 @@ struct request_queue {

int mq_freeze_depth;

#if defined(CONFIG_BLK_DEV_BSG)
#if defined(CONFIG_BLK_DEV_BSG_COMMON)
struct bsg_class_device bsg_dev;
#endif

Expand Down
11 changes: 3 additions & 8 deletions include/linux/bsg.h
Expand Up @@ -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,
Expand All @@ -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 */

0 comments on commit 7cec3a0

Please sign in to comment.