summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2014-11-20 01:55:12 +0000
committermav <mav@FreeBSD.org>2014-11-20 01:55:12 +0000
commit6414b04c27c11b1fb58b7605fde9797ffe3dfa32 (patch)
treeb3e695871eabeae5b0f9c125f54622c300f3baf5 /sys/cam
parent3f382b8a2d8301dde56a5e8b9bde1a25c1bcca19 (diff)
downloadFreeBSD-src-6414b04c27c11b1fb58b7605fde9797ffe3dfa32.zip
FreeBSD-src-6414b04c27c11b1fb58b7605fde9797ffe3dfa32.tar.gz
MFC r274154, r274163:
Add to CTL support for logical block provisioning threshold notifications. For ZVOL-backed LUNs this allows to inform initiators if storage's used or available spaces get above/below the configured thresholds. Sponsored by: iXsystems, Inc.
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/ctl/ctl.c346
-rw-r--r--sys/cam/ctl/ctl.h6
-rw-r--r--sys/cam/ctl/ctl_backend.h2
-rw-r--r--sys/cam/ctl/ctl_backend_block.c44
-rw-r--r--sys/cam/ctl/ctl_error.c5
-rw-r--r--sys/cam/ctl/ctl_private.h19
-rw-r--r--sys/cam/scsi/scsi_all.h6
7 files changed, 402 insertions, 26 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index 67e3d4b..3a1c9ae 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -137,7 +137,7 @@ static struct scsi_da_rw_recovery_page rw_er_page_default = {
/*correction_span*/0,
/*head_offset_count*/0,
/*data_strobe_offset_cnt*/0,
- /*byte8*/0,
+ /*byte8*/SMS_RWER_LBPERE,
/*write_retry_count*/0,
/*reserved2*/0,
/*recovery_time_limit*/{0, 0},
@@ -297,22 +297,58 @@ static struct scsi_info_exceptions_page ie_page_changeable = {
/*report_count*/{0, 0, 0, 0}
};
-static struct scsi_logical_block_provisioning_page lbp_page_default = {
+#define CTL_LBPM_LEN (sizeof(struct ctl_logical_block_provisioning_page) - 4)
+
+static struct ctl_logical_block_provisioning_page lbp_page_default = {{
/*page_code*/SMS_INFO_EXCEPTIONS_PAGE | SMPH_SPF,
/*subpage_code*/0x02,
- /*page_length*/{0, sizeof(struct scsi_logical_block_provisioning_page) - 4},
+ /*page_length*/{CTL_LBPM_LEN >> 8, CTL_LBPM_LEN},
/*flags*/0,
/*reserved*/{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- /*descr*/{}
+ /*descr*/{}},
+ {{/*flags*/0,
+ /*resource*/0x01,
+ /*reserved*/{0, 0},
+ /*count*/{0, 0, 0, 0}},
+ {/*flags*/0,
+ /*resource*/0x02,
+ /*reserved*/{0, 0},
+ /*count*/{0, 0, 0, 0}},
+ {/*flags*/0,
+ /*resource*/0xf1,
+ /*reserved*/{0, 0},
+ /*count*/{0, 0, 0, 0}},
+ {/*flags*/0,
+ /*resource*/0xf2,
+ /*reserved*/{0, 0},
+ /*count*/{0, 0, 0, 0}}
+ }
};
-static struct scsi_logical_block_provisioning_page lbp_page_changeable = {
+static struct ctl_logical_block_provisioning_page lbp_page_changeable = {{
/*page_code*/SMS_INFO_EXCEPTIONS_PAGE | SMPH_SPF,
/*subpage_code*/0x02,
- /*page_length*/{0, sizeof(struct scsi_logical_block_provisioning_page) - 4},
+ /*page_length*/{CTL_LBPM_LEN >> 8, CTL_LBPM_LEN},
/*flags*/0,
/*reserved*/{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- /*descr*/{}
+ /*descr*/{}},
+ {{/*flags*/0,
+ /*resource*/0,
+ /*reserved*/{0, 0},
+ /*count*/{0, 0, 0, 0}},
+ {/*flags*/0,
+ /*resource*/0,
+ /*reserved*/{0, 0},
+ /*count*/{0, 0, 0, 0}},
+ {/*flags*/0,
+ /*resource*/0,
+ /*reserved*/{0, 0},
+ /*count*/{0, 0, 0, 0}},
+ {/*flags*/0,
+ /*resource*/0,
+ /*reserved*/{0, 0},
+ /*count*/{0, 0, 0, 0}}
+ }
};
/*
@@ -449,6 +485,7 @@ static void ctl_datamove_remote_read(union ctl_io *io);
static void ctl_datamove_remote(union ctl_io *io);
static int ctl_process_done(union ctl_io *io);
static void ctl_lun_thread(void *arg);
+static void ctl_thresh_thread(void *arg);
static void ctl_work_thread(void *arg);
static void ctl_enqueue_incoming(union ctl_io *io);
static void ctl_enqueue_rtr(union ctl_io *io);
@@ -1087,6 +1124,15 @@ ctl_init(void)
ctl_pool_free(other_pool);
return (error);
}
+ error = kproc_kthread_add(ctl_thresh_thread, softc,
+ &softc->ctl_proc, NULL, 0, 0, "ctl", "thresh");
+ if (error != 0) {
+ printf("error creating CTL threshold thread!\n");
+ ctl_pool_free(internal_pool);
+ ctl_pool_free(emergency_pool);
+ ctl_pool_free(other_pool);
+ return (error);
+ }
if (bootverbose)
printf("ctl: CAM Target Layer loaded\n");
@@ -3993,6 +4039,52 @@ ctl_copy_io(union ctl_io *src, union ctl_io *dest)
dest->io_hdr.flags |= CTL_FLAG_INT_COPY;
}
+static int
+ctl_expand_number(const char *buf, uint64_t *num)
+{
+ char *endptr;
+ uint64_t number;
+ unsigned shift;
+
+ number = strtoq(buf, &endptr, 0);
+
+ switch (tolower((unsigned char)*endptr)) {
+ case 'e':
+ shift = 60;
+ break;
+ case 'p':
+ shift = 50;
+ break;
+ case 't':
+ shift = 40;
+ break;
+ case 'g':
+ shift = 30;
+ break;
+ case 'm':
+ shift = 20;
+ break;
+ case 'k':
+ shift = 10;
+ break;
+ case 'b':
+ case '\0': /* No unit. */
+ *num = number;
+ return (0);
+ default:
+ /* Unrecognized unit. */
+ return (-1);
+ }
+
+ if ((number << shift) >> shift != number) {
+ /* Overflow */
+ return (-1);
+ }
+ *num = number << shift;
+ return (0);
+}
+
+
/*
* This routine could be used in the future to load default and/or saved
* mode page parameters for a particuar lun.
@@ -4003,6 +4095,7 @@ ctl_init_page_index(struct ctl_lun *lun)
int i;
struct ctl_page_index *page_index;
const char *value;
+ uint64_t ival;
memcpy(&lun->mode_pages.index, page_index_template,
sizeof(page_index_template));
@@ -4246,22 +4339,77 @@ ctl_init_page_index(struct ctl_lun *lun)
page_index->page_data =
(uint8_t *)lun->mode_pages.ie_page;
break;
- case 0x02:
- memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_CURRENT],
+ case 0x02: {
+ struct ctl_logical_block_provisioning_page *page;
+
+ memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_DEFAULT],
&lbp_page_default,
sizeof(lbp_page_default));
memcpy(&lun->mode_pages.lbp_page[
CTL_PAGE_CHANGEABLE], &lbp_page_changeable,
sizeof(lbp_page_changeable));
- memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_DEFAULT],
- &lbp_page_default,
- sizeof(lbp_page_default));
memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_SAVED],
&lbp_page_default,
sizeof(lbp_page_default));
+ page = &lun->mode_pages.lbp_page[CTL_PAGE_SAVED];
+ value = ctl_get_opt(&lun->be_lun->options,
+ "avail-threshold");
+ if (value != NULL &&
+ ctl_expand_number(value, &ival) == 0) {
+ page->descr[0].flags |= SLBPPD_ENABLED |
+ SLBPPD_ARMING_DEC;
+ if (lun->be_lun->blocksize)
+ ival /= lun->be_lun->blocksize;
+ else
+ ival /= 512;
+ scsi_ulto4b(ival >> CTL_LBP_EXPONENT,
+ page->descr[0].count);
+ }
+ value = ctl_get_opt(&lun->be_lun->options,
+ "used-threshold");
+ if (value != NULL &&
+ ctl_expand_number(value, &ival) == 0) {
+ page->descr[1].flags |= SLBPPD_ENABLED |
+ SLBPPD_ARMING_INC;
+ if (lun->be_lun->blocksize)
+ ival /= lun->be_lun->blocksize;
+ else
+ ival /= 512;
+ scsi_ulto4b(ival >> CTL_LBP_EXPONENT,
+ page->descr[1].count);
+ }
+ value = ctl_get_opt(&lun->be_lun->options,
+ "pool-avail-threshold");
+ if (value != NULL &&
+ ctl_expand_number(value, &ival) == 0) {
+ page->descr[2].flags |= SLBPPD_ENABLED |
+ SLBPPD_ARMING_DEC;
+ if (lun->be_lun->blocksize)
+ ival /= lun->be_lun->blocksize;
+ else
+ ival /= 512;
+ scsi_ulto4b(ival >> CTL_LBP_EXPONENT,
+ page->descr[2].count);
+ }
+ value = ctl_get_opt(&lun->be_lun->options,
+ "pool-used-threshold");
+ if (value != NULL &&
+ ctl_expand_number(value, &ival) == 0) {
+ page->descr[3].flags |= SLBPPD_ENABLED |
+ SLBPPD_ARMING_INC;
+ if (lun->be_lun->blocksize)
+ ival /= lun->be_lun->blocksize;
+ else
+ ival /= 512;
+ scsi_ulto4b(ival >> CTL_LBP_EXPONENT,
+ page->descr[3].count);
+ }
+ memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_CURRENT],
+ &lun->mode_pages.lbp_page[CTL_PAGE_SAVED],
+ sizeof(lbp_page_default));
page_index->page_data =
(uint8_t *)lun->mode_pages.lbp_page;
- }
+ }}
break;
}
case SMS_VENDOR_SPECIFIC_PAGE:{
@@ -4320,13 +4468,13 @@ static int
ctl_init_log_page_index(struct ctl_lun *lun)
{
struct ctl_page_index *page_index;
- int i, j, prev;
+ int i, j, k, prev;
memcpy(&lun->log_pages.index, log_page_index_template,
sizeof(log_page_index_template));
prev = -1;
- for (i = 0, j = 0; i < CTL_NUM_LOG_PAGES; i++) {
+ for (i = 0, j = 0, k = 0; i < CTL_NUM_LOG_PAGES; i++) {
page_index = &lun->log_pages.index[i];
/*
@@ -4339,18 +4487,26 @@ ctl_init_log_page_index(struct ctl_lun *lun)
&& (page_index->page_flags & CTL_PAGE_FLAG_DISK_ONLY))
continue;
+ if (page_index->page_code == SLS_LOGICAL_BLOCK_PROVISIONING &&
+ ((lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) == 0 ||
+ lun->backend->lun_attr == NULL))
+ continue;
+
if (page_index->page_code != prev) {
lun->log_pages.pages_page[j] = page_index->page_code;
prev = page_index->page_code;
j++;
}
- lun->log_pages.subpages_page[i*2] = page_index->page_code;
- lun->log_pages.subpages_page[i*2+1] = page_index->subpage;
+ lun->log_pages.subpages_page[k*2] = page_index->page_code;
+ lun->log_pages.subpages_page[k*2+1] = page_index->subpage;
+ k++;
}
lun->log_pages.index[0].page_data = &lun->log_pages.pages_page[0];
lun->log_pages.index[0].page_len = j;
lun->log_pages.index[1].page_data = &lun->log_pages.subpages_page[0];
- lun->log_pages.index[1].page_len = i * 2;
+ lun->log_pages.index[1].page_len = k * 2;
+ lun->log_pages.index[2].page_data = &lun->log_pages.lbp_page[0];
+ lun->log_pages.index[2].page_len = 12*CTL_NUM_LBP_PARAMS;
return (CTL_RETVAL_COMPLETE);
}
@@ -6939,6 +7095,75 @@ ctl_mode_sense(struct ctl_scsiio *ctsio)
}
int
+ctl_lbp_log_sense_handler(struct ctl_scsiio *ctsio,
+ struct ctl_page_index *page_index,
+ int pc)
+{
+ struct ctl_lun *lun;
+ struct scsi_log_param_header *phdr;
+ uint8_t *data;
+ uint64_t val;
+
+ lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+ data = page_index->page_data;
+
+ if (lun->backend->lun_attr != NULL &&
+ (val = lun->backend->lun_attr(lun->be_lun->be_lun, "blocksavail"))
+ != UINT64_MAX) {
+ phdr = (struct scsi_log_param_header *)data;
+ scsi_ulto2b(0x0001, phdr->param_code);
+ phdr->param_control = SLP_LBIN | SLP_LP;
+ phdr->param_len = 8;
+ data = (uint8_t *)(phdr + 1);
+ scsi_ulto4b(val >> CTL_LBP_EXPONENT, data);
+ data[4] = 0x01; /* per-LUN */
+ data += phdr->param_len;
+ }
+
+ if (lun->backend->lun_attr != NULL &&
+ (val = lun->backend->lun_attr(lun->be_lun->be_lun, "blocksused"))
+ != UINT64_MAX) {
+ phdr = (struct scsi_log_param_header *)data;
+ scsi_ulto2b(0x0002, phdr->param_code);
+ phdr->param_control = SLP_LBIN | SLP_LP;
+ phdr->param_len = 8;
+ data = (uint8_t *)(phdr + 1);
+ scsi_ulto4b(val >> CTL_LBP_EXPONENT, data);
+ data[4] = 0x02; /* per-pool */
+ data += phdr->param_len;
+ }
+
+ if (lun->backend->lun_attr != NULL &&
+ (val = lun->backend->lun_attr(lun->be_lun->be_lun, "poolblocksavail"))
+ != UINT64_MAX) {
+ phdr = (struct scsi_log_param_header *)data;
+ scsi_ulto2b(0x00f1, phdr->param_code);
+ phdr->param_control = SLP_LBIN | SLP_LP;
+ phdr->param_len = 8;
+ data = (uint8_t *)(phdr + 1);
+ scsi_ulto4b(val >> CTL_LBP_EXPONENT, data);
+ data[4] = 0x02; /* per-pool */
+ data += phdr->param_len;
+ }
+
+ if (lun->backend->lun_attr != NULL &&
+ (val = lun->backend->lun_attr(lun->be_lun->be_lun, "poolblocksused"))
+ != UINT64_MAX) {
+ phdr = (struct scsi_log_param_header *)data;
+ scsi_ulto2b(0x00f2, phdr->param_code);
+ phdr->param_control = SLP_LBIN | SLP_LP;
+ phdr->param_len = 8;
+ data = (uint8_t *)(phdr + 1);
+ scsi_ulto4b(val >> CTL_LBP_EXPONENT, data);
+ data[4] = 0x02; /* per-pool */
+ data += phdr->param_len;
+ }
+
+ page_index->page_len = data - page_index->page_data;
+ return (0);
+}
+
+int
ctl_log_sense(struct ctl_scsiio *ctsio)
{
struct ctl_lun *lun;
@@ -10247,9 +10472,10 @@ ctl_inquiry_evpd_lbp(struct ctl_scsiio *ctsio, int alloc_len)
lbp_ptr->page_code = SVPD_LBP;
scsi_ulto2b(sizeof(*lbp_ptr) - 4, lbp_ptr->page_length);
if (lun != NULL && lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) {
+ lbp_ptr->threshold_exponent = CTL_LBP_EXPONENT;
lbp_ptr->flags = SVPD_LBP_UNMAP | SVPD_LBP_WS16 |
SVPD_LBP_WS10 | SVPD_LBP_RZ | SVPD_LBP_ANC_SUP;
- lbp_ptr->prov_type = SVPD_LBP_RESOURCE;
+ lbp_ptr->prov_type = SVPD_LBP_THIN;
}
ctsio->scsi_status = SCSI_STATUS_OK;
@@ -13996,6 +14222,88 @@ ctl_lun_thread(void *arg)
}
static void
+ctl_thresh_thread(void *arg)
+{
+ struct ctl_softc *softc = (struct ctl_softc *)arg;
+ struct ctl_lun *lun;
+ struct ctl_be_lun *be_lun;
+ struct scsi_da_rw_recovery_page *rwpage;
+ struct ctl_logical_block_provisioning_page *page;
+ const char *attr;
+ uint64_t thres, val;
+ int i, e;
+
+ CTL_DEBUG_PRINT(("ctl_thresh_thread starting\n"));
+
+ for (;;) {
+ mtx_lock(&softc->ctl_lock);
+ STAILQ_FOREACH(lun, &softc->lun_list, links) {
+ be_lun = lun->be_lun;
+ if ((lun->flags & CTL_LUN_DISABLED) ||
+ (lun->flags & CTL_LUN_OFFLINE) ||
+ (be_lun->flags & CTL_LUN_FLAG_UNMAP) == 0 ||
+ lun->backend->lun_attr == NULL)
+ continue;
+ rwpage = &lun->mode_pages.rw_er_page[CTL_PAGE_CURRENT];
+ if ((rwpage->byte8 & SMS_RWER_LBPERE) == 0)
+ continue;
+ e = 0;
+ page = &lun->mode_pages.lbp_page[CTL_PAGE_CURRENT];
+ for (i = 0; i < CTL_NUM_LBP_THRESH; i++) {
+ if ((page->descr[i].flags & SLBPPD_ENABLED) == 0)
+ continue;
+ thres = scsi_4btoul(page->descr[i].count);
+ thres <<= CTL_LBP_EXPONENT;
+ switch (page->descr[i].resource) {
+ case 0x01:
+ attr = "blocksavail";
+ break;
+ case 0x02:
+ attr = "blocksused";
+ break;
+ case 0xf1:
+ attr = "poolblocksavail";
+ break;
+ case 0xf2:
+ attr = "poolblocksused";
+ break;
+ default:
+ continue;
+ }
+ mtx_unlock(&softc->ctl_lock); // XXX
+ val = lun->backend->lun_attr(
+ lun->be_lun->be_lun, attr);
+ mtx_lock(&softc->ctl_lock);
+ if (val == UINT64_MAX)
+ continue;
+ if ((page->descr[i].flags & SLBPPD_ARMING_MASK)
+ == SLBPPD_ARMING_INC)
+ e |= (val >= thres);
+ else
+ e |= (val <= thres);
+ }
+ mtx_lock(&lun->lun_lock);
+ if (e) {
+ if (lun->lasttpt == 0 ||
+ time_uptime - lun->lasttpt >= CTL_LBP_UA_PERIOD) {
+ lun->lasttpt = time_uptime;
+ for (i = 0; i < CTL_MAX_INITIATORS; i++)
+ lun->pending_ua[i] |=
+ CTL_UA_THIN_PROV_THRES;
+ }
+ } else {
+ lun->lasttpt = 0;
+ for (i = 0; i < CTL_MAX_INITIATORS; i++)
+ lun->pending_ua[i] &= ~CTL_UA_THIN_PROV_THRES;
+ }
+ mtx_unlock(&lun->lun_lock);
+ }
+ mtx_unlock(&softc->ctl_lock);
+ pause("-", CTL_LBP_PERIOD * hz);
+ }
+}
+
+static void
ctl_enqueue_incoming(union ctl_io *io)
{
struct ctl_softc *softc = control_softc;
diff --git a/sys/cam/ctl/ctl.h b/sys/cam/ctl/ctl.h
index a9de265..9856dcc 100644
--- a/sys/cam/ctl/ctl.h
+++ b/sys/cam/ctl/ctl.h
@@ -127,7 +127,8 @@ typedef enum {
CTL_UA_RES_RELEASE = 0x0800,
CTL_UA_REG_PREEMPT = 0x1000,
CTL_UA_ASYM_ACC_CHANGE = 0x2000,
- CTL_UA_CAPACITY_CHANGED = 0x4000
+ CTL_UA_CAPACITY_CHANGED = 0x4000,
+ CTL_UA_THIN_PROV_THRES = 0x8000
} ctl_ua_type;
#ifdef _KERNEL
@@ -178,6 +179,9 @@ int ctl_debugconf_sp_sense_handler(struct ctl_scsiio *ctsio,
int ctl_debugconf_sp_select_handler(struct ctl_scsiio *ctsio,
struct ctl_page_index *page_index,
uint8_t *page_ptr);
+int ctl_lbp_log_sense_handler(struct ctl_scsiio *ctsio,
+ struct ctl_page_index *page_index,
+ int pc);
int ctl_config_move_done(union ctl_io *io);
void ctl_datamove(union ctl_io *io);
void ctl_done(union ctl_io *io);
diff --git a/sys/cam/ctl/ctl_backend.h b/sys/cam/ctl/ctl_backend.h
index 4d88f64..f32d120 100644
--- a/sys/cam/ctl/ctl_backend.h
+++ b/sys/cam/ctl/ctl_backend.h
@@ -218,6 +218,7 @@ typedef void (*be_vfunc_t)(union ctl_io *io);
typedef int (*be_ioctl_t)(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
struct thread *td);
typedef int (*be_luninfo_t)(void *be_lun, struct sbuf *sb);
+typedef uint64_t (*be_lunattr_t)(void *be_lun, const char *attrname);
struct ctl_backend_driver {
char name[CTL_BE_NAME_LEN]; /* passed to CTL */
@@ -229,6 +230,7 @@ struct ctl_backend_driver {
be_func_t config_write; /* passed to CTL */
be_ioctl_t ioctl; /* passed to CTL */
be_luninfo_t lun_info; /* passed to CTL */
+ be_lunattr_t lun_attr; /* passed to CTL */
#ifdef CS_BE_CONFIG_MOVE_DONE_IS_NOT_USED
be_func_t config_move_done; /* passed to backend */
#endif
diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c
index dc725a3..727811b 100644
--- a/sys/cam/ctl/ctl_backend_block.c
+++ b/sys/cam/ctl/ctl_backend_block.c
@@ -147,6 +147,8 @@ struct ctl_be_block_lun;
typedef void (*cbb_dispatch_t)(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
+typedef uint64_t (*cbb_getattr_t)(struct ctl_be_block_lun *be_lun,
+ const char *attrname);
/*
* Backend LUN structure. There is a 1:1 mapping between a block device
@@ -163,6 +165,7 @@ struct ctl_be_block_lun {
cbb_dispatch_t dispatch;
cbb_dispatch_t lun_flush;
cbb_dispatch_t unmap;
+ cbb_getattr_t getattr;
uma_zone_t lun_zone;
uint64_t size_blocks;
uint64_t size_bytes;
@@ -243,6 +246,8 @@ static void ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
static void ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
+static uint64_t ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun,
+ const char *attrname);
static void ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun,
union ctl_io *io);
static void ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun,
@@ -275,6 +280,7 @@ static void ctl_be_block_lun_config_status(void *be_lun,
static int ctl_be_block_config_write(union ctl_io *io);
static int ctl_be_block_config_read(union ctl_io *io);
static int ctl_be_block_lun_info(void *be_lun, struct sbuf *sb);
+static uint64_t ctl_be_block_lun_attr(void *be_lun, const char *attrname);
int ctl_be_block_init(void);
static struct ctl_backend_driver ctl_be_block_driver =
@@ -287,7 +293,8 @@ static struct ctl_backend_driver ctl_be_block_driver =
.config_read = ctl_be_block_config_read,
.config_write = ctl_be_block_config_write,
.ioctl = ctl_be_block_ioctl,
- .lun_info = ctl_be_block_lun_info
+ .lun_info = ctl_be_block_lun_info,
+ .lun_attr = ctl_be_block_lun_attr
};
MALLOC_DEFINE(M_CTLBLK, "ctlblk", "Memory used for CTL block backend");
@@ -1015,6 +1022,24 @@ ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun,
}
}
+static uint64_t
+ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname)
+{
+ struct ctl_be_block_devdata *dev_data = &be_lun->backend.dev;
+ struct diocgattr_arg arg;
+ int error;
+
+ if (dev_data->csw == NULL || dev_data->csw->d_ioctl == NULL)
+ return (UINT64_MAX);
+ strlcpy(arg.name, attrname, sizeof(arg.name));
+ arg.len = sizeof(arg.value.off);
+ error = dev_data->csw->d_ioctl(dev_data->cdev,
+ DIOCGATTR, (caddr_t)&arg, FREAD, curthread);
+ if (error != 0)
+ return (UINT64_MAX);
+ return (arg.value.off);
+}
+
static void
ctl_be_block_cw_done_ws(struct ctl_be_block_io *beio)
{
@@ -1650,6 +1675,7 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
be_lun->dispatch = ctl_be_block_dispatch_dev;
be_lun->lun_flush = ctl_be_block_flush_dev;
be_lun->unmap = ctl_be_block_unmap_dev;
+ be_lun->getattr = ctl_be_block_getattr_dev;
error = VOP_GETATTR(be_lun->vn, &vattr, NOCRED);
if (error) {
@@ -1996,10 +2022,10 @@ ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
}
num_threads = tmp_num_threads;
}
- unmap = 0;
+ unmap = (be_lun->dispatch == ctl_be_block_dispatch_zvol);
value = ctl_get_opt(&be_lun->ctl_be_lun.options, "unmap");
- if (value != NULL && strcmp(value, "on") == 0)
- unmap = 1;
+ if (value != NULL)
+ unmap = (strcmp(value, "on") == 0);
be_lun->flags = CTL_BE_BLOCK_LUN_UNCONFIGURED;
be_lun->ctl_be_lun.flags = CTL_LUN_FLAG_PRIMARY;
@@ -2585,6 +2611,16 @@ bailout:
return (retval);
}
+static uint64_t
+ctl_be_block_lun_attr(void *be_lun, const char *attrname)
+{
+ struct ctl_be_block_lun *lun = (struct ctl_be_block_lun *)be_lun;
+
+ if (lun->getattr == NULL)
+ return (UINT64_MAX);
+ return (lun->getattr(lun, attrname));
+}
+
int
ctl_be_block_init(void)
{
diff --git a/sys/cam/ctl/ctl_error.c b/sys/cam/ctl/ctl_error.c
index b6a8b89..370af63 100644
--- a/sys/cam/ctl/ctl_error.c
+++ b/sys/cam/ctl/ctl_error.c
@@ -463,6 +463,11 @@ ctl_build_ua(ctl_ua_type *ua_type, struct scsi_sense_data *sense,
asc = 0x2A;
ascq = 0x09;
break;
+ case CTL_UA_THIN_PROV_THRES:
+ /* 38h/07n THIN PROVISIONING SOFT THRESHOLD REACHED */
+ asc = 0x38;
+ ascq = 0x07;
+ break;
default:
panic("ctl_build_ua: Unknown UA %x", ua_to_build);
}
diff --git a/sys/cam/ctl/ctl_private.h b/sys/cam/ctl/ctl_private.h
index a2992d1..7b66c7f 100644
--- a/sys/cam/ctl/ctl_private.h
+++ b/sys/cam/ctl/ctl_private.h
@@ -302,6 +302,17 @@ struct ctl_page_index {
#define CTL_PAGE_DEFAULT 0x02
#define CTL_PAGE_SAVED 0x03
+#define CTL_NUM_LBP_PARAMS 4
+#define CTL_NUM_LBP_THRESH 4
+#define CTL_LBP_EXPONENT 11 /* 2048 sectors */
+#define CTL_LBP_PERIOD 10 /* 10 seconds */
+#define CTL_LBP_UA_PERIOD 300 /* 5 minutes */
+
+struct ctl_logical_block_provisioning_page {
+ struct scsi_logical_block_provisioning_page main;
+ struct scsi_logical_block_provisioning_page_descr descr[CTL_NUM_LBP_THRESH];
+};
+
static const struct ctl_page_index page_index_template[] = {
{SMS_RW_ERROR_RECOVERY_PAGE, 0, sizeof(struct scsi_da_rw_recovery_page), NULL,
CTL_PAGE_FLAG_DISK_ONLY, NULL, NULL},
@@ -316,7 +327,7 @@ static const struct ctl_page_index page_index_template[] = {
{SMS_INFO_EXCEPTIONS_PAGE, 0, sizeof(struct scsi_info_exceptions_page), NULL,
CTL_PAGE_FLAG_NONE, NULL, NULL},
{SMS_INFO_EXCEPTIONS_PAGE | SMPH_SPF, 0x02,
- sizeof(struct scsi_logical_block_provisioning_page), NULL,
+ sizeof(struct ctl_logical_block_provisioning_page), NULL,
CTL_PAGE_FLAG_DISK_ONLY, NULL, NULL},
{SMS_VENDOR_SPECIFIC_PAGE | SMPH_SPF, DBGCNF_SUBPAGE_CODE,
sizeof(struct copan_debugconf_subpage), NULL, CTL_PAGE_FLAG_NONE,
@@ -333,7 +344,7 @@ struct ctl_mode_pages {
struct scsi_caching_page caching_page[4];
struct scsi_control_page control_page[4];
struct scsi_info_exceptions_page ie_page[4];
- struct scsi_logical_block_provisioning_page lbp_page[4];
+ struct ctl_logical_block_provisioning_page lbp_page[4];
struct copan_debugconf_subpage debugconf_subpage[4];
struct ctl_page_index index[CTL_NUM_MODE_PAGES];
};
@@ -343,6 +354,8 @@ static const struct ctl_page_index log_page_index_template[] = {
CTL_PAGE_FLAG_NONE, NULL, NULL},
{SLS_SUPPORTED_PAGES_PAGE, SLS_SUPPORTED_SUBPAGES_SUBPAGE, 0, NULL,
CTL_PAGE_FLAG_NONE, NULL, NULL},
+ {SLS_LOGICAL_BLOCK_PROVISIONING, 0, 0, NULL,
+ CTL_PAGE_FLAG_NONE, ctl_lbp_log_sense_handler, NULL},
};
#define CTL_NUM_LOG_PAGES sizeof(log_page_index_template)/ \
@@ -351,6 +364,7 @@ static const struct ctl_page_index log_page_index_template[] = {
struct ctl_log_pages {
uint8_t pages_page[CTL_NUM_LOG_PAGES];
uint8_t subpages_page[CTL_NUM_LOG_PAGES * 2];
+ uint8_t lbp_page[12*CTL_NUM_LBP_PARAMS];
struct ctl_page_index index[CTL_NUM_LOG_PAGES];
};
@@ -411,6 +425,7 @@ struct ctl_lun {
struct scsi_sense_data pending_sense[CTL_MAX_INITIATORS];
#endif
ctl_ua_type pending_ua[CTL_MAX_INITIATORS];
+ time_t lasttpt;
struct ctl_mode_pages mode_pages;
struct ctl_log_pages log_pages;
struct ctl_lun_io_stats stats;
diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h
index 497edf7..6ee0370 100644
--- a/sys/cam/scsi/scsi_all.h
+++ b/sys/cam/scsi/scsi_all.h
@@ -559,6 +559,7 @@ struct scsi_log_sense
#define SLS_ERROR_VERIFY_PAGE 0x05
#define SLS_ERROR_NONMEDIUM_PAGE 0x06
#define SLS_ERROR_LASTN_PAGE 0x07
+#define SLS_LOGICAL_BLOCK_PROVISIONING 0x0c
#define SLS_SELF_TEST_PAGE 0x10
#define SLS_IE_PAGE 0x2f
#define SLS_PAGE_CTRL_MASK 0xC0
@@ -740,6 +741,11 @@ struct scsi_info_exceptions_page {
struct scsi_logical_block_provisioning_page_descr {
uint8_t flags;
+#define SLBPPD_ENABLED 0x80
+#define SLBPPD_TYPE_MASK 0x38
+#define SLBPPD_ARMING_MASK 0x07
+#define SLBPPD_ARMING_DEC 0x02
+#define SLBPPD_ARMING_INC 0x01
uint8_t resource;
uint8_t reserved[2];
uint8_t count[4];
OpenPOWER on IntegriCloud