diff options
author | Dan McDonald <danmcd@nexenta.com> | 2011-03-04 13:57:09 -0800 |
---|---|---|
committer | Dan McDonald <danmcd@nexenta.com> | 2011-03-04 13:57:09 -0800 |
commit | b77b9231da168bb31490f65bf2697f6031b7f601 (patch) | |
tree | ed69f4c3b7fa7df2dbc408df9e6f71e37f36085a /usr/src | |
parent | c8937b0da86ffcdeb5a328afe14cb7bb0a5a4d2b (diff) | |
download | illumos-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.c | 112 | ||||
-rw-r--r-- | usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c | 113 | ||||
-rw-r--r-- | usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c | 168 | ||||
-rw-r--r-- | usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h | 44 | ||||
-rw-r--r-- | usr/src/uts/common/sys/dkio.h | 15 | ||||
-rw-r--r-- | usr/src/uts/common/sys/scsi/generic/commands.h | 15 | ||||
-rw-r--r-- | usr/src/uts/common/sys/stmf_sbd_ioctl.h | 13 |
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 |