summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorDan McDonald <danmcd@nexenta.com>2011-03-04 13:57:09 -0800
committerDan McDonald <danmcd@nexenta.com>2011-03-04 13:57:09 -0800
commitb77b9231da168bb31490f65bf2697f6031b7f601 (patch)
treeed69f4c3b7fa7df2dbc408df9e6f71e37f36085a /usr/src
parentc8937b0da86ffcdeb5a328afe14cb7bb0a5a4d2b (diff)
downloadillumos-joyent-b77b9231da168bb31490f65bf2697f6031b7f601.tar.gz
701 UNMAP support for COMSTAR
Reviewed by: Garrett D'Amore <garrett@nexenta.com> Reviewed by: Eric Schrock <eric.schrock@delphix.com> Reviewed by: George Wilson <gwilson@zfsmail.com> Approved by: Garrett D'Amore <garrett@nexenta.com>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/fs/zfs/zvol.c112
-rw-r--r--usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c113
-rw-r--r--usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c168
-rw-r--r--usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h44
-rw-r--r--usr/src/uts/common/sys/dkio.h15
-rw-r--r--usr/src/uts/common/sys/scsi/generic/commands.h15
-rw-r--r--usr/src/uts/common/sys/stmf_sbd_ioctl.h13
7 files changed, 449 insertions, 31 deletions
diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c
index 47b6c5a87a..a59c2a9772 100644
--- a/usr/src/uts/common/fs/zfs/zvol.c
+++ b/usr/src/uts/common/fs/zfs/zvol.c
@@ -20,10 +20,12 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Portions Copyright 2010 Robert Milkowski
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
-/* Portions Copyright 2010 Robert Milkowski */
-
/*
* ZFS volume emulation driver.
*
@@ -342,6 +344,24 @@ zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
}
/*
+ * Replay a TX_TRUNCATE ZIL transaction if asked. TX_TRUNCATE is how we
+ * implement DKIOCFREE/free-long-range.
+ */
+static int
+zvol_replay_truncate(zvol_state_t *zv, lr_truncate_t *lr, boolean_t byteswap)
+{
+ uint64_t offset, length;
+
+ if (byteswap)
+ byteswap_uint64_array(lr, sizeof (*lr));
+
+ offset = lr->lr_offset;
+ length = lr->lr_length;
+
+ return (dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, offset, length));
+}
+
+/*
* Replay a TX_WRITE ZIL transaction that didn't get committed
* after a system failure
*/
@@ -391,7 +411,7 @@ zvol_replay_err(zvol_state_t *zv, lr_t *lr, boolean_t byteswap)
/*
* Callback vectors for replaying records.
- * Only TX_WRITE is needed for zvol.
+ * Only TX_WRITE and TX_TRUNCATE are needed for zvol.
*/
zil_replay_func_t *zvol_replay_vector[TX_MAX_TYPE] = {
zvol_replay_err, /* 0 no such transaction type */
@@ -404,7 +424,7 @@ zil_replay_func_t *zvol_replay_vector[TX_MAX_TYPE] = {
zvol_replay_err, /* TX_LINK */
zvol_replay_err, /* TX_RENAME */
zvol_replay_write, /* TX_WRITE */
- zvol_replay_err, /* TX_TRUNCATE */
+ zvol_replay_truncate, /* TX_TRUNCATE */
zvol_replay_err, /* TX_SETATTR */
zvol_replay_err, /* TX_ACL */
zvol_replay_err, /* TX_CREATE_ACL */
@@ -1512,7 +1532,32 @@ zvol_log_write_minor(void *minor_hdl, dmu_tx_t *tx, offset_t off, ssize_t resid,
*/
/*
+ * Log a DKIOCFREE/free-long-range to the ZIL with TX_TRUNCATE.
+ */
+static void
+zvol_log_truncate(zvol_state_t *zv, dmu_tx_t *tx, uint64_t off, uint64_t len,
+ boolean_t sync)
+{
+ itx_t *itx;
+ lr_truncate_t *lr;
+ zilog_t *zilog = zv->zv_zilog;
+
+ if (zil_replaying(zilog, tx))
+ return;
+
+ itx = zil_itx_create(TX_TRUNCATE, sizeof (*lr));
+ lr = (lr_truncate_t *)&itx->itx_lr;
+ lr->lr_foid = ZVOL_OBJ;
+ lr->lr_offset = off;
+ lr->lr_length = len;
+
+ itx->itx_sync = sync;
+ zil_itx_assign(zilog, itx, tx);
+}
+
+/*
* Dirtbag ioctls to support mkfs(1M) for UFS filesystems. See dkio(7I).
+ * Also a dirtbag dkio ioctl for unmap/free-block functionality.
*/
/*ARGSUSED*/
int
@@ -1631,6 +1676,65 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
zfs_range_unlock(rl);
break;
+ case DKIOCFREE:
+ {
+ dkioc_free_t df;
+ dmu_tx_t *tx;
+
+ if (ddi_copyin((void *)arg, &df, sizeof (df), flag)) {
+ error = EFAULT;
+ break;
+ }
+
+ /*
+ * Apply Postel's Law to length-checking. If they overshoot,
+ * just blank out until the end, if there's a need to blank
+ * out anything.
+ */
+ if (df.df_start >= zv->zv_volsize)
+ break; /* No need to do anything... */
+ if (df.df_start + df.df_length > zv->zv_volsize)
+ df.df_length = DMU_OBJECT_END;
+
+ rl = zfs_range_lock(&zv->zv_znode, df.df_start, df.df_length,
+ RL_WRITER);
+ tx = dmu_tx_create(zv->zv_objset);
+ error = dmu_tx_assign(tx, TXG_WAIT);
+ if (error != 0) {
+ dmu_tx_abort(tx);
+ } else {
+ zvol_log_truncate(zv, tx, df.df_start,
+ df.df_length, B_TRUE);
+ error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ,
+ df.df_start, df.df_length);
+ dmu_tx_commit(tx);
+ }
+
+ zfs_range_unlock(rl);
+
+ if (error == 0) {
+ /*
+ * If the write-cache is disabled or 'sync' property
+ * is set to 'always' then treat this as a synchronous
+ * operation (i.e. commit to zil).
+ */
+ if (!(zv->zv_flags & ZVOL_WCE) ||
+ (zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS))
+ zil_commit(zv->zv_zilog, ZVOL_OBJ);
+
+ /*
+ * If the caller really wants synchronous writes, and
+ * can't wait for them, don't return until the write
+ * is done.
+ */
+ if (df.df_flags & DF_WAIT_SYNC) {
+ txg_wait_synced(
+ dmu_objset_pool(zv->zv_objset), 0);
+ }
+ }
+ break;
+ }
+
default:
error = ENOTTY;
break;
diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c
index d3c2cdb0bf..64ff9c93a5 100644
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c
@@ -20,6 +20,8 @@
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/conf.h>
@@ -83,7 +85,9 @@ int sbd_get_global_props(sbd_global_props_t *oslp, uint32_t oslp_sz,
uint32_t *err_ret);
int sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
sbd_lu_props_t *oslp, uint32_t oslp_sz, uint32_t *err_ret);
-char *sbd_get_zvol_name(sbd_lu_t *sl);
+static char *sbd_get_zvol_name(sbd_lu_t *);
+static int sbd_get_unmap_props(sbd_unmap_props_t *sup, sbd_unmap_props_t *osup,
+ uint32_t *err_ret);
sbd_status_t sbd_create_zfs_meta_object(sbd_lu_t *sl);
sbd_status_t sbd_open_zfs_meta(sbd_lu_t *sl);
sbd_status_t sbd_read_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz,
@@ -448,6 +452,18 @@ stmf_sbd_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
ret = 0;
iocd->stmf_error = 0;
break;
+ case SBD_IOCTL_GET_UNMAP_PROPS:
+ if (iocd->stmf_ibuf_size < sizeof (sbd_unmap_props_t)) {
+ ret = EFAULT;
+ break;
+ }
+ if (iocd->stmf_obuf_size < sizeof (sbd_unmap_props_t)) {
+ ret = EINVAL;
+ break;
+ }
+ ret = sbd_get_unmap_props((sbd_unmap_props_t *)ibuf,
+ (sbd_unmap_props_t *)obuf, &iocd->stmf_error);
+ break;
default:
ret = ENOTTY;
}
@@ -1372,12 +1388,28 @@ sbd_write_lu_info(sbd_lu_t *sl)
return (ret);
}
+/*
+ * Will scribble SL_UNMAP_ENABLED into sl_flags if we succeed.
+ */
+static void
+do_unmap_setup(sbd_lu_t *sl)
+{
+ ASSERT((sl->sl_flags & SL_UNMAP_ENABLED) == 0);
+
+ if ((sl->sl_flags & SL_ZFS_META) == 0)
+ return; /* No UNMAP for you. */
+
+ sl->sl_flags |= SL_UNMAP_ENABLED;
+}
+
int
sbd_populate_and_register_lu(sbd_lu_t *sl, uint32_t *err_ret)
{
stmf_lu_t *lu = sl->sl_lu;
stmf_status_t ret;
+ do_unmap_setup(sl);
+
lu->lu_id = (scsi_devid_desc_t *)sl->sl_device_id;
if (sl->sl_alias) {
lu->lu_alias = sl->sl_alias;
@@ -3132,6 +3164,46 @@ sbd_get_global_props(sbd_global_props_t *oslp, uint32_t oslp_sz,
return (0);
}
+static int
+sbd_get_unmap_props(sbd_unmap_props_t *sup,
+ sbd_unmap_props_t *osup, uint32_t *err_ret)
+{
+ sbd_status_t sret;
+ sbd_lu_t *sl = NULL;
+
+ if (sup->sup_guid_valid) {
+ sret = sbd_find_and_lock_lu(sup->sup_guid,
+ NULL, SL_OP_LU_PROPS, &sl);
+ } else {
+ sret = sbd_find_and_lock_lu(NULL,
+ (uint8_t *)sup->sup_zvol_path, SL_OP_LU_PROPS,
+ &sl);
+ }
+ if (sret != SBD_SUCCESS) {
+ if (sret == SBD_BUSY) {
+ *err_ret = SBD_RET_LU_BUSY;
+ return (EBUSY);
+ } else if (sret == SBD_NOT_FOUND) {
+ *err_ret = SBD_RET_NOT_FOUND;
+ return (ENOENT);
+ }
+ return (EIO);
+ }
+
+ sup->sup_found_lu = 1;
+ sup->sup_guid_valid = 1;
+ bcopy(sl->sl_device_id + 4, sup->sup_guid, 16);
+ if (sl->sl_flags & SL_UNMAP_ENABLED)
+ sup->sup_unmap_enabled = 1;
+ else
+ sup->sup_unmap_enabled = 0;
+
+ *osup = *sup;
+ sl->sl_trans_op = SL_OP_NONE;
+
+ return (0);
+}
+
int
sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
sbd_lu_props_t *oslp, uint32_t oslp_sz, uint32_t *err_ret)
@@ -3272,7 +3344,10 @@ sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
return (0);
}
-char *
+/*
+ * Returns an allocated string with the "<pool>/..." form of the zvol name.
+ */
+static char *
sbd_get_zvol_name(sbd_lu_t *sl)
{
char *src;
@@ -3286,9 +3361,9 @@ sbd_get_zvol_name(sbd_lu_t *sl)
if (SBD_IS_ZVOL(src) != 0) {
ASSERT(0);
}
- src += 14;
+ src += 14; /* Past /dev/zvol/dsk/ */
if (*src == '/')
- src++;
+ src++; /* or /dev/zvol/rdsk/ */
p = (char *)kmem_alloc(strlen(src) + 1, KM_SLEEP);
(void) strcpy(p, src);
return (p);
@@ -3623,3 +3698,33 @@ out:
(void) ldi_close(zfs_lh, FREAD|FWRITE, kcred);
return (rc);
}
+
+/*
+ * Unmap a region in a volume. Currently only supported for zvols.
+ */
+int
+sbd_unmap(sbd_lu_t *sl, uint64_t offset, uint64_t length)
+{
+ vnode_t *vp;
+ int unused;
+ dkioc_free_t df;
+
+ /* Right now, we only support UNMAP on zvols. */
+ if (!(sl->sl_flags & SL_ZFS_META))
+ return (EIO);
+
+ df.df_flags = (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) ?
+ DF_WAIT_SYNC : 0;
+ df.df_start = offset;
+ df.df_length = length;
+
+ /* Use the data vnode we have to send a fop_ioctl(). */
+ vp = sl->sl_data_vp;
+ if (vp == NULL) {
+ cmn_err(CE_WARN, "Cannot unmap - no vnode pointer.");
+ return (EIO);
+ }
+
+ return (VOP_IOCTL(vp, DKIOCFREE, (intptr_t)(&df), FKIOCTL, kcred,
+ &unused, NULL));
+}
diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
index 23f306d15a..9cf4c9c140 100644
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
@@ -20,6 +20,8 @@
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/conf.h>
@@ -98,6 +100,11 @@ void sbd_handle_mode_select_xfer(scsi_task_t *task, uint8_t *buf,
void sbd_handle_mode_select(scsi_task_t *task, stmf_data_buf_t *dbuf);
void sbd_handle_identifying_info(scsi_task_t *task, stmf_data_buf_t *dbuf);
+static void sbd_handle_unmap_xfer(scsi_task_t *task, uint8_t *buf,
+ uint32_t buflen);
+static void sbd_handle_unmap(scsi_task_t *task, stmf_data_buf_t *dbuf);
+static void sbd_handle_write_same(scsi_task_t *task);
+
extern void sbd_pgr_initialize_it(scsi_task_t *, sbd_it_data_t *);
extern int sbd_pgr_reservation_conflict(scsi_task_t *);
extern void sbd_pgr_reset(sbd_lu_t *);
@@ -1754,6 +1761,10 @@ sbd_handle_short_write_xfer_completion(scsi_task_t *task,
dbuf->db_sglist[0].seg_addr, dbuf->db_data_size);
}
break;
+ case SCMD_UNMAP:
+ sbd_handle_unmap_xfer(task,
+ dbuf->db_sglist[0].seg_addr, dbuf->db_data_size);
+ break;
case SCMD_PERSISTENT_RESERVE_OUT:
if (sl->sl_access_state == SBD_LU_STANDBY) {
st_ret = stmf_proxy_scsi_cmd(task, dbuf);
@@ -1815,6 +1826,9 @@ sbd_handle_read_capacity(struct scsi_task *task,
p[7] = s & 0xff;
p[10] = (blksize >> 8) & 0xff;
p[11] = blksize & 0xff;
+ if (sl->sl_flags & SL_UNMAP_ENABLED) {
+ p[14] = 0x80;
+ }
sbd_handle_short_read_transfers(task, initial_dbuf, p,
cdb_len, 32);
break;
@@ -2216,6 +2230,105 @@ sbd_parse_mgmt_url(char **url_addr) {
return (url_length);
}
+static void
+sbd_handle_write_same(scsi_task_t *task)
+{
+ sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
+ uint64_t addr, len;
+ uint8_t *p;
+
+ task->task_cmd_xfer_length = 0;
+ if (task->task_additional_flags &
+ TASK_AF_NO_EXPECTED_XFER_LENGTH) {
+ task->task_expected_xfer_length = 0;
+ }
+ if (task->task_cdb[1] & 0xF7) {
+ stmf_scsilib_send_status(task, STATUS_CHECK,
+ STMF_SAA_INVALID_FIELD_IN_CDB);
+ return;
+ }
+ p = &task->task_cdb[2];
+ addr = READ_SCSI64(p, uint64_t);
+ addr <<= sl->sl_data_blocksize_shift;
+ len = READ_SCSI32(p+8, uint64_t);
+ len <<= sl->sl_data_blocksize_shift;
+
+ /* TODO -> full write_same support with data checks... */
+ if (sbd_unmap(sl, addr, len) != 0) {
+ stmf_scsilib_send_status(task, STATUS_CHECK,
+ STMF_SAA_LBA_OUT_OF_RANGE);
+ return;
+ }
+ stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+}
+
+static void
+sbd_handle_unmap(scsi_task_t *task, stmf_data_buf_t *dbuf)
+{
+ uint32_t cmd_xfer_len;
+
+ cmd_xfer_len = READ_SCSI16(&task->task_cdb[7], uint32_t);
+
+ if (task->task_cdb[1] & 1) {
+ stmf_scsilib_send_status(task, STATUS_CHECK,
+ STMF_SAA_INVALID_FIELD_IN_CDB);
+ return;
+ }
+
+ if (cmd_xfer_len == 0) {
+ task->task_cmd_xfer_length = 0;
+ if (task->task_additional_flags &
+ TASK_AF_NO_EXPECTED_XFER_LENGTH) {
+ task->task_expected_xfer_length = 0;
+ }
+ stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+ return;
+ }
+
+ sbd_handle_short_write_transfers(task, dbuf, cmd_xfer_len);
+}
+
+static void
+sbd_handle_unmap_xfer(scsi_task_t *task, uint8_t *buf, uint32_t buflen)
+{
+ sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
+ uint32_t ulen, dlen, num_desc;
+ uint64_t addr, len;
+ uint8_t *p;
+ int ret;
+
+ if (buflen < 24) {
+ stmf_scsilib_send_status(task, STATUS_CHECK,
+ STMF_SAA_INVALID_FIELD_IN_CDB);
+ return;
+ }
+ ulen = READ_SCSI16(buf, uint32_t);
+ dlen = READ_SCSI16(buf + 2, uint32_t);
+ num_desc = dlen >> 4;
+ if (((ulen + 2) != buflen) || ((dlen + 8) != buflen) || (dlen & 0xf) ||
+ (num_desc == 0)) {
+ stmf_scsilib_send_status(task, STATUS_CHECK,
+ STMF_SAA_INVALID_FIELD_IN_CDB);
+ return;
+ }
+
+ for (p = buf + 8; num_desc; num_desc--, p += 16) {
+ addr = READ_SCSI64(p, uint64_t);
+ addr <<= sl->sl_data_blocksize_shift;
+ len = READ_SCSI32(p+8, uint64_t);
+ len <<= sl->sl_data_blocksize_shift;
+ ret = sbd_unmap(sl, addr, len);
+ if (ret != 0) {
+ stmf_scsilib_send_status(task, STATUS_CHECK,
+ STMF_SAA_LBA_OUT_OF_RANGE);
+ return;
+ }
+ }
+
+unmap_done:
+ stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+}
+
void
sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
{
@@ -2228,6 +2341,8 @@ sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
uint16_t cmd_size;
uint32_t xfer_size = 4;
uint32_t mgmt_url_size = 0;
+ uint8_t exp;
+ uint64_t s;
char *mgmt_url = NULL;
@@ -2380,6 +2495,8 @@ sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
switch (cdbp[2]) {
case 0x00:
page_length = 4 + (mgmt_url_size ? 1 : 0);
+ if (sl->sl_flags & SL_UNMAP_ENABLED)
+ page_length += 2;
p[0] = byte0;
p[3] = page_length;
@@ -2392,6 +2509,10 @@ sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
if (mgmt_url_size != 0)
p[i++] = 0x85;
p[i++] = 0x86;
+ if (sl->sl_flags & SL_UNMAP_ENABLED) {
+ p[i++] = 0xb0;
+ p[i++] = 0xb2;
+ }
}
xfer_size = page_length + 4;
break;
@@ -2482,6 +2603,43 @@ sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
xfer_size = page_length + 4;
break;
+ case 0xb0:
+ if ((sl->sl_flags & SL_UNMAP_ENABLED) == 0) {
+ stmf_scsilib_send_status(task, STATUS_CHECK,
+ STMF_SAA_INVALID_FIELD_IN_CDB);
+ goto err_done;
+ }
+ page_length = 0x3c;
+ p[0] = byte0;
+ p[1] = 0xb0;
+ p[3] = page_length;
+ p[20] = p[21] = p[22] = p[23] = 0xFF;
+ p[24] = p[25] = p[26] = p[27] = 0xFF;
+ xfer_size = page_length + 4;
+ break;
+
+ case 0xb2:
+ if ((sl->sl_flags & SL_UNMAP_ENABLED) == 0) {
+ stmf_scsilib_send_status(task, STATUS_CHECK,
+ STMF_SAA_INVALID_FIELD_IN_CDB);
+ goto err_done;
+ }
+ page_length = 4;
+ p[0] = byte0;
+ p[1] = 0xb2;
+ p[3] = page_length;
+
+ exp = (uint8_t)sl->sl_data_blocksize_shift;
+ s = sl->sl_lu_size >> sl->sl_data_blocksize_shift;
+ while (s & ((uint64_t)0xFFFFFFFF80000000ull)) {
+ s >>= 1;
+ exp++;
+ }
+ p[4] = exp;
+ p[5] = 0xc0;
+ xfer_size = page_length + 4;
+ break;
+
default:
stmf_scsilib_send_status(task, STATUS_CHECK,
STMF_SAA_INVALID_FIELD_IN_CDB);
@@ -2908,6 +3066,16 @@ sbd_new_task(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
return;
}
+ if ((cdb0 == SCMD_UNMAP) && (sl->sl_flags & SL_UNMAP_ENABLED)) {
+ sbd_handle_unmap(task, initial_dbuf);
+ return;
+ }
+
+ if ((cdb0 == SCMD_WRITE_SAME_G4) && (sl->sl_flags & SL_UNMAP_ENABLED)) {
+ sbd_handle_write_same(task);
+ return;
+ }
+
if (cdb0 == SCMD_TEST_UNIT_READY) { /* Test unit ready */
task->task_cmd_xfer_length = 0;
stmf_scsilib_send_status(task, STATUS_GOOD, 0);
diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h b/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h
index ab3fa93b38..efbc7268ea 100644
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h
@@ -20,6 +20,8 @@
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _STMF_SBD_H
@@ -247,26 +249,27 @@ typedef struct sbd_lu {
/*
* sl_flags
*/
-#define SL_LINKED 0x00001
-#define SL_META_OPENED 0x00002
-#define SL_REGISTERED 0x00004
-#define SL_META_NEEDS_FLUSH 0x00008
-#define SL_DATA_NEEDS_FLUSH 0x00010
-#define SL_VID_VALID 0x00020
-#define SL_PID_VALID 0x00040
-#define SL_REV_VALID 0x00080
-#define SL_WRITE_PROTECTED 0x00100
-#define SL_MEDIA_LOADED 0x00200
-#define SL_LU_HAS_SCSI2_RESERVATION 0x00400
-#define SL_WRITEBACK_CACHE_DISABLE 0x00800
-#define SL_SAVED_WRITE_CACHE_DISABLE 0x01000
-#define SL_MEDIUM_REMOVAL_PREVENTED 0x02000
-#define SL_NO_DATA_DKIOFLUSH 0x04000
-#define SL_SHARED_META 0x08000
-#define SL_ZFS_META 0x10000
-#define SL_WRITEBACK_CACHE_SET_UNSUPPORTED 0x20000
-#define SL_FLUSH_ON_DISABLED_WRITECACHE 0x40000
-#define SL_CALL_ZVOL 0x80000
+#define SL_LINKED 0x00000001
+#define SL_META_OPENED 0x00000002
+#define SL_REGISTERED 0x00000004
+#define SL_META_NEEDS_FLUSH 0x00000008
+#define SL_DATA_NEEDS_FLUSH 0x00000010
+#define SL_VID_VALID 0x00000020
+#define SL_PID_VALID 0x00000040
+#define SL_REV_VALID 0x00000080
+#define SL_WRITE_PROTECTED 0x00000100
+#define SL_MEDIA_LOADED 0x00000200
+#define SL_LU_HAS_SCSI2_RESERVATION 0x00000400
+#define SL_WRITEBACK_CACHE_DISABLE 0x00000800
+#define SL_SAVED_WRITE_CACHE_DISABLE 0x00001000
+#define SL_MEDIUM_REMOVAL_PREVENTED 0x00002000
+#define SL_NO_DATA_DKIOFLUSH 0x00004000
+#define SL_SHARED_META 0x00008000
+#define SL_ZFS_META 0x00010000
+#define SL_WRITEBACK_CACHE_SET_UNSUPPORTED 0x00020000
+#define SL_FLUSH_ON_DISABLED_WRITECACHE 0x00040000
+#define SL_CALL_ZVOL 0x00080000
+#define SL_UNMAP_ENABLED 0x00100000
/*
* sl_trans_op. LU is undergoing some transition and this field
@@ -297,6 +300,7 @@ sbd_status_t sbd_write_lu_info(sbd_lu_t *sl);
sbd_status_t sbd_flush_data_cache(sbd_lu_t *sl, int fsync_done);
sbd_status_t sbd_wcd_set(int wcd, sbd_lu_t *sl);
void sbd_wcd_get(int *wcd, sbd_lu_t *sl);
+int sbd_unmap(sbd_lu_t *, uint64_t, uint64_t);
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/sys/dkio.h b/usr/src/uts/common/sys/dkio.h
index 5bae8e65bb..eb4ddf34fe 100644
--- a/usr/src/uts/common/sys/dkio.h
+++ b/usr/src/uts/common/sys/dkio.h
@@ -21,6 +21,8 @@
/*
* Copyright (c) 1982, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SYS_DKIO_H
@@ -515,6 +517,19 @@ typedef struct dk_updatefw_32 {
#define FW_TYPE_TEMP 0x0 /* temporary use */
#define FW_TYPE_PERM 0x1 /* permanent use */
+/*
+ * ioctl to free space (e.g. SCSI UNMAP) off a disk.
+ */
+#define DKIOCFREE (DKIOC|50)
+
+typedef struct dkioc_free_s {
+ uint32_t df_flags;
+ uint32_t df_reserved; /* For easy 64-bit alignment below... */
+ diskaddr_t df_start;
+ diskaddr_t df_length;
+} dkioc_free_t;
+
+#define DF_WAIT_SYNC 0x00000001 /* Wait for full write-out of free. */
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/sys/scsi/generic/commands.h b/usr/src/uts/common/sys/scsi/generic/commands.h
index aaa7b57915..e15a80a800 100644
--- a/usr/src/uts/common/sys/scsi/generic/commands.h
+++ b/usr/src/uts/common/sys/scsi/generic/commands.h
@@ -21,6 +21,8 @@
/*
* Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SYS_SCSI_GENERIC_COMMANDS_H
@@ -233,13 +235,15 @@ extern "C" {
#define SCMD_READ_BUFFER 0x3c
#define SCMD_READ_LONG 0x3E
#define SCMD_WRITE_LONG 0x3F
+#define SCMD_WRITE_SAME_G1 0x41
+#define SCMD_UNMAP 0x42
+#define SCMD_GET_CONFIGURATION 0x46
+#define SCMD_LOG_SELECT_G1 0x4c
+#define SCMD_LOG_SENSE_G1 0x4d
#define SCMD_RESERVE_G1 0x56
#define SCMD_RELEASE_G1 0x57
#define SCMD_MODE_SELECT_G1 0x55
#define SCMD_MODE_SENSE_G1 0x5A
-#define SCMD_GET_CONFIGURATION 0x46
-#define SCMD_LOG_SELECT_G1 0x4C
-#define SCMD_LOG_SENSE_G1 0x4d
/*
@@ -333,6 +337,7 @@ extern "C" {
#define SCMD_READ_G4 0x88
#define SCMD_WRITE_G4 0x8a
#define SCMD_WRITE_VERIFY_G4 0x8e
+#define SCMD_WRITE_SAME_G4 0x93
#define SCMD_SVC_ACTION_IN_G4 0x9e
#define SCMD_SVC_ACTION_OUT_G4 0x9f
@@ -455,9 +460,12 @@ extern "C" {
/* 0x3c */ SCMD_READ_BUFFER, "read_buffer", \
/* 0x3e */ SCMD_READ_LONG, "read_long", \
/* 0x3f */ SCMD_WRITE_LONG, "write_long", \
+/* 0x41 */ SCMD_WRITE_SAME_G1, "write_same(10)", \
+/* 0x42 */ SCMD_UNMAP, "unmap", \
/* 0x44 */ SCMD_REPORT_DENSITIES | \
/* SCMD_READ_HEADER (from cdio.h) | */ \
0, "report_densities/read_header", \
+/* 0x46 */ SCMD_GET_CONFIGURATION, "get_configuration", \
/* 0x4c */ SCMD_LOG_SELECT_G1, "log_select", \
/* 0x4d */ SCMD_LOG_SENSE_G1, "log_sense", \
/* 0x55 */ SCMD_MODE_SELECT_G1, "mode_select(10)", \
@@ -477,6 +485,7 @@ extern "C" {
/* 0x8f */ SCMD_VERIFY_G4, "verify(16)", \
/* 0x91 */ SCMD_SPACE_G4, "space(16)", \
/* 0x92 */ SCMD_LOCATE_G4, "locate(16)", \
+/* 0x92 */ SCMD_WRITE_SAME_G4, "write_same(16)", \
/* 0x9e */ SCMD_SVC_ACTION_IN_G4, "service_action_in(16)", \
/* 0x9f */ SCMD_SVC_ACTION_OUT_G4, "service_action_out(16)", \
/* 0xa0 */ SCMD_REPORT_LUNS, "report_luns", \
diff --git a/usr/src/uts/common/sys/stmf_sbd_ioctl.h b/usr/src/uts/common/sys/stmf_sbd_ioctl.h
index 5f1ba6cfe4..8e235ba651 100644
--- a/usr/src/uts/common/sys/stmf_sbd_ioctl.h
+++ b/usr/src/uts/common/sys/stmf_sbd_ioctl.h
@@ -21,6 +21,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _STMF_SBD_IOCTL_H
@@ -76,6 +78,7 @@ typedef enum sbd_ret {
#define SBD_IOCTL_SET_LU_STANDBY SBD_IOCTL_DEF(7)
#define SBD_IOCTL_SET_GLOBAL_LU SBD_IOCTL_DEF(8)
#define SBD_IOCTL_GET_GLOBAL_LU SBD_IOCTL_DEF(9)
+#define SBD_IOCTL_GET_UNMAP_PROPS SBD_IOCTL_DEF(10)
typedef struct sbd_create_and_reg_lu {
uint32_t slu_struct_size;
@@ -222,6 +225,16 @@ typedef struct sbd_lu_props {
uint8_t slp_buf[8]; /* likely more than 8 */
} sbd_lu_props_t;
+typedef struct sbd_unmap_props {
+ uint32_t sup_found_lu:1,
+ sup_zvol_path_valid:1,
+ sup_guid_valid:1,
+ sup_unmap_enabled;
+ uint32_t sup_rsvd;
+ char sup_zvol_path[256];
+ uint8_t sup_guid[16];
+} sbd_unmap_props_t;
+
#ifdef __cplusplus
}
#endif