#define MAX_SB 64 // sense block maximum return size
struct sgio_cmd {
- unsigned char cdb[16]; // increase to support 16 byte commands
+ unsigned char cdb[16]; // enhanced from 10 to support 16 byte commands
unsigned char sb[MAX_SB]; // add sense block to commands
int nr;
};
int *fd_flags;
void *sgbuf;
unsigned int bs;
- long long max_lba;
int type_checked;
};
return 0;
}
+static int sg_fd_read(int fd, void *data, size_t size)
+{
+ int err = 0;
+
+ while (size) {
+ ssize_t ret;
+
+ ret = read(fd, data, size);
+ if (ret < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ err = errno;
+ break;
+ } else if (!ret)
+ break;
+ else {
+ data += ret;
+ size -= ret;
+ }
+ }
+
+ if (err)
+ return err;
+ if (size)
+ return EAGAIN;
+
+ return 0;
+}
+
static int fio_sgio_getevents(struct thread_data *td, unsigned int min,
unsigned int max,
const struct timespec fio_unused *t)
{
- struct sgio_data *sd = td->io_ops->data;
+ struct sgio_data *sd = td->io_ops_data;
int left = max, eventNum, ret, r = 0;
void *buf = sd->sgbuf;
unsigned int i, events;
events = 0;
for_each_file(td, f, i) {
for (eventNum = 0; eventNum < left; eventNum++) {
- ret = read(f->fd, p, sizeof(struct sg_io_hdr));
+ ret = sg_fd_read(f->fd, p, sizeof(struct sg_io_hdr));
dprint(FD_IO, "sgio_getevents: ret: %d\n", ret);
- if (ret < 0) {
- /*
- * not sure if EINTR is needed,
- * but seems like it should be.
- */
- if (errno == EAGAIN || errno == EINTR)
- continue;
- r = -errno;
- td_verror(td, errno, "read");
+ if (ret) {
+ r = -ret;
+ td_verror(td, r, "sg_read");
break;
- } else if (ret) {
- p += ret;
- events += 1; /* ret / sizeof(struct sg_io_hdr); */
- dprint(FD_IO, "sgio_getevents: events: %d\n", events);
}
+ p += sizeof(struct sg_io_hdr);
+ events++;
+ dprint(FD_IO, "sgio_getevents: events: %d\n", events);
}
}
- if (r < 0)
+ if (r < 0 && !events)
break;
if (!events) {
usleep(1000);
static int fio_sgio_ioctl_doio(struct thread_data *td,
struct fio_file *f, struct io_u *io_u)
{
- struct sgio_data *sd = td->io_ops->data;
+ struct sgio_data *sd = td->io_ops_data;
struct sg_io_hdr *hdr = &io_u->hdr;
int ret;
static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u)
{
struct sg_io_hdr *hdr = &io_u->hdr;
- struct sgio_data *sd = td->io_ops->data;
+ struct sgio_data *sd = td->io_ops_data;
long long nr_blocks, lba;
if (io_u->xfer_buflen & (sd->bs - 1)) {
* blocks on medium.
*/
if (hdr->dxfer_direction != SG_DXFER_NONE) {
-
if (lba < MAX_10B_LBA) {
hdr->cmdp[2] = (unsigned char) ((lba >> 24) & 0xff);
hdr->cmdp[3] = (unsigned char) ((lba >> 16) & 0xff);
static struct io_u *fio_sgio_event(struct thread_data *td, int event)
{
- struct sgio_data *sd = td->io_ops->data;
+ struct sgio_data *sd = td->io_ops_data;
return sd->events[event];
}
}
*bs = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
- *max_lba = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]) & 0x00000000FFFFFFFFULL; // for some reason max_lba is being sign extended even though unsigned.
-
+ *max_lba = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]) & MAX_10B_LBA; // for some reason max_lba is being sign extended even though unsigned.
/*
- * If max lba is 0xFFFFFFFF, then need to retry with
- * 16 byteread capacity
+ * If max lba masked by MAX_10B_LBA equals MAX_10B_LBA,
+ * then need to retry with 16 byte Read Capacity command.
*/
if (*max_lba == MAX_10B_LBA) {
hdr.cmd_len = 16;
- hdr.cmdp[0] = 0x9e; // Read Capacity(16)
- hdr.cmdp[1] = 0x10; // service action
+ hdr.cmdp[0] = 0x9e; // service action
+ hdr.cmdp[1] = 0x10; // Read Capacity(16)
hdr.cmdp[10] = (unsigned char) ((sizeof(buf) >> 24) & 0xff);
hdr.cmdp[11] = (unsigned char) ((sizeof(buf) >> 16) & 0xff);
hdr.cmdp[12] = (unsigned char) ((sizeof(buf) >> 8) & 0xff);
static void fio_sgio_cleanup(struct thread_data *td)
{
- struct sgio_data *sd = td->io_ops->data;
+ struct sgio_data *sd = td->io_ops_data;
if (sd) {
free(sd->events);
sd->sgbuf = malloc(sizeof(struct sg_io_hdr) * td->o.iodepth);
memset(sd->sgbuf, 0, sizeof(struct sg_io_hdr) * td->o.iodepth);
sd->type_checked = 0;
- td->io_ops->data = sd;
+ td->io_ops_data = sd;
/*
* we want to do it, regardless of whether odirect is set or not
static int fio_sgio_type_check(struct thread_data *td, struct fio_file *f)
{
- struct sgio_data *sd = td->io_ops->data;
+ struct sgio_data *sd = td->io_ops_data;
unsigned int bs = 0;
unsigned long long max_lba = 0;
-
if (f->filetype == FIO_TYPE_BD) {
if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
td_verror(td, errno, "ioctl");
}
} else {
td_verror(td, EINVAL, "wrong file type");
- log_err("ioengine sg only works on block devices\n");
+ log_err("ioengine sg only works on block or character devices\n");
return 1;
}
sd->bs = bs;
// Determine size of commands needed based on max_lba
- sd->max_lba = max_lba;
- if (max_lba > MAX_10B_LBA) {
- dprint(FD_IO, "sgio_type_check: using 16 byte operations: max_lba = 0x%016llx\n", max_lba);
+ if (max_lba >= MAX_10B_LBA) {
+ dprint(FD_IO, "sgio_type_check: using 16 byte read/write "
+ "commands for lba above 0x%016llx/0x%016llx\n",
+ MAX_10B_LBA, max_lba);
}
-
if (f->filetype == FIO_TYPE_BD) {
td->io_ops->getevents = NULL;
td->io_ops->event = NULL;
static int fio_sgio_open(struct thread_data *td, struct fio_file *f)
{
- struct sgio_data *sd = td->io_ops->data;
+ struct sgio_data *sd = td->io_ops_data;
int ret;
ret = generic_open_file(td, f);
char *msg, msgchunk[MAXMSGCHUNK], *ret = NULL;
int i;
- msg = calloc(MAXERRDETAIL, 1);
+ msg = calloc(1, MAXERRDETAIL);
/*
* can't seem to find sg_err.h, so I'll just echo the define values
case 0x0d:
strlcat(msg, "SG_ERR_DID_REQUEUE", MAXERRDETAIL);
break;
+ case 0x0e:
+ strlcat(msg, "SG_ERR_DID_TRANSPORT_DISRUPTED", MAXERRDETAIL);
+ break;
+ case 0x0f:
+ strlcat(msg, "SG_ERR_DID_TRANSPORT_FAILFAST", MAXERRDETAIL);
+ break;
+ case 0x10:
+ strlcat(msg, "SG_ERR_DID_TARGET_FAILURE", MAXERRDETAIL);
+ break;
+ case 0x11:
+ strlcat(msg, "SG_ERR_DID_NEXUS_FAILURE", MAXERRDETAIL);
+ break;
+ case 0x12:
+ strlcat(msg, "SG_ERR_DID_ALLOC_FAILURE", MAXERRDETAIL);
+ break;
+ case 0x13:
+ strlcat(msg, "SG_ERR_DID_MEDIUM_ERROR", MAXERRDETAIL);
+ break;
default:
strlcat(msg, "Unknown", MAXERRDETAIL);
break;
if (fio_file_size_known(f))
return 0;
+ if (f->filetype != FIO_TYPE_BD && f->filetype != FIO_TYPE_CHAR) {
+ td_verror(td, EINVAL, "wrong file type");
+ log_err("ioengine sg only works on block or character devices\n");
+ return 1;
+ }
+
ret = fio_sgio_read_capacity(td, &bs, &max_lba);
if (ret ) {
td_verror(td, td->error, "fio_sgio_read_capacity");
.cleanup = fio_sgio_cleanup,
.open_file = fio_sgio_open,
.close_file = generic_close_file,
- .get_file_size = fio_sgio_get_file_size, // generic_get_file_size
+ .get_file_size = fio_sgio_get_file_size,
.flags = FIO_SYNCIO | FIO_RAWIO,
};