Skip to content

Commit

Permalink
added support for SG_IO ioctl
Browse files Browse the repository at this point in the history
async scsi commands (using read and write) do not work when you have
multiple processes, since one process's command response can get read
by another response.  The ioctl forces a blocking read after the
write.
  • Loading branch information
joc02012 committed Feb 9, 2013
1 parent f680ba2 commit 4856534
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 244 deletions.
130 changes: 81 additions & 49 deletions osd-initiator/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,84 +24,101 @@
#include "osd-util/osd-util.h"
#include <linux/bsg.h>
#include <scsi/sg.h>
#include <sys/ioctl.h>
#include "command.h"
#include "device.h"

int osd_submit_command(int fd, struct osd_command *command)
static void
osd_submit_command_setup(struct osd_command *command, struct sg_io_v4 *sg)
{
int ret;
struct sg_io_v4 sg;
memset(sg, 0, sizeof(*sg));

memset(&sg, 0, sizeof(sg));
sg.guard = 'Q';
sg.request_len = command->cdb_len;
sg.request = (uint64_t) (uintptr_t) command->cdb;
sg.max_response_len = sizeof(command->sense);
sg.response = (uint64_t) (uintptr_t) command->sense;
sg->guard = 'Q';
sg->request_len = command->cdb_len;
sg->request = (uint64_t) (uintptr_t) command->cdb;
sg->max_response_len = sizeof(command->sense);
sg->response = (uint64_t) (uintptr_t) command->sense;

if (command->outlen) {
#ifdef KERNEL_SUPPORTS_BSG_IOVEC
sg.dout_xfer_len = command->outlen;
sg.dout_xferp = (uint64_t) (uintptr_t) command->outdata;
sg.dout_iovec_count = command->iov_outlen;
sg->dout_xfer_len = command->outlen;
sg->dout_xferp = (uint64_t) (uintptr_t) command->outdata;
sg->dout_iovec_count = command->iov_outlen;
#else
// The kernel doesn't support BSG iovecs mainly because
// of a problem going from 32-bit user iovecs to a 64-bit kernel
// So, just copy the iovecs into a new buffer and use that
sg_iovec_t *iov = (sg_iovec_t *)(uintptr_t)command->outdata;
if (command->iov_outlen == 0) {
sg.dout_xfer_len = command->outlen;
sg.dout_xferp = (uint64_t) (uintptr_t) command->outdata;
sg->dout_xfer_len = command->outlen;
sg->dout_xferp = (uint64_t) (uintptr_t) command->outdata;
} else if (command->iov_outlen == 1) {
sg.dout_xfer_len = iov->iov_len;
sg.dout_xferp = (uint64_t) (uintptr_t) iov->iov_base;
sg->dout_xfer_len = iov->iov_len;
sg->dout_xferp = (uint64_t) (uintptr_t) iov->iov_base;
} else {
int i;
uint8_t *buff = Malloc(command->outlen);
sg.dout_xferp = (uint64_t) (uintptr_t) buff;
sg->dout_xferp = (uint64_t) (uintptr_t) buff;
for (i=0; i<command->iov_outlen; i++) {
memcpy(buff, iov[i].iov_base, iov[i].iov_len);
buff += iov[i].iov_len;
}
sg.dout_xfer_len = command->outlen;
sg->dout_xfer_len = command->outlen;
}
sg.dout_iovec_count = 0;
sg->dout_iovec_count = 0;
#endif
}
if (command->inlen_alloc) {
#ifdef KERNEL_SUPPORTS_BSG_IOVEC
sg.din_xfer_len = command->inlen_alloc;
sg.din_xferp = (uint64_t) (uintptr_t) command->indata;
sg.din_iovec_count = command->iov_inlen;
sg->din_xfer_len = command->inlen_alloc;
sg->din_xferp = (uint64_t) (uintptr_t) command->indata;
sg->din_iovec_count = command->iov_inlen;
#else
if (command->iov_inlen == 0) {
sg.din_xfer_len = command->inlen_alloc;
sg.din_xferp = (uint64_t) (uintptr_t) command->indata;
sg.din_iovec_count = command->iov_inlen;
sg->din_xfer_len = command->inlen_alloc;
sg->din_xferp = (uint64_t) (uintptr_t) command->indata;
sg->din_iovec_count = command->iov_inlen;
} else if (command->iov_inlen == 1) {
sg_iovec_t *iov = (sg_iovec_t *)command->indata;
sg.din_xfer_len = iov->iov_len;
sg.din_xferp = (uint64_t) (uintptr_t) iov->iov_base;
sg->din_xfer_len = iov->iov_len;
sg->din_xferp = (uint64_t) (uintptr_t) iov->iov_base;
} else {
sg.din_xfer_len = command->inlen_alloc;
sg.din_xferp = (uint64_t) (uintptr_t) (uint8_t*) Malloc(command->inlen_alloc);
sg->din_xfer_len = command->inlen_alloc;
sg->din_xferp = (uint64_t) (uintptr_t) (uint8_t*) Malloc(command->inlen_alloc);
}
sg.din_iovec_count = 0;
sg->din_iovec_count = 0;
#endif
}

/*
* Allow 30 sec for entire command. Some can be
* slow, especially with debugging messages on.
*/
sg.timeout = 30000;
sg.usr_ptr = (uint64_t) (uintptr_t) command;
ret = write(fd, &sg, sizeof(sg));
sg->timeout = 30000;
sg->usr_ptr = (uint64_t) (uintptr_t) command;
}

