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. MFC after: 2 weeks Sponsored by: iXsystems, Inc.
This commit is contained in:
parent
6cf2e00820
commit
7884d9292a
@ -5172,6 +5172,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.
|
||||
*/
|
||||
@ -7172,6 +7206,66 @@ ctl_read_capacity_16(struct ctl_scsiio *ctsio)
|
||||
return (CTL_RETVAL_COMPLETE);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -10642,6 +10736,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 */
|
||||
|
@ -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);
|
||||
|
@ -68,6 +68,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>
|
||||
@ -163,6 +164,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;
|
||||
@ -180,6 +182,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;
|
||||
@ -237,6 +240,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,
|
||||
@ -245,6 +250,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,
|
||||
@ -752,6 +759,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)
|
||||
@ -844,6 +891,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)
|
||||
@ -1216,6 +1302,49 @@ ctl_be_block_cw_dispatch_unmap(struct ctl_be_block_lun *be_lun,
|
||||
be_lun->unmap(be_lun, beio);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -1451,16 +1580,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;
|
||||
}
|
||||
@ -1589,6 +1723,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) {
|
||||
@ -1675,9 +1810,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;
|
||||
@ -1952,6 +2088,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);
|
||||
@ -2582,13 +2719,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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user