scsi: bsg: Move bsg_scsi_ops to drivers/scsi/

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.

Link: https://lore.kernel.org/r/20210724072033.1284840-15-hch@lst.de
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Christoph Hellwig 2021-07-24 09:20:23 +02:00 committed by Martin K. Petersen
parent d52fe8f436
commit 7801104268
10 changed files with 129 additions and 125 deletions

View File

@ -35,29 +35,12 @@ config BLK_SCSI_REQUEST
config BLK_CGROUP_RWSTAT config BLK_CGROUP_RWSTAT
bool bool
config BLK_DEV_BSG config BLK_DEV_BSG_COMMON
bool "Block layer SG support v4" tristate
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_BSGLIB config BLK_DEV_BSGLIB
bool "Block layer SG support v4 helper lib" bool "Block layer SG support v4 helper lib"
select BLK_DEV_BSG select BLK_DEV_BSG_COMMON
select BLK_SCSI_REQUEST
help help
Subsystems will normally enable this if needed. Users will not Subsystems will normally enable this if needed. Users will not
normally need to manually enable this. normally need to manually enable this.

View File

@ -13,7 +13,7 @@ obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-sysfs.o \
obj-$(CONFIG_BOUNCE) += bounce.o obj-$(CONFIG_BOUNCE) += bounce.o
obj-$(CONFIG_BLK_SCSI_REQUEST) += scsi_ioctl.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_DEV_BSGLIB) += bsg-lib.o
obj-$(CONFIG_BLK_CGROUP) += blk-cgroup.o obj-$(CONFIG_BLK_CGROUP) += blk-cgroup.o
obj-$(CONFIG_BLK_CGROUP_RWSTAT) += blk-cgroup-rwstat.o obj-$(CONFIG_BLK_CGROUP_RWSTAT) += blk-cgroup-rwstat.o

View File

@ -15,9 +15,6 @@
#include <scsi/scsi.h> #include <scsi/scsi.h>
#include <scsi/scsi_ioctl.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> #include <scsi/sg.h>
#define BSG_DESCRIPTION "Block layer SCSI generic (bsg) driver" #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)) #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) static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg)
{ {
struct request *rq; struct request *rq;
@ -487,17 +404,7 @@ unlock:
mutex_unlock(&bsg_mutex); mutex_unlock(&bsg_mutex);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(bsg_register_queue);
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);
static struct cdev bsg_cdev; static struct cdev bsg_cdev;

View File

@ -20,6 +20,7 @@ config SCSI
select SCSI_DMA if HAS_DMA select SCSI_DMA if HAS_DMA
select SG_POOL select SG_POOL
select BLK_SCSI_REQUEST select BLK_SCSI_REQUEST
select BLK_DEV_BSG_COMMON if BLK_DEV_BSG
help help
If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or 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 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. 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 config CHR_DEV_SCH
tristate "SCSI media changer support" tristate "SCSI media changer support"
depends on SCSI depends on SCSI

View File

@ -168,6 +168,7 @@ scsi_mod-$(CONFIG_BLK_DEBUG_FS) += scsi_debugfs.o
scsi_mod-y += scsi_trace.o scsi_logging.o scsi_mod-y += scsi_trace.o scsi_logging.o
scsi_mod-$(CONFIG_PM) += scsi_pm.o scsi_mod-$(CONFIG_PM) += scsi_pm.o
scsi_mod-$(CONFIG_SCSI_DH) += scsi_dh.o scsi_mod-$(CONFIG_SCSI_DH) += scsi_dh.o
scsi_mod-$(CONFIG_BLK_DEV_BSG) += scsi_bsg.o
hv_storvsc-y := storvsc_drv.o hv_storvsc-y := storvsc_drv.o

95
drivers/scsi/scsi_bsg.c Normal file
View File

@ -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);
}

View File

@ -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) { } static inline void scsi_dh_release_device(struct scsi_device *sdev) { }
#endif #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); extern int scsi_device_max_queue_depth(struct scsi_device *sdev);
/* /*

View File

@ -1366,7 +1366,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
transport_add_device(&sdev->sdev_gendev); transport_add_device(&sdev->sdev_gendev);
sdev->is_visible = 1; sdev->is_visible = 1;
error = bsg_scsi_register_queue(rq, &sdev->sdev_gendev); error = scsi_bsg_register_queue(rq, &sdev->sdev_gendev);
if (error) if (error)
/* we're treating error on bsg register as non-fatal, /* we're treating error on bsg register as non-fatal,
* so pretend nothing went wrong */ * so pretend nothing went wrong */

View File

@ -537,7 +537,7 @@ struct request_queue {
int mq_freeze_depth; int mq_freeze_depth;
#if defined(CONFIG_BLK_DEV_BSG) #if IS_ENABLED(CONFIG_BLK_DEV_BSG_COMMON)
struct bsg_class_device bsg_dev; struct bsg_class_device bsg_dev;
#endif #endif

View File

@ -5,8 +5,9 @@
#include <uapi/linux/bsg.h> #include <uapi/linux/bsg.h>
struct request; struct request;
struct request_queue;
#ifdef CONFIG_BLK_DEV_BSG #ifdef CONFIG_BLK_DEV_BSG_COMMON
struct bsg_ops { struct bsg_ops {
int (*check_proto)(struct sg_io_v4 *hdr); int (*check_proto)(struct sg_io_v4 *hdr);
int (*fill_hdr)(struct request *rq, 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, int bsg_register_queue(struct request_queue *q, struct device *parent,
const char *name, const struct bsg_ops *ops); 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); void bsg_unregister_queue(struct request_queue *q);
#else #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) 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 */ #endif /* _LINUX_BSG_H */