static void
osd_submit_command_cleanup(struct osd_command *command, struct sg_io_v4 *sg)
{
#ifndef KERNEL_SUPPORTS_BSG_IOVEC
if (command->outlen && command->iov_outlen > 1) {
free((void *) (uintptr_t) sg.dout_xferp);
free((void *) (uintptr_t) sg->dout_xferp);
}
#endif
}

int osd_submit_command(int fd, struct osd_command *command)
{
struct sg_io_v4 sg;
int ret;

osd_submit_command_setup(command, &sg);

ret = write(fd, &sg, sizeof(sg));

osd_submit_command_cleanup(command, &sg);

if (ret < 0) {
osd_error_errno("%s: write", __func__);
return -errno;
Expand All @@ -114,6 +131,8 @@ int osd_submit_command(int fd, struct osd_command *command)
return 0;
}

static void copy_sg_to_command(struct sg_io_v4 *sg, struct osd_command *command);

int osd_wait_response(int fd, struct osd_command **out_command)
{
struct sg_io_v4 sg;
Expand All @@ -132,28 +151,32 @@ int osd_wait_response(int fd, struct osd_command **out_command)
}

command = (void *)(uintptr_t) sg.usr_ptr;
copy_sg_to_command(&sg, command);

*out_command = command;

return 0;}

static void copy_sg_to_command(struct sg_io_v4 *sg, struct osd_command *command)
{
if (command->inlen_alloc)
command->inlen = command->inlen_alloc - sg.din_resid;
command->status = sg.device_status;
command->sense_len = sg.response_len;
command->inlen = command->inlen_alloc - sg->din_resid;
command->status = sg->device_status;
command->sense_len = sg->response_len;

#ifndef KERNEL_SUPPORTS_BSG_IOVEC
// copy from buffer to iovecs
if (command->inlen_alloc && command->iov_inlen > 1) {
sg_iovec_t *iov = (sg_iovec_t *) command->indata;
uint8_t *buff = (uint8_t *) (uintptr_t) sg.din_xferp;
uint8_t *buff = (uint8_t *) (uintptr_t) sg->din_xferp;
int i;
for (i=0; i<command->iov_inlen; i++) {
memcpy(iov[i].iov_base, buff, iov[i].iov_len);
buff += iov[i].iov_len;
}
free((void *) (uintptr_t) sg.din_xferp);
free((void *) (uintptr_t) sg->din_xferp);
}
#endif

*out_command = command;

return 0;
}

/*
Expand All @@ -178,17 +201,26 @@ int osd_wait_this_response(int fd, struct osd_command *command)
int osd_submit_and_wait(int fd, struct osd_command *command)
{
int ret;
struct sg_io_v4 sg;

ret = osd_submit_command(fd, command);
if (ret) {
osd_error("%s: submit failed", __func__);
return ret;
osd_submit_command_setup(command, &sg);
sg.flags = BSG_FLAG_Q_AT_TAIL;

ret = ioctl(fd, SG_IO, &sg);

osd_submit_command_cleanup(command, &sg);

if ((struct osd_command *)(uintptr_t)sg.usr_ptr != command) {
osd_error("%s: wrong command returned", __func__);
ret = -EIO;
}

ret = osd_wait_this_response(fd, command);
copy_sg_to_command(&sg, command);

if (ret) {
osd_error("%s: wait_response failed", __func__);
osd_error("%s: submit failed", __func__);
return ret;
}

return 0;
}
Loading

0 comments on commit 4856534

Please sign in to comment.