summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2014-12-18 08:38:07 +0000
committermav <mav@FreeBSD.org>2014-12-18 08:38:07 +0000
commit4ff47ae9abedf70df85d191c50e4130adbdea839 (patch)
tree493e69933075582f0f9d4d1a850896cee12710af
parent251a95deec1d0bdb97ae02542b701f42eb54476a (diff)
downloadFreeBSD-src-4ff47ae9abedf70df85d191c50e4130adbdea839.zip
FreeBSD-src-4ff47ae9abedf70df85d191c50e4130adbdea839.tar.gz
MFC r275474: Add GET LBA STATUS command support to CTL.
It is implemented for LUNs backed by ZVOLs in "dev" mode and files. GEOM has no such API, so for LUNs backed by raw devices all LBAs will be reported as mapped/unknown. Sponsored by: iXsystems, Inc.
-rw-r--r--sys/cam/ctl/ctl.c102
-rw-r--r--sys/cam/ctl/ctl.h1
-rw-r--r--sys/cam/ctl/ctl_backend_block.c192
-rw-r--r--sys/cam/ctl/ctl_backend_ramdisk.c31
-rw-r--r--sys/cam/ctl/ctl_cmd_table.c15
-rw-r--r--sys/cam/ctl/ctl_private.h1
-rw-r--r--sys/cam/scsi/scsi_all.h26
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c13
8 files changed, 366 insertions, 15 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index 4cbc14f..126c95b85 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -5174,6 +5174,40 @@ ctl_config_write_done(union ctl_io *io)
free(buf, M_CTL);
}
+void
+ctl_config_read_done(union ctl_io *io)
+{
+ uint8_t *buf;
+
+ /*
+ * If there is some error -- we are done, skip data transfer.
+ */
+ if ((io->io_hdr.flags & CTL_FLAG_ABORT) != 0 ||
+ ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE &&
+ (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) {
+ if (io->io_hdr.flags & CTL_FLAG_ALLOCATED)
+ buf = io->scsiio.kern_data_ptr;
+ else
+ buf = NULL;
+ ctl_done(io);
+ if (buf)
+ free(buf, M_CTL);
+ return;
+ }
+
+ /*
+ * If the IO_CONT flag is set, we need to call the supplied
+ * function to continue processing the I/O, instead of completing
+ * the I/O just yet.
+ */
+ if (io->io_hdr.flags & CTL_FLAG_IO_CONT) {
+ io->scsiio.io_cont(io);
+ return;
+ }
+
+ ctl_datamove(io);
+}
+
/*
* SCSI release command.
*/
@@ -7175,6 +7209,66 @@ ctl_read_capacity_16(struct ctl_scsiio *ctsio)
}
int
+ctl_get_lba_status(struct ctl_scsiio *ctsio)
+{
+ struct scsi_get_lba_status *cdb;
+ struct scsi_get_lba_status_data *data;
+ struct ctl_lun *lun;
+ struct ctl_lba_len_flags *lbalen;
+ uint64_t lba;
+ uint32_t alloc_len, total_len;
+ int retval;
+
+ CTL_DEBUG_PRINT(("ctl_get_lba_status\n"));
+
+ lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+ cdb = (struct scsi_get_lba_status *)ctsio->cdb;
+ lba = scsi_8btou64(cdb->addr);
+ alloc_len = scsi_4btoul(cdb->alloc_len);
+
+ if (lba > lun->be_lun->maxlba) {
+ ctl_set_lba_out_of_range(ctsio);
+ ctl_done((union ctl_io *)ctsio);
+ return (CTL_RETVAL_COMPLETE);
+ }
+
+ total_len = sizeof(*data) + sizeof(data->descr[0]);
+ ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
+ data = (struct scsi_get_lba_status_data *)ctsio->kern_data_ptr;
+
+ if (total_len < alloc_len) {
+ ctsio->residual = alloc_len - total_len;
+ ctsio->kern_data_len = total_len;
+ ctsio->kern_total_len = total_len;
+ } else {
+ ctsio->residual = 0;
+ ctsio->kern_data_len = alloc_len;
+ ctsio->kern_total_len = alloc_len;
+ }
+ ctsio->kern_data_resid = 0;
+ ctsio->kern_rel_offset = 0;
+ ctsio->kern_sg_entries = 0;
+
+ /* Fill dummy data in case backend can't tell anything. */
+ scsi_ulto4b(4 + sizeof(data->descr[0]), data->length);
+ scsi_u64to8b(lba, data->descr[0].addr);
+ scsi_ulto4b(MIN(UINT32_MAX, lun->be_lun->maxlba + 1 - lba),
+ data->descr[0].length);
+ data->descr[0].status = 0; /* Mapped or unknown. */
+
+ ctl_set_success(ctsio);
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
+ ctsio->be_move_done = ctl_config_move_done;
+
+ lbalen = (struct ctl_lba_len_flags *)&ctsio->io_hdr.ctl_private[CTL_PRIV_LBA_LEN];
+ lbalen->lba = lba;
+ lbalen->len = total_len;
+ lbalen->flags = 0;
+ retval = lun->backend->config_read((union ctl_io *)ctsio);
+ return (CTL_RETVAL_COMPLETE);
+}
+
+int
ctl_read_defect(struct ctl_scsiio *ctsio)
{
struct scsi_read_defect_data_10 *ccb10;
@@ -10644,6 +10738,14 @@ ctl_get_lba_len(union ctl_io *io, uint64_t *lba, uint64_t *len)
*len = UINT64_MAX;
break;
}
+ case SERVICE_ACTION_IN: { /* GET LBA STATUS */
+ struct scsi_get_lba_status *cdb;
+
+ cdb = (struct scsi_get_lba_status *)io->scsiio.cdb;
+ *lba = scsi_8btou64(cdb->addr);
+ *len = UINT32_MAX;
+ break;
+ }
default:
return (1);
break; /* NOTREACHED */
diff --git a/sys/cam/ctl/ctl.h b/sys/cam/ctl/ctl.h
index 9856dcc..1ec0586 100644
--- a/sys/cam/ctl/ctl.h
+++ b/sys/cam/ctl/ctl.h
@@ -186,6 +186,7 @@ int ctl_config_move_done(union ctl_io *io);
void ctl_datamove(union ctl_io *io);
void ctl_done(union ctl_io *io);
void ctl_data_submit_done(union ctl_io *io);
+void ctl_config_read_done(union ctl_io *io);
void ctl_config_write_done(union ctl_io *io);
void ctl_portDB_changed(int portnum);
void ctl_init_isc_msg(void);
diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c
index 6f6b51a..3e33084 100644
--- a/sys/cam/ctl/ctl_backend_block.c
+++ b/sys/cam/ctl/ctl_backend_block.c
@@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
#include <sys/disk.h>
#include <sys/fcntl.h>
#include <sys/filedesc.h>
+#include <sys/filio.h>
#include <sys/proc.h>
#include <sys/pcpu.h>
#include <sys/module.h>
@@ -165,6 +166,7 @@ struct ctl_be_block_lun {
cbb_dispatch_t dispatch;
cbb_dispatch_t lun_flush;
cbb_dispatch_t unmap;
+ cbb_dispatch_t get_lba_status;
cbb_getattr_t getattr;
uma_zone_t lun_zone;
uint64_t size_blocks;
@@ -182,6 +184,7 @@ struct ctl_be_block_lun {
struct task io_task;
int num_threads;
STAILQ_HEAD(, ctl_io_hdr) input_queue;
+ STAILQ_HEAD(, ctl_io_hdr) config_read_queue;
STAILQ_HEAD(, ctl_io_hdr) config_write_queue;
STAILQ_HEAD(, ctl_io_hdr) datamove_queue;
struct mtx_padalign io_lock;
@@ -240,6 +243,8 @@ static void ctl_be_block_flush_file(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
static void ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
+static void ctl_be_block_gls_file(struct ctl_be_block_lun *be_lun,
+ struct ctl_be_block_io *beio);
static void ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
static void ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun,
@@ -248,6 +253,8 @@ static void ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
static uint64_t ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun,
const char *attrname);
+static void ctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun,
+ union ctl_io *io);
static void ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun,
union ctl_io *io);
static void ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun,
@@ -756,6 +763,46 @@ ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun,
}
static void
+ctl_be_block_gls_file(struct ctl_be_block_lun *be_lun,
+ struct ctl_be_block_io *beio)
+{
+ union ctl_io *io = beio->io;
+ struct ctl_lba_len_flags *lbalen = ARGS(io);
+ struct scsi_get_lba_status_data *data;
+ off_t roff, off;
+ int error, status;
+
+ DPRINTF("entered\n");
+
+ off = roff = ((off_t)lbalen->lba) << be_lun->blocksize_shift;
+ vn_lock(be_lun->vn, LK_SHARED | LK_RETRY);
+ error = VOP_IOCTL(be_lun->vn, FIOSEEKHOLE, &off,
+ 0, curthread->td_ucred, curthread);
+ if (error == 0 && off > roff)
+ status = 0; /* mapped up to off */
+ else {
+ error = VOP_IOCTL(be_lun->vn, FIOSEEKDATA, &off,
+ 0, curthread->td_ucred, curthread);
+ if (error == 0 && off > roff)
+ status = 1; /* deallocated up to off */
+ else {
+ status = 0; /* unknown up to the end */
+ off = be_lun->size_bytes;
+ }
+ }
+ VOP_UNLOCK(be_lun->vn, 0);
+
+ off >>= be_lun->blocksize_shift;
+ data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr;
+ scsi_u64to8b(lbalen->lba, data->descr[0].addr);
+ scsi_ulto4b(MIN(UINT32_MAX, off - lbalen->lba),
+ data->descr[0].length);
+ data->descr[0].status = status;
+
+ ctl_complete_beio(beio);
+}
+
+static void
ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio)
{
@@ -848,6 +895,45 @@ ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun,
}
static void
+ctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun,
+ struct ctl_be_block_io *beio)
+{
+ struct ctl_be_block_devdata *dev_data = &be_lun->backend.dev;
+ union ctl_io *io = beio->io;
+ struct ctl_lba_len_flags *lbalen = ARGS(io);
+ struct scsi_get_lba_status_data *data;
+ off_t roff, off;
+ int error, status;
+
+ DPRINTF("entered\n");
+
+ off = roff = ((off_t)lbalen->lba) << be_lun->blocksize_shift;
+ error = (*dev_data->csw->d_ioctl)(dev_data->cdev, FIOSEEKHOLE,
+ (caddr_t)&off, FREAD, curthread);
+ if (error == 0 && off > roff)
+ status = 0; /* mapped up to off */
+ else {
+ error = (*dev_data->csw->d_ioctl)(dev_data->cdev, FIOSEEKDATA,
+ (caddr_t)&off, FREAD, curthread);
+ if (error == 0 && off > roff)
+ status = 1; /* deallocated up to off */
+ else {
+ status = 0; /* unknown up to the end */
+ off = be_lun->size_bytes;
+ }
+ }
+
+ off >>= be_lun->blocksize_shift;
+ data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr;
+ scsi_u64to8b(lbalen->lba, data->descr[0].addr);
+ scsi_ulto4b(MIN(UINT32_MAX, off - lbalen->lba),
+ data->descr[0].length);
+ data->descr[0].status = status;
+
+ ctl_complete_beio(beio);
+}
+
+static void
ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio)
{
@@ -1220,6 +1306,49 @@ ctl_be_block_cw_dispatch_unmap(struct ctl_be_block_lun *be_lun,
}
static void
+ctl_be_block_cr_done(struct ctl_be_block_io *beio)
+{
+ union ctl_io *io;
+
+ io = beio->io;
+ ctl_free_beio(beio);
+ ctl_config_read_done(io);
+}
+
+static void
+ctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun,
+ union ctl_io *io)
+{
+ struct ctl_be_block_io *beio;
+ struct ctl_be_block_softc *softc;
+
+ DPRINTF("entered\n");
+
+ softc = be_lun->softc;
+ beio = ctl_alloc_beio(softc);
+ beio->io = io;
+ beio->lun = be_lun;
+ beio->beio_cont = ctl_be_block_cr_done;
+ PRIV(io)->ptr = (void *)beio;
+
+ switch (io->scsiio.cdb[0]) {
+ case SERVICE_ACTION_IN: /* GET LBA STATUS */
+ beio->bio_cmd = -1;
+ beio->ds_trans_type = DEVSTAT_NO_DATA;
+ beio->ds_tag_type = DEVSTAT_TAG_ORDERED;
+ beio->io_len = 0;
+ if (be_lun->get_lba_status)
+ be_lun->get_lba_status(be_lun, beio);
+ else
+ ctl_be_block_cr_done(beio);
+ break;
+ default:
+ panic("Unhandled CDB type %#x", io->scsiio.cdb[0]);
+ break;
+ }
+}
+
+static void
ctl_be_block_cw_done(struct ctl_be_block_io *beio)
{
union ctl_io *io;
@@ -1454,16 +1583,21 @@ ctl_be_block_worker(void *context, int pending)
}
io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_write_queue);
if (io != NULL) {
-
DPRINTF("config write queue\n");
-
STAILQ_REMOVE(&be_lun->config_write_queue, &io->io_hdr,
ctl_io_hdr, links);
-
mtx_unlock(&be_lun->queue_lock);
-
ctl_be_block_cw_dispatch(be_lun, io);
-
+ mtx_lock(&be_lun->queue_lock);
+ continue;
+ }
+ io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_read_queue);
+ if (io != NULL) {
+ DPRINTF("config read queue\n");
+ STAILQ_REMOVE(&be_lun->config_read_queue, &io->io_hdr,
+ ctl_io_hdr, links);
+ mtx_unlock(&be_lun->queue_lock);
+ ctl_be_block_cr_dispatch(be_lun, io);
mtx_lock(&be_lun->queue_lock);
continue;
}
@@ -1592,6 +1726,7 @@ ctl_be_block_open_file(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
be_lun->dev_type = CTL_BE_BLOCK_FILE;
be_lun->dispatch = ctl_be_block_dispatch_file;
be_lun->lun_flush = ctl_be_block_flush_file;
+ be_lun->get_lba_status = ctl_be_block_gls_file;
error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred);
if (error != 0) {
@@ -1678,9 +1813,10 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
&be_lun->backend.dev.dev_ref);
if (be_lun->backend.dev.csw == NULL)
panic("Unable to retrieve device switch");
- if (strcmp(be_lun->backend.dev.csw->d_name, "zvol") == 0)
+ if (strcmp(be_lun->backend.dev.csw->d_name, "zvol") == 0) {
be_lun->dispatch = ctl_be_block_dispatch_zvol;
- else
+ be_lun->get_lba_status = ctl_be_block_gls_zvol;
+ } else
be_lun->dispatch = ctl_be_block_dispatch_dev;
be_lun->lun_flush = ctl_be_block_flush_dev;
be_lun->unmap = ctl_be_block_unmap_dev;
@@ -1955,6 +2091,7 @@ ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
be_lun->params = req->reqdata.create;
be_lun->softc = softc;
STAILQ_INIT(&be_lun->input_queue);
+ STAILQ_INIT(&be_lun->config_read_queue);
STAILQ_INIT(&be_lun->config_write_queue);
STAILQ_INIT(&be_lun->datamove_queue);
sprintf(be_lun->lunname, "cblk%d", softc->num_luns);
@@ -2585,13 +2722,50 @@ ctl_be_block_config_write(union ctl_io *io)
}
return (retval);
-
}
static int
ctl_be_block_config_read(union ctl_io *io)
{
- return (0);
+ struct ctl_be_block_lun *be_lun;
+ struct ctl_be_lun *ctl_be_lun;
+ int retval = 0;
+
+ DPRINTF("entered\n");
+
+ ctl_be_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[
+ CTL_PRIV_BACKEND_LUN].ptr;
+ be_lun = (struct ctl_be_block_lun *)ctl_be_lun->be_lun;
+
+ switch (io->scsiio.cdb[0]) {
+ case SERVICE_ACTION_IN:
+ if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) {
+ mtx_lock(&be_lun->queue_lock);
+ STAILQ_INSERT_TAIL(&be_lun->config_read_queue,
+ &io->io_hdr, links);
+ mtx_unlock(&be_lun->queue_lock);
+ taskqueue_enqueue(be_lun->io_taskqueue,
+ &be_lun->io_task);
+ retval = CTL_RETVAL_QUEUED;
+ break;
+ }
+ ctl_set_invalid_field(&io->scsiio,
+ /*sks_valid*/ 1,
+ /*command*/ 1,
+ /*field*/ 1,
+ /*bit_valid*/ 1,
+ /*bit*/ 4);
+ ctl_config_read_done(io);
+ retval = CTL_RETVAL_COMPLETE;
+ break;
+ default:
+ ctl_set_invalid_opcode(&io->scsiio);
+ ctl_config_read_done(io);
+ retval = CTL_RETVAL_COMPLETE;
+ break;
+ }
+
+ return (retval);
}
static int
diff --git a/sys/cam/ctl/ctl_backend_ramdisk.c b/sys/cam/ctl/ctl_backend_ramdisk.c
index 9b3b14a..adace4f 100644
--- a/sys/cam/ctl/ctl_backend_ramdisk.c
+++ b/sys/cam/ctl/ctl_backend_ramdisk.c
@@ -967,8 +967,31 @@ ctl_backend_ramdisk_config_write(union ctl_io *io)
static int
ctl_backend_ramdisk_config_read(union ctl_io *io)
{
- /*
- * XXX KDM need to implement!!
- */
- return (0);
+ int retval = 0;
+
+ switch (io->scsiio.cdb[0]) {
+ case SERVICE_ACTION_IN:
+ if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) {
+ /* We have nothing to tell, leave default data. */
+ ctl_config_read_done(io);
+ retval = CTL_RETVAL_COMPLETE;
+ break;
+ }
+ ctl_set_invalid_field(&io->scsiio,
+ /*sks_valid*/ 1,
+ /*command*/ 1,
+ /*field*/ 1,
+ /*bit_valid*/ 1,
+ /*bit*/ 4);
+ ctl_config_read_done(io);
+ retval = CTL_RETVAL_COMPLETE;
+ break;
+ default:
+ ctl_set_invalid_opcode(&io->scsiio);
+ ctl_config_read_done(io);
+ retval = CTL_RETVAL_COMPLETE;
+ break;
+ }
+
+ return (retval);
}
diff --git a/sys/cam/ctl/ctl_cmd_table.c b/sys/cam/ctl/ctl_cmd_table.c
index 5ae5057..24c0091 100644
--- a/sys/cam/ctl/ctl_cmd_table.c
+++ b/sys/cam/ctl/ctl_cmd_table.c
@@ -433,7 +433,7 @@ const struct ctl_cmd_entry ctl_cmd_table_9e[32] =
/* 0F */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
-/* 10 */
+/* 10 READ CAPACITY(16) */
{ctl_read_capacity_16, CTL_SERIDX_RD_CAP, CTL_CMD_FLAG_OK_ON_SLUN |
CTL_CMD_FLAG_OK_ON_STOPPED |
CTL_CMD_FLAG_OK_ON_INOPERABLE |
@@ -443,7 +443,18 @@ const struct ctl_cmd_entry ctl_cmd_table_9e[32] =
CTL_LUN_PAT_READCAP,
16, {0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
-/* 11-1f */
+/* 11 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 12 GET LBA STATUS */
+{ctl_get_lba_status, CTL_SERIDX_READ, CTL_CMD_FLAG_OK_ON_SLUN |
+ CTL_FLAG_DATA_IN |
+ CTL_CMD_FLAG_ALLOW_ON_PR_WRESV,
+ CTL_LUN_PAT_READ | CTL_LUN_PAT_RANGE,
+ 16, {0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
+
+/* 13-1f */
};
/* A3 MAINTENANCE IN */
diff --git a/sys/cam/ctl/ctl_private.h b/sys/cam/ctl/ctl_private.h
index dac8123..351b7f8 100644
--- a/sys/cam/ctl/ctl_private.h
+++ b/sys/cam/ctl/ctl_private.h
@@ -516,6 +516,7 @@ int ctl_report_supported_opcodes(struct ctl_scsiio *ctsio);
int ctl_report_supported_tmf(struct ctl_scsiio *ctsio);
int ctl_report_timestamp(struct ctl_scsiio *ctsio);
int ctl_isc(struct ctl_scsiio *ctsio);
+int ctl_get_lba_status(struct ctl_scsiio *ctsio);
void ctl_tpc_init(struct ctl_softc *softc);
void ctl_tpc_shutdown(struct ctl_softc *softc);
diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h
index 6ee0370..d536a74 100644
--- a/sys/cam/scsi/scsi_all.h
+++ b/sys/cam/scsi/scsi_all.h
@@ -2518,6 +2518,32 @@ struct scsi_read_capacity_data_long
uint8_t reserved[16];
};
+struct scsi_get_lba_status
+{
+ uint8_t opcode;
+#define SGLS_SERVICE_ACTION 0x12
+ uint8_t service_action;
+ uint8_t addr[8];
+ uint8_t alloc_len[4];
+ uint8_t reserved;
+ uint8_t control;
+};
+
+struct scsi_get_lba_status_data_descr
+{
+ uint8_t addr[8];
+ uint8_t length[4];
+ uint8_t status;
+ uint8_t reserved[3];
+};
+
+struct scsi_get_lba_status_data
+{
+ uint8_t length[4];
+ uint8_t reserved[4];
+ struct scsi_get_lba_status_data_descr descr[];
+};
+
struct scsi_report_luns
{
uint8_t opcode;
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
index 0451c65..e483d33 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
@@ -91,6 +91,7 @@
#include <sys/dmu_tx.h>
#include <sys/zfeature.h>
#include <sys/zio_checksum.h>
+#include <sys/filio.h>
#include <geom/geom.h>
@@ -2914,6 +2915,18 @@ zvol_d_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct threa
error = ENOIOCTL;
break;
}
+ case FIOSEEKHOLE:
+ case FIOSEEKDATA: {
+ off_t *off = (off_t *)data;
+ uint64_t noff;
+ boolean_t hole;
+
+ hole = (cmd == FIOSEEKHOLE);
+ noff = *off;
+ error = dmu_offset_next(zv->zv_objset, ZVOL_OBJ, hole, &noff);
+ *off = noff;
+ break;
+ }
default:
error = ENOIOCTL;
}
OpenPOWER on IntegriCloud