Message ID | 20210724072033.1284840-15-hch@lst.de |
---|---|
State | New |
Headers | show |
Series | None | expand |
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, -- 2.30.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 --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 */
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