1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/bsg.h> 3 #include <scsi/scsi.h> 4 #include <scsi/scsi_ioctl.h> 5 #include <scsi/scsi_cmnd.h> 6 #include <scsi/scsi_device.h> 7 #include <scsi/sg.h> 8 #include "scsi_priv.h" 9 10 #define uptr64(val) ((void __user *)(uintptr_t)(val)) 11 12 static int scsi_bsg_sg_io_fn(struct request_queue *q, struct sg_io_v4 *hdr, 13 bool open_for_write, unsigned int timeout) 14 { 15 struct scsi_cmnd *scmd; 16 struct request *rq; 17 struct bio *bio; 18 int ret; 19 20 if (hdr->protocol != BSG_PROTOCOL_SCSI || 21 hdr->subprotocol != BSG_SUB_PROTOCOL_SCSI_CMD) 22 return -EINVAL; 23 if (hdr->dout_xfer_len && hdr->din_xfer_len) { 24 pr_warn_once("BIDI support in bsg has been removed.\n"); 25 return -EOPNOTSUPP; 26 } 27 28 rq = scsi_alloc_request(q, hdr->dout_xfer_len ? 29 REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); 30 if (IS_ERR(rq)) 31 return PTR_ERR(rq); 32 rq->timeout = timeout; 33 34 scmd = blk_mq_rq_to_pdu(rq); 35 scmd->cmd_len = hdr->request_len; 36 if (scmd->cmd_len > sizeof(scmd->cmnd)) { 37 ret = -EINVAL; 38 goto out_put_request; 39 } 40 41 ret = -EFAULT; 42 if (copy_from_user(scmd->cmnd, uptr64(hdr->request), scmd->cmd_len)) 43 goto out_put_request; 44 ret = -EPERM; 45 if (!scsi_cmd_allowed(scmd->cmnd, open_for_write)) 46 goto out_put_request; 47 48 ret = 0; 49 if (hdr->dout_xfer_len) { 50 ret = blk_rq_map_user(rq->q, rq, NULL, uptr64(hdr->dout_xferp), 51 hdr->dout_xfer_len, GFP_KERNEL); 52 } else if (hdr->din_xfer_len) { 53 ret = blk_rq_map_user(rq->q, rq, NULL, uptr64(hdr->din_xferp), 54 hdr->din_xfer_len, GFP_KERNEL); 55 } 56 57 if (ret) 58 goto out_put_request; 59 60 bio = rq->bio; 61 blk_execute_rq(rq, !(hdr->flags & BSG_FLAG_Q_AT_TAIL)); 62 63 /* 64 * fill in all the output members 65 */ 66 hdr->device_status = scmd->result & 0xff; 67 hdr->transport_status = host_byte(scmd->result); 68 hdr->driver_status = 0; 69 if (scsi_status_is_check_condition(scmd->result)) 70 hdr->driver_status = DRIVER_SENSE; 71 hdr->info = 0; 72 if (hdr->device_status || hdr->transport_status || hdr->driver_status) 73 hdr->info |= SG_INFO_CHECK; 74 hdr->response_len = 0; 75 76 if (scmd->sense_len && hdr->response) { 77 int len = min_t(unsigned int, hdr->max_response_len, 78 scmd->sense_len); 79 80 if (copy_to_user(uptr64(hdr->response), scmd->sense_buffer, 81 len)) 82 ret = -EFAULT; 83 else 84 hdr->response_len = len; 85 } 86 87 if (rq_data_dir(rq) == READ) 88 hdr->din_resid = scmd->resid_len; 89 else 90 hdr->dout_resid = scmd->resid_len; 91 92 blk_rq_unmap_user(bio); 93 94 out_put_request: 95 blk_mq_free_request(rq); 96 return ret; 97 } 98 99 struct bsg_device *scsi_bsg_register_queue(struct scsi_device *sdev) 100 { 101 return bsg_register_queue(sdev->request_queue, &sdev->sdev_gendev, 102 dev_name(&sdev->sdev_gendev), scsi_bsg_sg_io_fn); 103 } 104