提交 70e36ece 编写于 作者: F FUJITA Tomonori 提交者: Jens Axboe

bsg: replace SG v3 with SG v4

This patch replaces SG v3 in bsg with SG v4 (except for SG_IO).
Signed-off-by: NFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: NJens Axboe <jens.axboe@oracle.com>
上级 45977d0e
...@@ -103,8 +103,8 @@ struct bsg_command { ...@@ -103,8 +103,8 @@ struct bsg_command {
struct request *rq; struct request *rq;
struct bio *bio; struct bio *bio;
int err; int err;
struct sg_io_hdr hdr; struct sg_io_v4 hdr;
struct sg_io_hdr __user *uhdr; struct sg_io_v4 __user *uhdr;
char sense[SCSI_SENSE_BUFFERSIZE]; char sense[SCSI_SENSE_BUFFERSIZE];
}; };
...@@ -235,57 +235,82 @@ static struct bsg_command *bsg_get_command(struct bsg_device *bd) ...@@ -235,57 +235,82 @@ static struct bsg_command *bsg_get_command(struct bsg_device *bd)
return bc; return bc;
} }
static int blk_fill_sgv4_hdr_rq(request_queue_t *q, struct request *rq,
struct sg_io_v4 *hdr, int has_write_perm)
{
memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
if (copy_from_user(rq->cmd, (void *)(unsigned long)hdr->request,
hdr->request_len))
return -EFAULT;
if (blk_verify_command(rq->cmd, has_write_perm))
return -EPERM;
/*
* fill in request structure
*/
rq->cmd_len = hdr->request_len;
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = (hdr->timeout * HZ) / 1000;
if (!rq->timeout)
rq->timeout = q->sg_timeout;
if (!rq->timeout)
rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
return 0;
}
/* /*
* Check if sg_io_hdr from user is allowed and valid * Check if sg_io_v4 from user is allowed and valid
*/ */
static int static int
bsg_validate_sghdr(request_queue_t *q, struct sg_io_hdr *hdr, int *rw) bsg_validate_sgv4_hdr(request_queue_t *q, struct sg_io_v4 *hdr, int *rw)
{ {
if (hdr->interface_id != 'S') if (hdr->guard != 'Q')
return -EINVAL; return -EINVAL;
if (hdr->cmd_len > BLK_MAX_CDB) if (hdr->request_len > BLK_MAX_CDB)
return -EINVAL; return -EINVAL;
if (hdr->dxfer_len > (q->max_sectors << 9)) if (hdr->dout_xfer_len > (q->max_sectors << 9) ||
hdr->din_xfer_len > (q->max_sectors << 9))
return -EIO; return -EIO;
/* not supported currently */
if (hdr->protocol || hdr->subprotocol)
return -EINVAL;
/* /*
* looks sane, if no data then it should be fine from our POV * looks sane, if no data then it should be fine from our POV
*/ */
if (!hdr->dxfer_len) if (!hdr->dout_xfer_len && !hdr->din_xfer_len)
return 0; return 0;
switch (hdr->dxfer_direction) { /* not supported currently */
case SG_DXFER_TO_FROM_DEV: if (hdr->dout_xfer_len && hdr->din_xfer_len)
case SG_DXFER_FROM_DEV: return -EINVAL;
*rw = READ;
break; *rw = hdr->dout_xfer_len ? WRITE : READ;
case SG_DXFER_TO_DEV:
*rw = WRITE;
break;
default:
return -EINVAL;
}
return 0; return 0;
} }
/* /*
* map sg_io_hdr to a request. for scatter-gather sg_io_hdr, we map * map sg_io_v4 to a request.
* each segment to a bio and string multiple bio's to the request
*/ */
static struct request * static struct request *
bsg_map_hdr(struct bsg_device *bd, int rw, struct sg_io_hdr *hdr) bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr)
{ {
request_queue_t *q = bd->queue; request_queue_t *q = bd->queue;
struct sg_iovec iov;
struct sg_iovec __user *u_iov;
struct request *rq; struct request *rq;
int ret, i = 0; int ret, rw;
unsigned int dxfer_len;
void *dxferp = NULL;
dprintk("map hdr %p/%d/%d\n", hdr->dxferp, hdr->dxfer_len, dprintk("map hdr %llx/%u %llx/%u\n", (unsigned long long) hdr->dout_xferp,
hdr->iovec_count); hdr->dout_xfer_len, (unsigned long long) hdr->din_xferp,
hdr->din_xfer_len);
ret = bsg_validate_sghdr(q, hdr, &rw); ret = bsg_validate_sgv4_hdr(q, hdr, &rw);
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -293,44 +318,29 @@ bsg_map_hdr(struct bsg_device *bd, int rw, struct sg_io_hdr *hdr) ...@@ -293,44 +318,29 @@ bsg_map_hdr(struct bsg_device *bd, int rw, struct sg_io_hdr *hdr)
* map scatter-gather elements seperately and string them to request * map scatter-gather elements seperately and string them to request
*/ */
rq = blk_get_request(q, rw, GFP_KERNEL); rq = blk_get_request(q, rw, GFP_KERNEL);
ret = blk_fill_sghdr_rq(q, rq, hdr, test_bit(BSG_F_WRITE_PERM, ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, test_bit(BSG_F_WRITE_PERM,
&bd->flags)); &bd->flags));
if (ret) { if (ret) {
blk_put_request(rq); blk_put_request(rq);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
if (!hdr->iovec_count) { if (hdr->dout_xfer_len) {
ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len); dxfer_len = hdr->dout_xfer_len;
if (ret) dxferp = (void*)(unsigned long)hdr->dout_xferp;
goto out; } else if (hdr->din_xfer_len) {
} dxfer_len = hdr->din_xfer_len;
dxferp = (void*)(unsigned long)hdr->din_xferp;
u_iov = hdr->dxferp; } else
for (ret = 0, i = 0; i < hdr->iovec_count; i++, u_iov++) { dxfer_len = 0;
if (copy_from_user(&iov, u_iov, sizeof(iov))) {
ret = -EFAULT; if (dxfer_len) {
break; ret = blk_rq_map_user(q, rq, dxferp, dxfer_len);
} if (ret) {
dprintk("failed map at %d\n", ret);
if (!iov.iov_len || !iov.iov_base) { blk_put_request(rq);
ret = -EINVAL; rq = ERR_PTR(ret);
break;
} }
ret = blk_rq_map_user(q, rq, iov.iov_base, iov.iov_len);
if (ret)
break;
}
/*
* bugger, cleanup
*/
if (ret) {
out:
dprintk("failed map at %d: %d\n", i, ret);
blk_unmap_sghdr_rq(rq, hdr);
rq = ERR_PTR(ret);
} }
return rq; return rq;
...@@ -346,7 +356,7 @@ static void bsg_rq_end_io(struct request *rq, int uptodate) ...@@ -346,7 +356,7 @@ static void bsg_rq_end_io(struct request *rq, int uptodate)
struct bsg_device *bd = bc->bd; struct bsg_device *bd = bc->bd;
unsigned long flags; unsigned long flags;
dprintk("%s: finished rq %p bc %p, bio %p offset %d stat %d\n", dprintk("%s: finished rq %p bc %p, bio %p offset %Zd stat %d\n",
bd->name, rq, bc, bc->bio, bc - bd->cmd_map, uptodate); bd->name, rq, bc, bc->bio, bc - bd->cmd_map, uptodate);
bc->hdr.duration = jiffies_to_msecs(jiffies - bc->hdr.duration); bc->hdr.duration = jiffies_to_msecs(jiffies - bc->hdr.duration);
...@@ -434,6 +444,42 @@ bsg_get_done_cmd_nosignals(struct bsg_device *bd) ...@@ -434,6 +444,42 @@ bsg_get_done_cmd_nosignals(struct bsg_device *bd)
return __bsg_get_done_cmd(bd, TASK_UNINTERRUPTIBLE); return __bsg_get_done_cmd(bd, TASK_UNINTERRUPTIBLE);
} }
static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
struct bio *bio)
{
int ret = 0;
dprintk("rq %p bio %p %u\n", rq, bio, rq->errors);
/*
* fill in all the output members
*/
hdr->device_status = status_byte(rq->errors);
hdr->transport_status = host_byte(rq->errors);
hdr->driver_status = driver_byte(rq->errors);
hdr->info = 0;
if (hdr->device_status || hdr->transport_status || hdr->driver_status)
hdr->info |= SG_INFO_CHECK;
hdr->din_resid = rq->data_len;
hdr->response_len = 0;
if (rq->sense_len && hdr->response) {
int len = min((unsigned int) hdr->max_response_len,
rq->sense_len);
ret = copy_to_user((void*)(unsigned long)hdr->response,
rq->sense, len);
if (!ret)
hdr->response_len = len;
else
ret = -EFAULT;
}
blk_rq_unmap_user(bio);
blk_put_request(rq);
return ret;
}
static int bsg_complete_all_commands(struct bsg_device *bd) static int bsg_complete_all_commands(struct bsg_device *bd)
{ {
struct bsg_command *bc; struct bsg_command *bc;
...@@ -476,7 +522,7 @@ static int bsg_complete_all_commands(struct bsg_device *bd) ...@@ -476,7 +522,7 @@ static int bsg_complete_all_commands(struct bsg_device *bd)
break; break;
} }
tret = blk_complete_sghdr_rq(bc->rq, &bc->hdr, bc->bio); tret = blk_complete_sgv4_hdr_rq(bc->rq, &bc->hdr, bc->bio);
if (!ret) if (!ret)
ret = tret; ret = tret;
...@@ -495,11 +541,11 @@ __bsg_read(char __user *buf, size_t count, bsg_command_callback get_bc, ...@@ -495,11 +541,11 @@ __bsg_read(char __user *buf, size_t count, bsg_command_callback get_bc,
struct bsg_command *bc; struct bsg_command *bc;
int nr_commands, ret; int nr_commands, ret;
if (count % sizeof(struct sg_io_hdr)) if (count % sizeof(struct sg_io_v4))
return -EINVAL; return -EINVAL;
ret = 0; ret = 0;
nr_commands = count / sizeof(struct sg_io_hdr); nr_commands = count / sizeof(struct sg_io_v4);
while (nr_commands) { while (nr_commands) {
bc = get_bc(bd, iov); bc = get_bc(bd, iov);
if (IS_ERR(bc)) { if (IS_ERR(bc)) {
...@@ -512,7 +558,7 @@ __bsg_read(char __user *buf, size_t count, bsg_command_callback get_bc, ...@@ -512,7 +558,7 @@ __bsg_read(char __user *buf, size_t count, bsg_command_callback get_bc,
* after completing the request. so do that here, * after completing the request. so do that here,
* bsg_complete_work() cannot do that for us * bsg_complete_work() cannot do that for us
*/ */
ret = blk_complete_sghdr_rq(bc->rq, &bc->hdr, bc->bio); ret = blk_complete_sgv4_hdr_rq(bc->rq, &bc->hdr, bc->bio);
if (copy_to_user(buf, (char *) &bc->hdr, sizeof(bc->hdr))) if (copy_to_user(buf, (char *) &bc->hdr, sizeof(bc->hdr)))
ret = -EFAULT; ret = -EFAULT;
...@@ -522,8 +568,8 @@ __bsg_read(char __user *buf, size_t count, bsg_command_callback get_bc, ...@@ -522,8 +568,8 @@ __bsg_read(char __user *buf, size_t count, bsg_command_callback get_bc,
if (ret) if (ret)
break; break;
buf += sizeof(struct sg_io_hdr); buf += sizeof(struct sg_io_v4);
*bytes_read += sizeof(struct sg_io_hdr); *bytes_read += sizeof(struct sg_io_v4);
nr_commands--; nr_commands--;
} }
...@@ -582,16 +628,15 @@ static ssize_t __bsg_write(struct bsg_device *bd, const char __user *buf, ...@@ -582,16 +628,15 @@ static ssize_t __bsg_write(struct bsg_device *bd, const char __user *buf,
struct request *rq; struct request *rq;
int ret, nr_commands; int ret, nr_commands;
if (count % sizeof(struct sg_io_hdr)) if (count % sizeof(struct sg_io_v4))
return -EINVAL; return -EINVAL;
nr_commands = count / sizeof(struct sg_io_hdr); nr_commands = count / sizeof(struct sg_io_v4);
rq = NULL; rq = NULL;
bc = NULL; bc = NULL;
ret = 0; ret = 0;
while (nr_commands) { while (nr_commands) {
request_queue_t *q = bd->queue; request_queue_t *q = bd->queue;
int rw = READ;
bc = bsg_get_command(bd); bc = bsg_get_command(bd);
if (!bc) if (!bc)
...@@ -602,7 +647,7 @@ static ssize_t __bsg_write(struct bsg_device *bd, const char __user *buf, ...@@ -602,7 +647,7 @@ static ssize_t __bsg_write(struct bsg_device *bd, const char __user *buf,
break; break;
} }
bc->uhdr = (struct sg_io_hdr __user *) buf; bc->uhdr = (struct sg_io_v4 __user *) buf;
if (copy_from_user(&bc->hdr, buf, sizeof(bc->hdr))) { if (copy_from_user(&bc->hdr, buf, sizeof(bc->hdr))) {
ret = -EFAULT; ret = -EFAULT;
break; break;
...@@ -611,7 +656,7 @@ static ssize_t __bsg_write(struct bsg_device *bd, const char __user *buf, ...@@ -611,7 +656,7 @@ static ssize_t __bsg_write(struct bsg_device *bd, const char __user *buf,
/* /*
* get a request, fill in the blanks, and add to request queue * get a request, fill in the blanks, and add to request queue
*/ */
rq = bsg_map_hdr(bd, rw, &bc->hdr); rq = bsg_map_hdr(bd, &bc->hdr);
if (IS_ERR(rq)) { if (IS_ERR(rq)) {
ret = PTR_ERR(rq); ret = PTR_ERR(rq);
rq = NULL; rq = NULL;
...@@ -622,12 +667,10 @@ static ssize_t __bsg_write(struct bsg_device *bd, const char __user *buf, ...@@ -622,12 +667,10 @@ static ssize_t __bsg_write(struct bsg_device *bd, const char __user *buf,
bc = NULL; bc = NULL;
rq = NULL; rq = NULL;
nr_commands--; nr_commands--;
buf += sizeof(struct sg_io_hdr); buf += sizeof(struct sg_io_v4);
*bytes_read += sizeof(struct sg_io_hdr); *bytes_read += sizeof(struct sg_io_v4);
} }
if (rq)
blk_unmap_sghdr_rq(rq, &bc->hdr);
if (bc) if (bc)
bsg_free_command(bc); bsg_free_command(bc);
...@@ -898,11 +941,12 @@ bsg_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -898,11 +941,12 @@ bsg_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case SG_GET_RESERVED_SIZE: case SG_GET_RESERVED_SIZE:
case SG_SET_RESERVED_SIZE: case SG_SET_RESERVED_SIZE:
case SG_EMULATED_HOST: case SG_EMULATED_HOST:
case SG_IO:
case SCSI_IOCTL_SEND_COMMAND: { case SCSI_IOCTL_SEND_COMMAND: {
void __user *uarg = (void __user *) arg; void __user *uarg = (void __user *) arg;
return scsi_cmd_ioctl(file, bd->disk, cmd, uarg); return scsi_cmd_ioctl(file, bd->disk, cmd, uarg);
} }
case SG_IO:
return -EINVAL;
/* /*
* block device ioctls * block device ioctls
*/ */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册