diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/lib/libdevid/Makefile.com | 4 | ||||
-rw-r--r-- | usr/src/lib/libdiskmgt/Makefile.com | 3 | ||||
-rw-r--r-- | usr/src/lib/libfdisk/Makefile.com | 3 | ||||
-rw-r--r-- | usr/src/lib/libsmedia/library/Makefile.com | 4 | ||||
-rw-r--r-- | usr/src/pkg/manifests/system-header.mf | 1 | ||||
-rw-r--r-- | usr/src/uts/common/Makefile.files | 1 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zvol.c | 82 | ||||
-rw-r--r-- | usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c | 26 | ||||
-rw-r--r-- | usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c | 50 | ||||
-rw-r--r-- | usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h | 6 | ||||
-rw-r--r-- | usr/src/uts/common/io/sata/impl/sata.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/io/scsi/targets/sd.c | 397 | ||||
-rw-r--r-- | usr/src/uts/common/os/dkioc_free_util.c | 80 | ||||
-rw-r--r-- | usr/src/uts/common/sys/Makefile | 3 | ||||
-rw-r--r-- | usr/src/uts/common/sys/dkio.h | 24 | ||||
-rw-r--r-- | usr/src/uts/common/sys/dkioc_free_util.h | 34 | ||||
-rw-r--r-- | usr/src/uts/common/sys/scsi/targets/sddef.h | 42 |
17 files changed, 691 insertions, 73 deletions
diff --git a/usr/src/lib/libdevid/Makefile.com b/usr/src/lib/libdevid/Makefile.com index 59c39c0b9c..fe065fc59a 100644 --- a/usr/src/lib/libdevid/Makefile.com +++ b/usr/src/lib/libdevid/Makefile.com @@ -22,6 +22,8 @@ # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# Copyright 2018 Joyent, Inc. +# LIBRARY= libdevid.a VERS= .1 OBJECTS= deviceid.o devid.o devid_scsi.o devid_smp.o @@ -41,6 +43,8 @@ LDLIBS += -ldevinfo -lc CFLAGS += $(CCVERBOSE) +CSTD = $(CSTD_GNU99) + .KEEP_STATE: all: $(LIBS) diff --git a/usr/src/lib/libdiskmgt/Makefile.com b/usr/src/lib/libdiskmgt/Makefile.com index 9c9e20908e..03a779d11e 100644 --- a/usr/src/lib/libdiskmgt/Makefile.com +++ b/usr/src/lib/libdiskmgt/Makefile.com @@ -23,6 +23,7 @@ # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # Copyright 2016 Nexenta Systems, Inc. +# Copyright 2018 Joyent, Inc. # LIBRARY = libdiskmgt.a @@ -65,6 +66,8 @@ CERRWARN += -_gcc=-Wno-parentheses CERRWARN += -_gcc=-Wno-uninitialized CPPFLAGS += -D_REENTRANT -I$(SRC)/lib/libdiskmgt/common +CSTD = $(CSTD_GNU99) + .KEEP_STATE: all: $(LIBS) diff --git a/usr/src/lib/libfdisk/Makefile.com b/usr/src/lib/libfdisk/Makefile.com index 46572b0b2b..198669d353 100644 --- a/usr/src/lib/libfdisk/Makefile.com +++ b/usr/src/lib/libfdisk/Makefile.com @@ -22,6 +22,7 @@ # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# Copyright 2018 Joyent, Inc. # LIBRARY= libfdisk.a @@ -49,6 +50,8 @@ CFLAGS += -D_FILE_OFFSET_BITS=64 CFLAGS64 += -D_LARGEFILE64_SOURCE CFLAGS64 += -D_FILE_OFFSET_BITS=64 +CSTD = $(CSTD_GNU99) + LINTFLAGS += -erroff=E_BAD_PTR_CAST_ALIGN LINTFLAGS64 += -erroff=E_BAD_PTR_CAST_ALIGN diff --git a/usr/src/lib/libsmedia/library/Makefile.com b/usr/src/lib/libsmedia/library/Makefile.com index e570948866..bcdb37b2e7 100644 --- a/usr/src/lib/libsmedia/library/Makefile.com +++ b/usr/src/lib/libsmedia/library/Makefile.com @@ -22,6 +22,8 @@ # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# Copyright 2018 Joyent, Inc. +# LIBRARY= libsmedia.a VERS=.1 @@ -54,6 +56,8 @@ CFLAGS64 += $(CCVERBOSE) CERRWARN += -_gcc=-Wno-unused-variable +CSTD = $(CSTD_GNU99) + LDLIBS += -lnsl -lc .KEEP_STATE: diff --git a/usr/src/pkg/manifests/system-header.mf b/usr/src/pkg/manifests/system-header.mf index 3f62bda986..a65dbd02b9 100644 --- a/usr/src/pkg/manifests/system-header.mf +++ b/usr/src/pkg/manifests/system-header.mf @@ -919,6 +919,7 @@ file path=usr/include/sys/dirent.h file path=usr/include/sys/disp.h file path=usr/include/sys/dkbad.h file path=usr/include/sys/dkio.h +file path=usr/include/sys/dkioc_free_util.h file path=usr/include/sys/dklabel.h $(sparc_ONLY)file path=usr/include/sys/dkmpio.h $(i386_ONLY)file path=usr/include/sys/dktp/altsctr.h diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index c9d04fb798..c963c34ce4 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -160,6 +160,7 @@ GENUNIX_OBJS += \ devid_smp.o \ devpolicy.o \ disp_lock.o \ + dkioc_free_util.o \ dnlc.o \ driver.o \ dumpsubr.o \ diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c index 2127de2bf0..b58cf54a17 100644 --- a/usr/src/uts/common/fs/zfs/zvol.c +++ b/usr/src/uts/common/fs/zfs/zvol.c @@ -23,7 +23,7 @@ * * Portions Copyright 2010 Robert Milkowski * - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2012, 2017 by Delphix. All rights reserved. * Copyright (c) 2014 Integros [integros.com] * Copyright 2018 Joyent, Inc. @@ -91,6 +91,7 @@ #include <sys/zio_checksum.h> #include <sys/zil_impl.h> #include <sys/ht.h> +#include <sys/dkioc_free_util.h> #include "zfs_namecheck.h" @@ -1900,45 +1901,65 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) case DKIOCFREE: { - dkioc_free_t df; + dkioc_free_list_t *dfl; dmu_tx_t *tx; if (!zvol_unmap_enabled) break; - if (ddi_copyin((void *)arg, &df, sizeof (df), flag)) { - error = SET_ERROR(EFAULT); - break; + if (!(flag & FKIOCTL)) { + error = dfl_copyin((void *)arg, &dfl, flag, KM_SLEEP); + if (error != 0) + break; + } else { + dfl = (dkioc_free_list_t *)arg; + ASSERT3U(dfl->dfl_num_exts, <=, DFL_COPYIN_MAX_EXTS); + if (dfl->dfl_num_exts > DFL_COPYIN_MAX_EXTS) { + error = SET_ERROR(EINVAL); + 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... */ - mutex_exit(&zfsdev_state_lock); ht_begin_unsafe(); - rl = zfs_range_lock(&zv->zv_znode, df.df_start, df.df_length, - RL_WRITER); - tx = dmu_tx_create(zv->zv_objset); - dmu_tx_mark_netfree(tx); - 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); - dmu_tx_commit(tx); - error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, - df.df_start, df.df_length); - } + for (int i = 0; i < dfl->dfl_num_exts; i++) { + uint64_t start = dfl->dfl_exts[i].dfle_start, + length = dfl->dfl_exts[i].dfle_length, + end = start + length; + + /* + * 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 (start >= zv->zv_volsize) + continue; /* No need to do anything... */ + if (end > zv->zv_volsize) { + end = DMU_OBJECT_END; + length = end - start; + } - zfs_range_unlock(rl); + rl = zfs_range_lock(&zv->zv_znode, start, 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, start, length, + B_TRUE); + dmu_tx_commit(tx); + error = dmu_free_long_range(zv->zv_objset, + ZVOL_OBJ, start, length); + } + + zfs_range_unlock(rl); + + if (error != 0) + break; + } /* * If the write-cache is disabled, 'sync' property @@ -1951,10 +1972,13 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) if ((error == 0) && zvol_unmap_sync_enabled && (!(zv->zv_flags & ZVOL_WCE) || (zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS) || - (df.df_flags & DF_WAIT_SYNC))) { + (dfl->dfl_flags & DF_WAIT_SYNC))) { zil_commit(zv->zv_zilog, ZVOL_OBJ); } + if (!(flag & FKIOCTL)) + dfl_free(dfl); + ht_end_unsafe(); return (error); 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 81e63367c5..d2dca92dfc 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 @@ -21,7 +21,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. */ @@ -318,7 +318,7 @@ sbd_close(dev_t dev, int flag, int otype, cred_t *credp) /* ARGSUSED */ static int stmf_sbd_ioctl(dev_t dev, int cmd, intptr_t data, int mode, - cred_t *credp, int *rval) + cred_t *credp, int *rval) { stmf_iocdata_t *iocd; void *ibuf = NULL; @@ -3689,22 +3689,26 @@ out: /* * Unmap a region in a volume. Currently only supported for zvols. + * The list of extents to be freed is passed in a dkioc_free_list_t + * which the caller is responsible for destroying. */ int -sbd_unmap(sbd_lu_t *sl, uint64_t offset, uint64_t length) +sbd_unmap(sbd_lu_t *sl, dkioc_free_list_t *dfl) { 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); + /* Nothing to do */ + if (dfl->dfl_num_exts == 0) + return (0); - df.df_flags = (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) ? + /* + * TODO: unmap performance may be improved by not doing the synchronous + * removal of the blocks and writing of the metadata. The + * transaction is in the zil so the state should be stable. + */ + dfl->dfl_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; @@ -3713,6 +3717,6 @@ sbd_unmap(sbd_lu_t *sl, uint64_t offset, uint64_t length) return (EIO); } - return (VOP_IOCTL(vp, DKIOCFREE, (intptr_t)(&df), FKIOCTL, kcred, + return (VOP_IOCTL(vp, DKIOCFREE, (intptr_t)dfl, 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 cb6e115fe9..0ca48aed9d 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,7 +20,7 @@ */ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. */ @@ -37,6 +37,7 @@ #include <sys/atomic.h> #include <sys/sdt.h> #include <sys/dkio.h> +#include <sys/dkioc_free_util.h> #include <sys/stmf.h> #include <sys/lpif.h> @@ -130,7 +131,7 @@ static void sbd_handle_write_same_xfer_completion(struct scsi_task *task, void sbd_do_read_xfer(struct scsi_task *task, sbd_cmd_t *scmd, - struct stmf_data_buf *dbuf) + struct stmf_data_buf *dbuf) { sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private; uint64_t laddr; @@ -450,7 +451,7 @@ sbd_do_sgl_read_xfer(struct scsi_task *task, sbd_cmd_t *scmd, int first_xfer) void sbd_handle_read_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd, - struct stmf_data_buf *dbuf) + struct stmf_data_buf *dbuf) { if (dbuf->db_xfer_status != STMF_SUCCESS) { stmf_abort(STMF_QUEUE_TASK_ABORT, task, @@ -503,7 +504,7 @@ sbd_handle_read_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd, */ void sbd_handle_sgl_read_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd, - struct stmf_data_buf *dbuf) + struct stmf_data_buf *dbuf) { sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private; stmf_status_t xfer_status; @@ -592,7 +593,7 @@ sbd_handle_sgl_read_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd, void sbd_handle_sgl_write_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd, - struct stmf_data_buf *dbuf) + struct stmf_data_buf *dbuf) { sbd_zvol_io_t *zvio = dbuf->db_lu_private; sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private; @@ -1641,7 +1642,7 @@ sbd_handle_short_read_transfers(scsi_task_t *task, stmf_data_buf_t *dbuf, void sbd_handle_short_read_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd, - struct stmf_data_buf *dbuf) + struct stmf_data_buf *dbuf) { if (dbuf->db_xfer_status != STMF_SUCCESS) { stmf_abort(STMF_QUEUE_TASK_ABORT, task, @@ -2189,7 +2190,8 @@ sbd_handle_identifying_info(struct scsi_task *task, * and returns the length of the URL */ uint16_t -sbd_parse_mgmt_url(char **url_addr) { +sbd_parse_mgmt_url(char **url_addr) +{ uint16_t url_length = 0; char *url; url = *url_addr; @@ -2467,12 +2469,18 @@ sbd_handle_write_same(scsi_task_t *task, struct stmf_data_buf *initial_dbuf) /* Check if the command is for the unmap function */ if (unmap) { - if (sbd_unmap(sl, addr, len) != 0) { + dkioc_free_list_t *dfl = kmem_zalloc(DFL_SZ(1), KM_SLEEP); + + dfl->dfl_num_exts = 1; + dfl->dfl_exts[0].dfle_start = addr; + dfl->dfl_exts[0].dfle_length = len; + if (sbd_unmap(sl, dfl) != 0) { stmf_scsilib_send_status(task, STATUS_CHECK, STMF_SAA_LBA_OUT_OF_RANGE); } else { stmf_scsilib_send_status(task, STATUS_GOOD, 0); } + dfl_free(dfl); return; } @@ -2576,7 +2584,9 @@ sbd_handle_unmap_xfer(scsi_task_t *task, uint8_t *buf, uint32_t buflen) uint32_t ulen, dlen, num_desc; uint64_t addr, len; uint8_t *p; + dkioc_free_list_t *dfl; int ret; + int i; if (buflen < 24) { stmf_scsilib_send_status(task, STATUS_CHECK, @@ -2593,20 +2603,28 @@ sbd_handle_unmap_xfer(scsi_task_t *task, uint8_t *buf, uint32_t buflen) return; } - for (p = buf + 8; num_desc; num_desc--, p += 16) { + dfl = kmem_zalloc(DFL_SZ(num_desc), KM_SLEEP); + dfl->dfl_num_exts = num_desc; + for (p = buf + 8, i = 0; num_desc; num_desc--, p += 16, i++) { 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; - } + /* Prepare a list of extents to unmap */ + dfl->dfl_exts[i].dfle_start = addr; + dfl->dfl_exts[i].dfle_length = len; + } + ASSERT(i == dfl->dfl_num_exts); + + /* Finally execute the unmap operations in a single step */ + ret = sbd_unmap(sl, dfl); + dfl_free(dfl); + 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); } 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 a402ad0ee3..f3ab44f8f4 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 @@ -21,12 +21,14 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ #ifndef _STMF_SBD_H #define _STMF_SBD_H +#include <sys/dkio.h> + #ifdef __cplusplus extern "C" { #endif @@ -300,7 +302,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); +int sbd_unmap(sbd_lu_t *sl, dkioc_free_list_t *dfl); #ifdef __cplusplus } diff --git a/usr/src/uts/common/io/sata/impl/sata.c b/usr/src/uts/common/io/sata/impl/sata.c index 17c6da2813..29b7cf2005 100644 --- a/usr/src/uts/common/io/sata/impl/sata.c +++ b/usr/src/uts/common/io/sata/impl/sata.c @@ -23,7 +23,7 @@ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ /* - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. * Copyright 2016 Argo Technologies SA * Copyright (c) 2018, Joyent, Inc. */ @@ -4851,7 +4851,7 @@ sata_txlt_unmap(sata_pkt_txlate_t *spx) bdlen = scsipkt->pkt_cdbp[7]; bdlen = (bdlen << 8) + scsipkt->pkt_cdbp[8] - paramlen; if ((bdlen < 0) || ((bdlen % 16) != 0) || - (bdlen > (bp->b_bcount - paramlen))) { + ((bp != NULL) && (bdlen > (bp->b_bcount - paramlen)))) { SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst, "sata_txlt_unmap: invalid block descriptor length", NULL); mutex_exit(cport_mutex); diff --git a/usr/src/uts/common/io/scsi/targets/sd.c b/usr/src/uts/common/io/scsi/targets/sd.c index 3a3494aa50..550d1afe23 100644 --- a/usr/src/uts/common/io/scsi/targets/sd.c +++ b/usr/src/uts/common/io/scsi/targets/sd.c @@ -53,6 +53,7 @@ #include <sys/efi_partition.h> #include <sys/var.h> #include <sys/aio_req.h> +#include <sys/dkioc_free_util.h> #ifdef __lock_lint #define _LP64 @@ -1152,6 +1153,24 @@ static int sd_pm_idletime = 1; #endif /* #if (defined(__fibre)) */ +typedef struct unmap_param_hdr_s { + uint16_t uph_data_len; + uint16_t uph_descr_data_len; + uint32_t uph_reserved; +} unmap_param_hdr_t; + +typedef struct unmap_blk_descr_s { + uint64_t ubd_lba; + uint32_t ubd_lba_cnt; + uint32_t ubd_reserved; +} unmap_blk_descr_t; + +/* Max number of block descriptors in UNMAP command */ +#define SD_UNMAP_MAX_DESCR \ + ((UINT16_MAX - sizeof (unmap_param_hdr_t)) / sizeof (unmap_blk_descr_t)) +/* Max size of the UNMAP parameter list in bytes */ +#define SD_UNMAP_PARAM_LIST_MAXSZ (sizeof (unmap_param_hdr_t) + \ + SD_UNMAP_MAX_DESCR * sizeof (unmap_blk_descr_t)) int _init(void); int _fini(void); @@ -1534,6 +1553,8 @@ static int sd_send_scsi_PERSISTENT_RESERVE_OUT(sd_ssc_t *ssc, static int sd_send_scsi_SYNCHRONIZE_CACHE(struct sd_lun *un, struct dk_callback *dkc); static int sd_send_scsi_SYNCHRONIZE_CACHE_biodone(struct buf *bp); +static int sd_send_scsi_UNMAP(dev_t dev, sd_ssc_t *ssc, dkioc_free_list_t *dfl, + int flag); static int sd_send_scsi_GET_CONFIGURATION(sd_ssc_t *ssc, struct uscsi_cmd *ucmdbuf, uchar_t *rqbuf, uint_t rqbuflen, uchar_t *bufaddr, uint_t buflen, int path_flag); @@ -3481,8 +3502,8 @@ sd_set_mmc_caps(sd_ssc_t *ssc) * The following warning occurs due to the KVM CD-ROM * mishandling the multi-media commands. Ignore it. * scsi_log(SD_DEVINFO(un), sd_label, CE_WARN, - * "sd_set_mmc_caps: Mode Sense returned " - * "invalid block descriptor length\n"); + * "sd_set_mmc_caps: Mode Sense returned " + * "invalid block descriptor length\n"); */ kmem_free(buf, BUFLEN_MODE_CDROM_CAP); return; @@ -5372,6 +5393,91 @@ sd_update_block_info(struct sd_lun *un, uint32_t lbasize, uint64_t capacity) } } +/* + * Parses the SCSI Block Limits VPD page (0xB0). It's legal to pass NULL for + * vpd_pg, in which case all the block limits will be reset to the defaults. + */ +static void +sd_parse_blk_limits_vpd(struct sd_lun *un, uchar_t *vpd_pg) +{ + sd_blk_limits_t *lim = &un->un_blk_lim; + unsigned pg_len; + + if (vpd_pg != NULL) + pg_len = BE_IN16(&vpd_pg[2]); + else + pg_len = 0; + + /* Block Limits VPD can be 16 bytes or 64 bytes long - support both */ + if (pg_len >= 0x10) { + lim->lim_opt_xfer_len_gran = BE_IN16(&vpd_pg[6]); + lim->lim_max_xfer_len = BE_IN32(&vpd_pg[8]); + lim->lim_opt_xfer_len = BE_IN32(&vpd_pg[12]); + + /* Zero means not reported, so use "unlimited" */ + if (lim->lim_max_xfer_len == 0) + lim->lim_max_xfer_len = UINT32_MAX; + if (lim->lim_opt_xfer_len == 0) + lim->lim_opt_xfer_len = UINT32_MAX; + } else { + lim->lim_opt_xfer_len_gran = 0; + lim->lim_max_xfer_len = UINT32_MAX; + lim->lim_opt_xfer_len = UINT32_MAX; + } + if (pg_len >= 0x3c) { + lim->lim_max_pfetch_len = BE_IN32(&vpd_pg[16]); + /* + * A zero in either of the following two fields indicates lack + * of UNMAP support. + */ + lim->lim_max_unmap_lba_cnt = BE_IN32(&vpd_pg[20]); + lim->lim_max_unmap_descr_cnt = BE_IN32(&vpd_pg[24]); + lim->lim_opt_unmap_gran = BE_IN32(&vpd_pg[28]); + if ((vpd_pg[32] >> 7) == 1) { + lim->lim_unmap_gran_align = + ((vpd_pg[32] & 0x7f) << 24) | (vpd_pg[33] << 16) | + (vpd_pg[34] << 8) | vpd_pg[35]; + } else { + lim->lim_unmap_gran_align = 0; + } + lim->lim_max_write_same_len = BE_IN64(&vpd_pg[36]); + } else { + lim->lim_max_pfetch_len = UINT32_MAX; + lim->lim_max_unmap_lba_cnt = UINT32_MAX; + lim->lim_max_unmap_descr_cnt = SD_UNMAP_MAX_DESCR; + lim->lim_opt_unmap_gran = 0; + lim->lim_unmap_gran_align = 0; + lim->lim_max_write_same_len = UINT64_MAX; + } +} + +/* + * Collects VPD page B0 data if available (block limits). If the data is + * not available or querying the device failed, we revert to the defaults. + */ +static void +sd_setup_blk_limits(sd_ssc_t *ssc) +{ + struct sd_lun *un = ssc->ssc_un; + uchar_t *inqB0 = NULL; + size_t inqB0_resid = 0; + int rval; + + if (un->un_vpd_page_mask & SD_VPD_BLK_LIMITS_PG) { + inqB0 = kmem_zalloc(MAX_INQUIRY_SIZE, KM_SLEEP); + rval = sd_send_scsi_INQUIRY(ssc, inqB0, MAX_INQUIRY_SIZE, 0x01, + 0xB0, &inqB0_resid); + if (rval != 0) { + sd_ssc_assessment(ssc, SD_FMT_IGNORE); + kmem_free(inqB0, MAX_INQUIRY_SIZE); + inqB0 = NULL; + } + } + /* passing NULL inqB0 will reset to defaults */ + sd_parse_blk_limits_vpd(ssc->ssc_un, inqB0); + if (inqB0) + kmem_free(inqB0, MAX_INQUIRY_SIZE); +} /* * Function: sd_register_devid @@ -5901,6 +6007,9 @@ sd_check_vpd_page_support(sd_ssc_t *ssc) case 0x86: un->un_vpd_page_mask |= SD_VPD_EXTENDED_DATA_PG; break; + case 0xB0: + un->un_vpd_page_mask |= SD_VPD_BLK_LIMITS_PG; + break; case 0xB1: un->un_vpd_page_mask |= SD_VPD_DEV_CHARACTER_PG; break; @@ -7805,6 +7914,27 @@ sd_unit_attach(dev_info_t *devi) SD_TRACE(SD_LOG_ATTACH_DETACH, un, "sd_unit_attach: un:0x%p un_stats created\n", un); + un->un_unmapstats_ks = kstat_create(sd_label, instance, "unmapstats", + "misc", KSTAT_TYPE_NAMED, sizeof (*un->un_unmapstats) / + sizeof (kstat_named_t), 0); + if (un->un_unmapstats_ks) { + un->un_unmapstats = un->un_unmapstats_ks->ks_data; + + kstat_named_init(&un->un_unmapstats->us_cmds, + "commands", KSTAT_DATA_UINT64); + kstat_named_init(&un->un_unmapstats->us_errs, + "errors", KSTAT_DATA_UINT64); + kstat_named_init(&un->un_unmapstats->us_extents, + "extents", KSTAT_DATA_UINT64); + kstat_named_init(&un->un_unmapstats->us_bytes, + "bytes", KSTAT_DATA_UINT64); + + kstat_install(un->un_unmapstats_ks); + } else { + cmn_err(CE_NOTE, "!Cannot create unmap kstats for disk %d", + instance); + } + sd_create_errstats(un, instance); if (un->un_errstats == NULL) { goto create_errstats_failed; @@ -8442,6 +8572,7 @@ sd_unit_attach(dev_info_t *devi) SD_TRACE(SD_LOG_ATTACH_DETACH, un, "sd_unit_attach: un:0x%p errstats set\n", un); + sd_setup_blk_limits(ssc); /* * After successfully attaching an instance, we record the information @@ -9015,6 +9146,11 @@ sd_unit_detach(dev_info_t *devi) kstat_delete(un->un_stats); un->un_stats = NULL; } + if (un->un_unmapstats != NULL) { + kstat_delete(un->un_unmapstats_ks); + un->un_unmapstats_ks = NULL; + un->un_unmapstats = NULL; + } if (un->un_errstats != NULL) { kstat_delete(un->un_errstats); un->un_errstats = NULL; @@ -20392,11 +20528,21 @@ sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp, uint32_t *lbap, * (MSB in byte:8 & LSB in byte:11) * * byte 13: LOGICAL BLOCKS PER PHYSICAL BLOCK EXPONENT + * + * byte 14: + * bit 7: Thin-Provisioning Enabled + * bit 6: Thin-Provisioning Read Zeros */ capacity = BE_64(capacity16_buf[0]); lbasize = BE_32(*(uint32_t *)&capacity16_buf[1]); lbpb_exp = (BE_64(capacity16_buf[1]) >> 16) & 0x0f; + un->un_thin_flags = 0; + if (((uint8_t *)capacity16_buf)[14] & (1 << 7)) + un->un_thin_flags |= SD_THIN_PROV_ENABLED; + if (((uint8_t *)capacity16_buf)[14] & (1 << 6)) + un->un_thin_flags |= SD_THIN_PROV_READ_ZEROS; + pbsize = lbasize << lbpb_exp; /* @@ -21451,6 +21597,237 @@ done: return (status); } +/* + * Issues a single SCSI UNMAP command with a prepared UNMAP parameter list. + * Returns zero on success, or the non-zero command error code on failure. + */ +static int +sd_send_scsi_UNMAP_issue_one(sd_ssc_t *ssc, unmap_param_hdr_t *uph, + uint64_t num_descr, uint64_t bytes) +{ + struct sd_lun *un = ssc->ssc_un; + struct scsi_extended_sense sense_buf; + union scsi_cdb cdb; + struct uscsi_cmd ucmd_buf; + int status; + const uint64_t param_size = sizeof (unmap_param_hdr_t) + + num_descr * sizeof (unmap_blk_descr_t); + + ASSERT3U(param_size - 2, <=, UINT16_MAX); + uph->uph_data_len = BE_16(param_size - 2); + uph->uph_descr_data_len = BE_16(param_size - 8); + + bzero(&cdb, sizeof (cdb)); + bzero(&ucmd_buf, sizeof (ucmd_buf)); + bzero(&sense_buf, sizeof (struct scsi_extended_sense)); + + cdb.scc_cmd = SCMD_UNMAP; + FORMG1COUNT(&cdb, param_size); + + ucmd_buf.uscsi_cdb = (char *)&cdb; + ucmd_buf.uscsi_cdblen = (uchar_t)CDB_GROUP1; + ucmd_buf.uscsi_bufaddr = (caddr_t)uph; + ucmd_buf.uscsi_buflen = param_size; + ucmd_buf.uscsi_rqbuf = (caddr_t)&sense_buf; + ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense); + ucmd_buf.uscsi_flags = USCSI_WRITE | USCSI_RQENABLE | USCSI_SILENT; + ucmd_buf.uscsi_timeout = un->un_cmd_timeout; + + status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL, UIO_SYSSPACE, + SD_PATH_STANDARD); + + switch (status) { + case 0: + sd_ssc_assessment(ssc, SD_FMT_STANDARD); + + if (un->un_unmapstats) { + atomic_inc_64(&un->un_unmapstats->us_cmds.value.ui64); + atomic_add_64(&un->un_unmapstats->us_extents.value.ui64, + num_descr); + atomic_add_64(&un->un_unmapstats->us_bytes.value.ui64, + bytes); + } + break; /* Success! */ + case EIO: + if (un->un_unmapstats) + atomic_inc_64(&un->un_unmapstats->us_errs.value.ui64); + switch (ucmd_buf.uscsi_status) { + case STATUS_RESERVATION_CONFLICT: + status = EACCES; + break; + default: + break; + } + break; + default: + if (un->un_unmapstats) + atomic_inc_64(&un->un_unmapstats->us_errs.value.ui64); + break; + } + + return (status); +} + +/* + * Returns a pointer to the i'th block descriptor inside an UNMAP param list. + */ +static inline unmap_blk_descr_t * +UNMAP_blk_descr_i(void *buf, size_t i) +{ + return ((unmap_blk_descr_t *)((uintptr_t)buf + + sizeof (unmap_param_hdr_t) + (i * sizeof (unmap_blk_descr_t)))); +} + +/* + * Takes the list of extents from sd_send_scsi_UNMAP, chops it up, prepares + * UNMAP block descriptors and issues individual SCSI UNMAP commands. While + * doing so we consult the block limits to determine at most how many + * extents and LBAs we can UNMAP in one command. + * If a command fails for whatever, reason, extent list processing is aborted + * and the failed command's status is returned. Otherwise returns 0 on + * success. + */ +static int +sd_send_scsi_UNMAP_issue(dev_t dev, sd_ssc_t *ssc, const dkioc_free_list_t *dfl) +{ + struct sd_lun *un = ssc->ssc_un; + unmap_param_hdr_t *uph; + sd_blk_limits_t *lim = &un->un_blk_lim; + int rval = 0; + int partition; + /* partition offset & length in system blocks */ + diskaddr_t part_off_sysblks = 0, part_len_sysblks = 0; + uint64_t part_off, part_len; + uint64_t descr_cnt_lim, byte_cnt_lim; + uint64_t descr_issued = 0, bytes_issued = 0; + + uph = kmem_zalloc(SD_UNMAP_PARAM_LIST_MAXSZ, KM_SLEEP); + + partition = SDPART(dev); + rval = cmlb_partinfo(un->un_cmlbhandle, partition, &part_len_sysblks, + &part_off_sysblks, NULL, NULL, (void *)SD_PATH_DIRECT); + if (rval != 0) + goto out; + part_off = SD_SYSBLOCKS2BYTES(part_off_sysblks); + part_len = SD_SYSBLOCKS2BYTES(part_len_sysblks); + + ASSERT(un->un_blk_lim.lim_max_unmap_lba_cnt != 0); + ASSERT(un->un_blk_lim.lim_max_unmap_descr_cnt != 0); + /* Spec says 0xffffffff are special values, so compute maximums. */ + byte_cnt_lim = lim->lim_max_unmap_lba_cnt < UINT32_MAX ? + (uint64_t)lim->lim_max_unmap_lba_cnt * un->un_tgt_blocksize : + UINT64_MAX; + descr_cnt_lim = MIN(lim->lim_max_unmap_descr_cnt, SD_UNMAP_MAX_DESCR); + + if (dfl->dfl_offset >= part_len) { + rval = SET_ERROR(EINVAL); + goto out; + } + + for (size_t i = 0; i < dfl->dfl_num_exts; i++) { + const dkioc_free_list_ext_t *ext = &dfl->dfl_exts[i]; + uint64_t ext_start = ext->dfle_start; + uint64_t ext_length = ext->dfle_length; + + while (ext_length > 0) { + unmap_blk_descr_t *ubd; + /* Respect device limit on LBA count per command */ + uint64_t len = MIN(MIN(ext_length, byte_cnt_lim - + bytes_issued), SD_TGTBLOCKS2BYTES(un, UINT32_MAX)); + + /* check partition limits */ + if (ext_start >= part_len || + ext_start + len < ext_start || + dfl->dfl_offset + ext_start + len < + dfl->dfl_offset || + dfl->dfl_offset + ext_start + len > part_len) { + rval = SET_ERROR(EINVAL); + goto out; + } + + ASSERT3U(descr_issued, <, descr_cnt_lim); + ASSERT3U(bytes_issued, <, byte_cnt_lim); + ubd = UNMAP_blk_descr_i(uph, descr_issued); + + /* adjust in-partition addresses to be device-global */ + ubd->ubd_lba = BE_64(SD_BYTES2TGTBLOCKS(un, + dfl->dfl_offset + ext_start + part_off)); + ubd->ubd_lba_cnt = BE_32(SD_BYTES2TGTBLOCKS(un, len)); + + descr_issued++; + bytes_issued += len; + + /* Issue command when device limits reached */ + if (descr_issued == descr_cnt_lim || + bytes_issued == byte_cnt_lim) { + rval = sd_send_scsi_UNMAP_issue_one(ssc, uph, + descr_issued, bytes_issued); + if (rval != 0) + goto out; + descr_issued = 0; + bytes_issued = 0; + } + + ext_start += len; + ext_length -= len; + } + } + + if (descr_issued > 0) { + /* issue last command */ + rval = sd_send_scsi_UNMAP_issue_one(ssc, uph, descr_issued, + bytes_issued); + } + +out: + kmem_free(uph, SD_UNMAP_PARAM_LIST_MAXSZ); + return (rval); +} + +/* + * Issues one or several UNMAP commands based on a list of extents to be + * unmapped. The internal multi-command processing is hidden, as the exact + * number of commands and extents per command is limited by both SCSI + * command syntax and device limits (as expressed in the SCSI Block Limits + * VPD page and un_blk_lim in struct sd_lun). + * Returns zero on success, or the error code of the first failed SCSI UNMAP + * command. + */ +static int +sd_send_scsi_UNMAP(dev_t dev, sd_ssc_t *ssc, dkioc_free_list_t *dfl, int flag) +{ + struct sd_lun *un = ssc->ssc_un; + int rval = 0; + + ASSERT(!mutex_owned(SD_MUTEX(un))); + ASSERT(dfl != NULL); + + /* Per spec, any of these conditions signals lack of UNMAP support. */ + if (!(un->un_thin_flags & SD_THIN_PROV_ENABLED) || + un->un_blk_lim.lim_max_unmap_descr_cnt == 0 || + un->un_blk_lim.lim_max_unmap_lba_cnt == 0) { + return (SET_ERROR(ENOTSUP)); + } + + /* For userspace calls we must copy in. */ + if (!(flag & FKIOCTL)) { + int err = dfl_copyin(dfl, &dfl, flag, KM_SLEEP); + if (err != 0) + return (err); + } else if (dfl->dfl_num_exts > DFL_COPYIN_MAX_EXTS) { + ASSERT3U(dfl->dfl_num_exts, <=, DFL_COPYIN_MAX_EXTS); + return (SET_ERROR(EINVAL)); + } + + rval = sd_send_scsi_UNMAP_issue(dev, ssc, dfl); + + if (!(flag & FKIOCTL)) { + dfl_free(dfl); + dfl = NULL; + } + + return (rval); +} /* * Function: sd_send_scsi_GET_CONFIGURATION @@ -23206,6 +23583,22 @@ skip_ready_valid: } break; + case DKIOCFREE: + { + dkioc_free_list_t *dfl = (dkioc_free_list_t *)arg; + + /* bad ioctls shouldn't panic */ + if (dfl == NULL) { + /* check kernel callers strictly in debug */ + ASSERT0(flag & FKIOCTL); + err = SET_ERROR(EINVAL); + break; + } + /* synchronous UNMAP request */ + err = sd_send_scsi_UNMAP(dev, ssc, dfl, flag); + } + break; + case DKIOCGETWCE: { int wce; diff --git a/usr/src/uts/common/os/dkioc_free_util.c b/usr/src/uts/common/os/dkioc_free_util.c new file mode 100644 index 0000000000..85470f7e28 --- /dev/null +++ b/usr/src/uts/common/os/dkioc_free_util.c @@ -0,0 +1,80 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2017 Nexenta Inc. All rights reserved. + */ + +/* needed when building libzpool */ +#ifndef _KERNEL +#include <sys/zfs_context.h> +#endif + +#include <sys/sunddi.h> +#include <sys/dkio.h> +#include <sys/dkioc_free_util.h> +#include <sys/sysmacros.h> +#include <sys/file.h> +#include <sys/sdt.h> + +/* + * Copy-in convenience function for variable-length dkioc_free_list_t + * structures. The pointer to be copied from is in `arg' (may be a pointer + * to userspace). A new buffer is allocated and a pointer to it is placed + * in `out'. `ddi_flags' indicates whether the pointer is from user- + * or kernelspace (FKIOCTL) and `kmflags' are the flags passed to + * kmem_zalloc when allocating the new structure. + * Returns 0 on success, or an errno on failure. + */ +int +dfl_copyin(void *arg, dkioc_free_list_t **out, int ddi_flags, int kmflags) +{ + dkioc_free_list_t *dfl; + + if (ddi_flags & FKIOCTL) { + dkioc_free_list_t *dfl_in = arg; + + if (dfl_in->dfl_num_exts == 0 || + dfl_in->dfl_num_exts > DFL_COPYIN_MAX_EXTS) + return (SET_ERROR(EINVAL)); + dfl = kmem_alloc(DFL_SZ(dfl_in->dfl_num_exts), kmflags); + if (dfl == NULL) + return (SET_ERROR(ENOMEM)); + bcopy(dfl_in, dfl, DFL_SZ(dfl_in->dfl_num_exts)); + } else { + uint64_t num_exts; + + if (ddi_copyin(((uint8_t *)arg) + offsetof(dkioc_free_list_t, + dfl_num_exts), &num_exts, sizeof (num_exts), + ddi_flags) != 0) + return (SET_ERROR(EFAULT)); + if (num_exts == 0 || num_exts > DFL_COPYIN_MAX_EXTS) + return (SET_ERROR(EINVAL)); + dfl = kmem_alloc(DFL_SZ(num_exts), kmflags); + if (dfl == NULL) + return (SET_ERROR(ENOMEM)); + if (ddi_copyin(arg, dfl, DFL_SZ(num_exts), ddi_flags) != 0 || + dfl->dfl_num_exts != num_exts) { + kmem_free(dfl, DFL_SZ(num_exts)); + return (SET_ERROR(EFAULT)); + } + } + + *out = dfl; + return (0); +} + +/* Frees a variable-length dkioc_free_list_t structure. */ +void +dfl_free(dkioc_free_list_t *dfl) +{ + kmem_free(dfl, DFL_SZ(dfl->dfl_num_exts)); +} diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index 0fa800d39e..787774e03a 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -26,7 +26,7 @@ # Copyright 2015, Joyent, Inc. All rights reserved. # Copyright 2013 Saso Kiselkov. All rights reserved. # Copyright 2015 Igor Kozhukhov <ikozhukhov@gmail.com> -# Copyright 2016 Nexenta Systems, Inc. +# Copyright 2017 Nexenta Systems, Inc. # Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> # @@ -189,6 +189,7 @@ CHKHDRS= \ disp.h \ dkbad.h \ dkio.h \ + dkioc_free_util.h \ dklabel.h \ dl.h \ dlpi.h \ diff --git a/usr/src/uts/common/sys/dkio.h b/usr/src/uts/common/sys/dkio.h index 3d1a839164..dcb817fc72 100644 --- a/usr/src/uts/common/sys/dkio.h +++ b/usr/src/uts/common/sys/dkio.h @@ -22,7 +22,7 @@ /* * Copyright (c) 1982, 2010, Oracle and/or its affiliates. All rights reserved. * - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. */ @@ -523,17 +523,25 @@ typedef struct dk_updatefw_32 { /* * ioctl to free space (e.g. SCSI UNMAP) off a disk. + * Pass a dkioc_free_list_t containing a list of extents to be freed. */ #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. */ +typedef struct dkioc_free_list_ext_s { + uint64_t dfle_start; + uint64_t dfle_length; +} dkioc_free_list_ext_t; + +typedef struct dkioc_free_list_s { + uint64_t dfl_flags; + uint64_t dfl_num_exts; + uint64_t dfl_offset; + dkioc_free_list_ext_t dfl_exts[]; +} dkioc_free_list_t; +#define DFL_SZ(num_exts) \ + (sizeof (dkioc_free_list_t) + \ + (num_exts) * sizeof (dkioc_free_list_ext_t)) #ifdef __cplusplus } diff --git a/usr/src/uts/common/sys/dkioc_free_util.h b/usr/src/uts/common/sys/dkioc_free_util.h new file mode 100644 index 0000000000..9e83ab3bff --- /dev/null +++ b/usr/src/uts/common/sys/dkioc_free_util.h @@ -0,0 +1,34 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2017 Nexenta Inc. All rights reserved. + */ + +#ifndef _SYS_DKIOC_FREE_UTIL_H +#define _SYS_DKIOC_FREE_UTIL_H + +#include <sys/dkio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define DFL_COPYIN_MAX_EXTS (1024 * 1024) + +int dfl_copyin(void *arg, dkioc_free_list_t **out, int ddi_flags, int kmflags); +void dfl_free(dkioc_free_list_t *dfl); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_DKIOC_FREE_UTIL_H */ diff --git a/usr/src/uts/common/sys/scsi/targets/sddef.h b/usr/src/uts/common/sys/scsi/targets/sddef.h index da9f25c4ae..30c6ae54d1 100644 --- a/usr/src/uts/common/sys/scsi/targets/sddef.h +++ b/usr/src/uts/common/sys/scsi/targets/sddef.h @@ -23,7 +23,7 @@ */ /* * Copyright 2011 cyril.galibern@opensvc.com - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ #ifndef _SYS_SCSI_TARGETS_SDDEF_H @@ -215,6 +215,35 @@ struct sd_mapblocksize_info { _NOTE(SCHEME_PROTECTS_DATA("unshared data", sd_mapblocksize_info)) +/* Thin-provisioning (UNMAP) flags for un_thin_flags. */ +enum { + SD_THIN_PROV_ENABLED = 1 << 0, /* UNMAP available */ + SD_THIN_PROV_READ_ZEROS = 1 << 1 /* unmapped blk = zeros */ +}; + +/* + * Device limits as read from the Block Limits VPD page (0xB0). If the page + * is unavailable, will be filled with some defaults. + */ +typedef struct sd_blk_limits_s { + uint16_t lim_opt_xfer_len_gran; + uint32_t lim_max_xfer_len; + uint32_t lim_opt_xfer_len; + uint32_t lim_max_pfetch_len; + uint32_t lim_max_unmap_lba_cnt; + uint32_t lim_max_unmap_descr_cnt; + uint32_t lim_opt_unmap_gran; + uint32_t lim_unmap_gran_align; + uint64_t lim_max_write_same_len; +} sd_blk_limits_t; + +typedef struct sd_unmapstats { + kstat_named_t us_cmds; + kstat_named_t us_errs; + kstat_named_t us_extents; + kstat_named_t us_bytes; +} sd_unmapstats_t; + /* * sd_lun: The main data structure for a scsi logical unit. * Stored as the softstate structure for each device. @@ -356,6 +385,8 @@ struct sd_lun { union ocmap un_ocmap; /* open partition map */ struct kstat *un_pstats[NSDMAP]; /* partition statistics */ struct kstat *un_stats; /* disk statistics */ + sd_unmapstats_t *un_unmapstats; /* UNMAP stats structure */ + struct kstat *un_unmapstats_ks; /* UNMAP kstat */ kstat_t *un_errstats; /* for error statistics */ uint64_t un_exclopen; /* exclusive open bitmask */ ddi_devid_t un_devid; /* device id */ @@ -508,6 +539,12 @@ struct sd_lun { uint64_t un_rmw_incre_count; /* count I/O */ timeout_id_t un_rmw_msg_timeid; /* for RMW message control */ + /* Thin provisioning support (see SD_THIN_PROV_*) */ + uint64_t un_thin_flags; + + /* Block limits (0xB0 VPD page) */ + sd_blk_limits_t un_blk_lim; + /* For timeout callback to issue a START STOP UNIT command */ timeout_id_t un_startstop_timeid; @@ -2385,7 +2422,8 @@ typedef struct disk_power_attr_pc { #define SD_VPD_ASCII_OP_PG 0x08 /* 0x82 - ASCII Op Defs */ #define SD_VPD_DEVID_WWN_PG 0x10 /* 0x83 - Device Identification */ #define SD_VPD_EXTENDED_DATA_PG 0x80 /* 0x86 - Extended data about the lun */ -#define SD_VPD_DEV_CHARACTER_PG 0x400 /* 0xB1 - Device Characteristics */ +#define SD_VPD_BLK_LIMITS_PG 0x400 /* 0xB0 - Block Limits */ +#define SD_VPD_DEV_CHARACTER_PG 0x800 /* 0xB1 - Device Characteristics */ /* * Non-volatile cache support |