Print this page
NEX-6832 fcsm module's debug level default should be 0 (cstyle fix)
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-7503 backport illumos #7307
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
NEX-7048 COMSTAR MODE_SENSE support is broken
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5428 Backout the 5.0 changes
NEX-2937 Continuous write_same starves all other commands
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
NEX-4707 memory leak in stmf_sbd`sbd_attach() on successful property lookup
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Marcel Telka <marcel.telka@nexenta.com>
NEX-3508 CLONE - Port NEX-2946 Add UNMAP/TRIM functionality to ZFS and illumos
Reviewed by: Josef Sipek <josef.sipek@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Conflicts:
usr/src/uts/common/io/scsi/targets/sd.c
usr/src/uts/common/sys/scsi/targets/sddef.h
NEX-3111 Comstar does not pass cstyle and hdrchk
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Tony Nguyen <tony.nguyen@nexenta.com>
NEX-3023 Panics and hangs when using write_same and compare_and_write
Review by: Bayard Bell <bayard.bell@nexenta.com>
Review by: Rick McNeal <rick.mcneal@nexenta.com>
Review by: Jean McCormack <jean.mccormack@nexenta.com>
Approved by: Jean McCormack <jean.mccormack@nexenta.com>
Related bug: NEX-2723 Kernel panic in xfer_completion code for write_same (0x93) and compare_and_write (0x89)
NEX-1965 Page fault at netbios_first_level_name_decode+0xbb
Support simultaneous compare_and_write operations for VAAI
Bug IDs SUP-505
SUP-1768
SUP-1928
Code Reviewers:
Sarah Jelinek
Jeffry Molanus
Albert Lee
Harold Shaw
NEX-988 itask_lu_[read|write]_time was inadvertently removed by the Illumos 3862 fix
re #12618 rb4053 Creating LU unconditionally enables write cache on backing store device
re #7936 rb3706 Support for COMSTAR/OEM
re #8002 rb3706 Allow setting iSCSI vendor ID via stmf_sbd.conf
re #11454 rb3750 Fix inconsistent vid/pid in stmf
Re #6790 backspace should perform delete on console
VAAI (XXX ATS support for COMSTAR, YYY Block-copy support for COMSTAR)
*** 19,34 ****
* CDDL HEADER END
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
*/
- #include <sys/sysmacros.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/scsi/scsi.h>
--- 19,34 ----
* CDDL HEADER END
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/conf.h>
+ #include <sys/list.h>
#include <sys/file.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/scsi/scsi.h>
*** 54,63 ****
--- 54,67 ----
#define SBD_IS_ZVOL(zvol) (strncmp("/dev/zvol", zvol, 9))
extern sbd_status_t sbd_pgr_meta_init(sbd_lu_t *sl);
extern sbd_status_t sbd_pgr_meta_load(sbd_lu_t *sl);
extern void sbd_pgr_reset(sbd_lu_t *sl);
+ extern int HardwareAcceleratedLocking;
+ extern int HardwareAcceleratedInit;
+ extern int HardwareAcceleratedMove;
+ extern uint8_t sbd_unmap_enable;
static int sbd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
void **result);
static int sbd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
static int sbd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
*** 107,119 ****
static stmf_lu_provider_t *sbd_lp;
static sbd_lu_t *sbd_lu_list = NULL;
static kmutex_t sbd_lock;
static dev_info_t *sbd_dip;
static uint32_t sbd_lu_count = 0;
/* Global property settings for the logical unit */
! char sbd_vendor_id[] = "SUN ";
char sbd_product_id[] = "COMSTAR ";
char sbd_revision[] = "1.0 ";
char *sbd_mgmt_url = NULL;
uint16_t sbd_mgmt_url_alloc_size = 0;
krwlock_t sbd_global_prop_lock;
--- 111,124 ----
static stmf_lu_provider_t *sbd_lp;
static sbd_lu_t *sbd_lu_list = NULL;
static kmutex_t sbd_lock;
static dev_info_t *sbd_dip;
static uint32_t sbd_lu_count = 0;
+ uint8_t sbd_enable_unmap_sync = 0;
/* Global property settings for the logical unit */
! char sbd_vendor_id[] = "NEXENTA ";
char sbd_product_id[] = "COMSTAR ";
char sbd_revision[] = "1.0 ";
char *sbd_mgmt_url = NULL;
uint16_t sbd_mgmt_url_alloc_size = 0;
krwlock_t sbd_global_prop_lock;
*** 153,163 ****
&sbd_cb_ops,
NULL, /* bus_ops */
NULL /* power */
};
! #define SBD_NAME "COMSTAR SBD"
static struct modldrv modldrv = {
&mod_driverops,
SBD_NAME,
&sbd_ops
--- 158,172 ----
&sbd_cb_ops,
NULL, /* bus_ops */
NULL /* power */
};
! #ifdef DEBUG
! #define SBD_NAME "COMSTAR SBD+ " __DATE__ " " __TIME__ " DEBUG"
! #else
! #define SBD_NAME "COMSTAR SBD+"
! #endif
static struct modldrv modldrv = {
&mod_driverops,
SBD_NAME,
&sbd_ops
*** 192,201 ****
--- 201,218 ----
stmf_free(sbd_lp);
return (EINVAL);
}
mutex_init(&sbd_lock, NULL, MUTEX_DRIVER, NULL);
rw_init(&sbd_global_prop_lock, NULL, RW_DRIVER, NULL);
+
+ if (HardwareAcceleratedLocking == 0)
+ cmn_err(CE_NOTE, "HardwareAcceleratedLocking Disabled");
+ if (HardwareAcceleratedMove == 0)
+ cmn_err(CE_NOTE, "HardwareAcceleratedMove Disabled");
+ if (HardwareAcceleratedInit == 0)
+ cmn_err(CE_NOTE, "HardwareAcceleratedInit Disabled");
+
return (0);
}
int
_fini(void)
*** 270,288 ****
--- 287,324 ----
}
static int
sbd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
+ char *prop;
+
switch (cmd) {
case DDI_ATTACH:
sbd_dip = dip;
if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0,
DDI_NT_STMF_LP, 0) != DDI_SUCCESS) {
break;
}
ddi_report_dev(dip);
+
+ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "vendor-id", &prop) == DDI_SUCCESS) {
+ (void) snprintf(sbd_vendor_id, 9, "%s%8s", prop, "");
+ ddi_prop_free(prop);
+ }
+ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "product-id", &prop) == DDI_SUCCESS) {
+ (void) snprintf(sbd_product_id, 17, "%s%16s", prop, "");
+ ddi_prop_free(prop);
+ }
+ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "revision", &prop) == DDI_SUCCESS) {
+ (void) snprintf(sbd_revision, 5, "%s%4s", prop, "");
+ ddi_prop_free(prop);
+ }
+
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
*** 1394,1404 ****
* 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;
--- 1430,1443 ----
* Will scribble SL_UNMAP_ENABLED into sl_flags if we succeed.
*/
static void
do_unmap_setup(sbd_lu_t *sl)
{
! if (sbd_unmap_enable == 0) {
! sl->sl_flags &= ~(SL_UNMAP_ENABLED);
! return;
! }
if ((sl->sl_flags & SL_ZFS_META) == 0)
return; /* No UNMAP for you. */
sl->sl_flags |= SL_UNMAP_ENABLED;
*** 1439,1450 ****
--- 1478,1491 ----
lu->lu_new_task = sbd_new_task;
lu->lu_dbuf_xfer_done = sbd_dbuf_xfer_done;
lu->lu_send_status_done = sbd_send_status_done;
lu->lu_task_free = sbd_task_free;
lu->lu_abort = sbd_abort;
+ lu->lu_task_poll = sbd_task_poll;
lu->lu_dbuf_free = sbd_dbuf_free;
lu->lu_ctl = sbd_ctl;
+ lu->lu_task_done = sbd_ats_remove_by_task;
lu->lu_info = sbd_info;
sl->sl_state = STMF_STATE_OFFLINE;
if ((ret = stmf_register_lu(lu)) != STMF_SUCCESS) {
stmf_trace(0, "Failed to register with framework, ret=%llx",
*** 1453,1462 ****
--- 1494,1509 ----
*err_ret = SBD_RET_GUID_ALREADY_REGISTERED;
}
return (EIO);
}
+ /*
+ * setup the ATS (compare and write) lists to handle multiple
+ * ATS commands simultaneously
+ */
+ list_create(&sl->sl_ats_io_list, sizeof (ats_state_t),
+ offsetof(ats_state_t, as_next));
*err_ret = 0;
return (0);
}
int
*** 1559,1568 ****
--- 1606,1616 ----
}
} else {
sl->sl_lu_size = vattr.va_size;
}
}
+
if (sl->sl_lu_size < SBD_MIN_LU_SIZE) {
*err_ret = SBD_RET_FILE_SIZE_ERROR;
ret = EINVAL;
goto odf_close_data_and_exit;
}
*** 1835,1845 ****
}
if (slu->slu_write_protected) {
sl->sl_flags |= SL_WRITE_PROTECTED;
}
if (slu->slu_blksize_valid) {
! if (!ISP2(slu->slu_blksize) ||
(slu->slu_blksize > (32 * 1024)) ||
(slu->slu_blksize == 0)) {
*err_ret = SBD_RET_INVALID_BLKSIZE;
ret = EINVAL;
goto scm_err_out;
--- 1883,1893 ----
}
if (slu->slu_write_protected) {
sl->sl_flags |= SL_WRITE_PROTECTED;
}
if (slu->slu_blksize_valid) {
! if ((slu->slu_blksize & (slu->slu_blksize - 1)) ||
(slu->slu_blksize > (32 * 1024)) ||
(slu->slu_blksize == 0)) {
*err_ret = SBD_RET_INVALID_BLKSIZE;
ret = EINVAL;
goto scm_err_out;
*** 2995,3013 ****
sbd_status_t
sbd_data_read(sbd_lu_t *sl, struct scsi_task *task,
uint64_t offset, uint64_t size, uint8_t *buf)
{
! int ret;
long resid;
if ((offset + size) > sl->sl_lu_size) {
return (SBD_IO_PAST_EOF);
}
offset += sl->sl_data_offset;
if ((offset + size) > sl->sl_data_readable_size) {
uint64_t store_end;
if (offset > sl->sl_data_readable_size) {
bzero(buf, size);
return (SBD_SUCCESS);
--- 3043,3073 ----
sbd_status_t
sbd_data_read(sbd_lu_t *sl, struct scsi_task *task,
uint64_t offset, uint64_t size, uint8_t *buf)
{
! int ret, ioflag = 0;
long resid;
+ hrtime_t xfer_start;
+ uint8_t op = task->task_cdb[0];
if ((offset + size) > sl->sl_lu_size) {
return (SBD_IO_PAST_EOF);
}
offset += sl->sl_data_offset;
+ /*
+ * Check to see if the command is READ(10), READ(12), or READ(16).
+ * If it is then check for bit 3 being set to indicate if Forced
+ * Unit Access is being requested. If so, the FSYNC flag will be set
+ * on the read.
+ */
+ if (((op == SCMD_READ_G1) || (op == SCMD_READ_G4) ||
+ (op == SCMD_READ_G5)) && (task->task_cdb[1] & BIT_3)) {
+ ioflag = FSYNC;
+ }
if ((offset + size) > sl->sl_data_readable_size) {
uint64_t store_end;
if (offset > sl->sl_data_readable_size) {
bzero(buf, size);
return (SBD_SUCCESS);
*** 3015,3024 ****
--- 3075,3085 ----
store_end = sl->sl_data_readable_size - offset;
bzero(buf + store_end, size - store_end);
size = store_end;
}
+ xfer_start = gethrtime();
DTRACE_PROBE5(backing__store__read__start, sbd_lu_t *, sl,
uint8_t *, buf, uint64_t, size, uint64_t, offset,
scsi_task_t *, task);
/*
*** 3030,3044 ****
rw_enter(&sl->sl_access_state_lock, RW_READER);
if ((sl->sl_flags & SL_MEDIA_LOADED) == 0) {
rw_exit(&sl->sl_access_state_lock);
return (SBD_FAILURE);
}
ret = vn_rdwr(UIO_READ, sl->sl_data_vp, (caddr_t)buf, (ssize_t)size,
! (offset_t)offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, CRED(),
&resid);
rw_exit(&sl->sl_access_state_lock);
DTRACE_PROBE6(backing__store__read__end, sbd_lu_t *, sl,
uint8_t *, buf, uint64_t, size, uint64_t, offset,
int, ret, scsi_task_t *, task);
over_sl_data_read:
--- 3091,3108 ----
rw_enter(&sl->sl_access_state_lock, RW_READER);
if ((sl->sl_flags & SL_MEDIA_LOADED) == 0) {
rw_exit(&sl->sl_access_state_lock);
return (SBD_FAILURE);
}
+
ret = vn_rdwr(UIO_READ, sl->sl_data_vp, (caddr_t)buf, (ssize_t)size,
! (offset_t)offset, UIO_SYSSPACE, ioflag, RLIM64_INFINITY, CRED(),
&resid);
rw_exit(&sl->sl_access_state_lock);
+ stmf_lu_xfer_done(task, B_TRUE /* read */,
+ (gethrtime() - xfer_start));
DTRACE_PROBE6(backing__store__read__end, sbd_lu_t *, sl,
uint8_t *, buf, uint64_t, size, uint64_t, offset,
int, ret, scsi_task_t *, task);
over_sl_data_read:
*** 3057,3080 ****
{
int ret;
long resid;
sbd_status_t sret = SBD_SUCCESS;
int ioflag;
if ((offset + size) > sl->sl_lu_size) {
return (SBD_IO_PAST_EOF);
}
offset += sl->sl_data_offset;
! if ((sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) &&
! (sl->sl_flags & SL_FLUSH_ON_DISABLED_WRITECACHE)) {
ioflag = FSYNC;
} else {
ioflag = 0;
}
DTRACE_PROBE5(backing__store__write__start, sbd_lu_t *, sl,
uint8_t *, buf, uint64_t, size, uint64_t, offset,
scsi_task_t *, task);
/*
--- 3121,3158 ----
{
int ret;
long resid;
sbd_status_t sret = SBD_SUCCESS;
int ioflag;
+ hrtime_t xfer_start;
+ uint8_t op = task->task_cdb[0];
+ boolean_t fua_bit = B_FALSE;
if ((offset + size) > sl->sl_lu_size) {
return (SBD_IO_PAST_EOF);
}
offset += sl->sl_data_offset;
! /*
! * Check to see if the command is WRITE(10), WRITE(12), or WRITE(16).
! * If it is then check for bit 3 being set to indicate if Forced
! * Unit Access is being requested. If so, the FSYNC flag will be set
! * on the write.
! */
! if (((op == SCMD_WRITE_G1) || (op == SCMD_WRITE_G4) ||
! (op == SCMD_WRITE_G5)) && (task->task_cdb[1] & BIT_3)) {
! fua_bit = B_TRUE;
! }
! if (((sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) &&
! (sl->sl_flags & SL_FLUSH_ON_DISABLED_WRITECACHE)) || fua_bit) {
ioflag = FSYNC;
} else {
ioflag = 0;
}
+ xfer_start = gethrtime();
DTRACE_PROBE5(backing__store__write__start, sbd_lu_t *, sl,
uint8_t *, buf, uint64_t, size, uint64_t, offset,
scsi_task_t *, task);
/*
*** 3091,3100 ****
--- 3169,3180 ----
ret = vn_rdwr(UIO_WRITE, sl->sl_data_vp, (caddr_t)buf, (ssize_t)size,
(offset_t)offset, UIO_SYSSPACE, ioflag, RLIM64_INFINITY, CRED(),
&resid);
rw_exit(&sl->sl_access_state_lock);
+ stmf_lu_xfer_done(task, B_FALSE /* write */,
+ (gethrtime() - xfer_start));
DTRACE_PROBE6(backing__store__write__end, sbd_lu_t *, sl,
uint8_t *, buf, uint64_t, size, uint64_t, offset,
int, ret, scsi_task_t *, task);
if ((ret == 0) && (resid == 0) &&
*** 3101,3111 ****
(sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) &&
(sl->sl_flags & SL_FLUSH_ON_DISABLED_WRITECACHE)) {
sret = sbd_flush_data_cache(sl, 1);
}
over_sl_data_write:
-
if ((ret || resid) || (sret != SBD_SUCCESS)) {
return (SBD_FAILURE);
} else if ((offset + size) > sl->sl_data_readable_size) {
uint64_t old_size, new_size;
--- 3181,3190 ----
*** 3637,3646 ****
--- 3716,3726 ----
KM_SLEEP);
(void) strcpy(*comstarprop, ptr);
}
}
out:
+ if (nv != NULL)
nvlist_free(nv);
kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, size);
kmem_free(zc, sizeof (zfs_cmd_t));
(void) ldi_close(zfs_lh, FREAD|FWRITE, kcred);
*** 3687,3718 ****
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));
}
--- 3767,3825 ----
return (rc);
}
/*
* 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, dkioc_free_list_t *dfl)
{
vnode_t *vp;
! int unused, ret;
! /* Nothing to do */
! if (dfl->dfl_num_exts == 0)
! return (0);
! /*
! * 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;
/* 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);
}
! ret = VOP_IOCTL(vp, DKIOCFREE, (intptr_t)dfl, FKIOCTL, kcred,
! &unused, NULL);
!
! return (ret);
! }
!
! /*
! * Check if this lu belongs to sbd or some other lu
! * provider. A simple check for one of the module
! * entry points is sufficient.
! */
! int
! sbd_is_valid_lu(stmf_lu_t *lu)
! {
! if (lu->lu_new_task == sbd_new_task)
! return (1);
! return (0);
! }
!
! uint8_t
! sbd_get_lbasize_shift(stmf_lu_t *lu)
! {
! sbd_lu_t *sl = (sbd_lu_t *)lu->lu_provider_private;
!
! return (sl->sl_data_blocksize_shift);
}