Commit 78011042 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Martin K. Petersen

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.deSigned-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent d52fe8f4
...@@ -35,29 +35,12 @@ config BLK_SCSI_REQUEST ...@@ -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.
......
...@@ -13,7 +13,7 @@ obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-sysfs.o \ ...@@ -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
......
...@@ -15,9 +15,6 @@ ...@@ -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) ...@@ -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 @@ int bsg_register_queue(struct request_queue *q, struct device *parent, ...@@ -487,17 +404,7 @@ int bsg_register_queue(struct request_queue *q, struct device *parent,
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;
......
...@@ -20,6 +20,7 @@ config SCSI ...@@ -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 ...@@ -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
......
...@@ -168,6 +168,7 @@ scsi_mod-$(CONFIG_BLK_DEBUG_FS) += scsi_debugfs.o ...@@ -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
......
// 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);
}
...@@ -180,6 +180,16 @@ static inline void scsi_dh_add_device(struct scsi_device *sdev) { } ...@@ -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);
/* /*
......
...@@ -1366,7 +1366,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) ...@@ -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 */
......
...@@ -537,7 +537,7 @@ struct request_queue { ...@@ -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
......
...@@ -5,8 +5,9 @@ ...@@ -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 { ...@@ -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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment