Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 20 Nov 2014 01:55:13 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r274732 - in stable/10: sys/cam/ctl sys/cam/scsi sys/cddl/contrib/opensolaris/uts/common/fs/zfs sys/geom sys/sys usr.sbin/ctladm
Message-ID:  <201411200155.sAK1tDAT050034@svn.freebsd.org>

index | next in thread | raw e-mail

Author: mav
Date: Thu Nov 20 01:55:12 2014
New Revision: 274732
URL: https://svnweb.freebsd.org/changeset/base/274732

Log:
  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.

Modified:
  stable/10/sys/cam/ctl/ctl.c
  stable/10/sys/cam/ctl/ctl.h
  stable/10/sys/cam/ctl/ctl_backend.h
  stable/10/sys/cam/ctl/ctl_backend_block.c
  stable/10/sys/cam/ctl/ctl_error.c
  stable/10/sys/cam/ctl/ctl_private.h
  stable/10/sys/cam/scsi/scsi_all.h
  stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
  stable/10/sys/geom/geom_dev.c
  stable/10/sys/sys/disk.h
  stable/10/usr.sbin/ctladm/ctladm.8
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/cam/ctl/ctl.c
==============================================================================
--- stable/10/sys/cam/ctl/ctl.c	Thu Nov 20 01:51:54 2014	(r274731)
+++ stable/10/sys/cam/ctl/ctl.c	Thu Nov 20 01:55:12 2014	(r274732)
@@ -137,7 +137,7 @@ static struct scsi_da_rw_recovery_page r
 	/*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 
 	/*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(uni
 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
 	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 *
 		 && (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 *
 	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;

Modified: stable/10/sys/cam/ctl/ctl.h
==============================================================================
--- stable/10/sys/cam/ctl/ctl.h	Thu Nov 20 01:51:54 2014	(r274731)
+++ stable/10/sys/cam/ctl/ctl.h	Thu Nov 20 01:55:12 2014	(r274732)
@@ -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(struc
 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);

Modified: stable/10/sys/cam/ctl/ctl_backend.h
==============================================================================
--- stable/10/sys/cam/ctl/ctl_backend.h	Thu Nov 20 01:51:54 2014	(r274731)
+++ stable/10/sys/cam/ctl/ctl_backend.h	Thu Nov 20 01:55:12 2014	(r274732)
@@ -218,6 +218,7 @@ typedef void (*be_vfunc_t)(union ctl_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

Modified: stable/10/sys/cam/ctl/ctl_backend_block.c
==============================================================================
--- stable/10/sys/cam/ctl/ctl_backend_block.c	Thu Nov 20 01:51:54 2014	(r274731)
+++ stable/10/sys/cam/ctl/ctl_backend_block.c	Thu Nov 20 01:55:12 2014	(r274732)
@@ -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(struc
 				   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_stat
 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_
 	.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_
 	}
 }
 
+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_bloc
 		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_
 		}
 		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)
 {

Modified: stable/10/sys/cam/ctl/ctl_error.c
==============================================================================
--- stable/10/sys/cam/ctl/ctl_error.c	Thu Nov 20 01:51:54 2014	(r274731)
+++ stable/10/sys/cam/ctl/ctl_error.c	Thu Nov 20 01:55:12 2014	(r274732)
@@ -463,6 +463,11 @@ ctl_build_ua(ctl_ua_type *ua_type, struc
 		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);
 	}

Modified: stable/10/sys/cam/ctl/ctl_private.h
==============================================================================
--- stable/10/sys/cam/ctl/ctl_private.h	Thu Nov 20 01:51:54 2014	(r274731)
+++ stable/10/sys/cam/ctl/ctl_private.h	Thu Nov 20 01:55:12 2014	(r274732)
@@ -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_
 	{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_p
 	 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_p
 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;

Modified: stable/10/sys/cam/scsi/scsi_all.h
==============================================================================
--- stable/10/sys/cam/scsi/scsi_all.h	Thu Nov 20 01:51:54 2014	(r274731)
+++ stable/10/sys/cam/scsi/scsi_all.h	Thu Nov 20 01:55:12 2014	(r274732)
@@ -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];

Modified: stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
==============================================================================
--- stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c	Thu Nov 20 01:51:54 2014	(r274731)
+++ stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c	Thu Nov 20 01:55:12 2014	(r274732)
@@ -2460,10 +2460,38 @@ zvol_geom_start(struct bio *bp)
 			goto enqueue;
 		zvol_strategy(bp);
 		break;
-	case BIO_GETATTR:
+	case BIO_GETATTR: {
+		spa_t *spa = dmu_objset_spa(zv->zv_objset);
+		uint64_t refd, avail, usedobjs, availobjs, val;
+
 		if (g_handleattr_int(bp, "GEOM::candelete", 1))
 			return;
+		if (strcmp(bp->bio_attribute, "blocksavail") == 0) {
+			dmu_objset_space(zv->zv_objset, &refd, &avail,
+			    &usedobjs, &availobjs);
+			if (g_handleattr_off_t(bp, "blocksavail",
+			    avail / DEV_BSIZE))
+				return;
+		} else if (strcmp(bp->bio_attribute, "blocksused") == 0) {
+			dmu_objset_space(zv->zv_objset, &refd, &avail,
+			    &usedobjs, &availobjs);
+			if (g_handleattr_off_t(bp, "blocksused",
+			    refd / DEV_BSIZE))
+				return;
+		} else if (strcmp(bp->bio_attribute, "poolblocksavail") == 0) {
+			avail = metaslab_class_get_space(spa_normal_class(spa));
+			avail -= metaslab_class_get_alloc(spa_normal_class(spa));
+			if (g_handleattr_off_t(bp, "poolblocksavail",
+			    avail / DEV_BSIZE))
+				return;
+		} else if (strcmp(bp->bio_attribute, "poolblocksused") == 0) {
+			refd = metaslab_class_get_alloc(spa_normal_class(spa));
+			if (g_handleattr_off_t(bp, "poolblocksused",
+			    refd / DEV_BSIZE))
+				return;
+		}
 		/* FALLTHROUGH */
+	}
 	default:
 		g_io_deliver(bp, EOPNOTSUPP);
 		break;
@@ -2862,6 +2890,30 @@ zvol_d_ioctl(struct cdev *dev, u_long cm
 	case DIOCGSTRIPEOFFSET:
 		*(off_t *)data = 0;
 		break;
+	case DIOCGATTR: {
+		spa_t *spa = dmu_objset_spa(zv->zv_objset);
+		struct diocgattr_arg *arg = (struct diocgattr_arg *)data;
+		uint64_t refd, avail, usedobjs, availobjs;
+
+		if (strcmp(arg->name, "blocksavail") == 0) {
+			dmu_objset_space(zv->zv_objset, &refd, &avail,
+			    &usedobjs, &availobjs);
+			arg->value.off = avail / DEV_BSIZE;
+		} else if (strcmp(arg->name, "blocksused") == 0) {
+			dmu_objset_space(zv->zv_objset, &refd, &avail,
+			    &usedobjs, &availobjs);
+			arg->value.off = refd / DEV_BSIZE;
+		} else if (strcmp(arg->name, "poolblocksavail") == 0) {
+			avail = metaslab_class_get_space(spa_normal_class(spa));
+			avail -= metaslab_class_get_alloc(spa_normal_class(spa));
+			arg->value.off = avail / DEV_BSIZE;
+		} else if (strcmp(arg->name, "poolblocksused") == 0) {
+			refd = metaslab_class_get_alloc(spa_normal_class(spa));
+			arg->value.off = refd / DEV_BSIZE;
+		} else
+			error = ENOIOCTL;
+		break;
+	}
 	default:
 		error = ENOIOCTL;
 	}

Modified: stable/10/sys/geom/geom_dev.c
==============================================================================
--- stable/10/sys/geom/geom_dev.c	Thu Nov 20 01:51:54 2014	(r274731)
+++ stable/10/sys/geom/geom_dev.c	Thu Nov 20 01:55:12 2014	(r274732)
@@ -508,6 +508,16 @@ g_dev_ioctl(struct cdev *dev, u_long cmd
 		if (error == 0 && *(char *)data == '\0')
 			error = ENOENT;
 		break;
+	case DIOCGATTR: {
+		struct diocgattr_arg *arg = (struct diocgattr_arg *)data;
+
+		if (arg->len > sizeof(arg->value)) {
+			error = EINVAL;
+			break;
+		}
+		error = g_io_getattr(arg->name, cp, &arg->len, &arg->value);
+		break;
+	}
 	default:
 		if (cp->provider->geom->ioctl != NULL) {
 			error = cp->provider->geom->ioctl(cp->provider, cmd, data, fflag, td);

Modified: stable/10/sys/sys/disk.h
==============================================================================
--- stable/10/sys/sys/disk.h	Thu Nov 20 01:51:54 2014	(r274731)
+++ stable/10/sys/sys/disk.h	Thu Nov 20 01:55:12 2014	(r274732)
@@ -14,6 +14,7 @@
 #define	_SYS_DISK_H_
 
 #include <sys/ioccom.h>
+#include <sys/types.h>
 
 #ifdef _KERNEL
 
@@ -124,4 +125,14 @@ void disk_err(struct bio *bp, const char
 	 * occupant of that location.
 	 */
 
+struct diocgattr_arg {
+	char name[64];
+	int len;
+	union {
+		char str[DISK_IDENT_SIZE];
+		off_t off;
+	} value;
+};
+#define	DIOCGATTR _IOWR('d', 142, struct diocgattr_arg)
+
 #endif /* _SYS_DISK_H_ */

Modified: stable/10/usr.sbin/ctladm/ctladm.8
==============================================================================
--- stable/10/usr.sbin/ctladm/ctladm.8	Thu Nov 20 01:51:54 2014	(r274731)
+++ stable/10/usr.sbin/ctladm/ctladm.8	Thu Nov 20 01:55:12 2014	(r274732)
@@ -34,7 +34,7 @@
 .\" $Id: //depot/users/kenm/FreeBSD-test2/usr.sbin/ctladm/ctladm.8#3 $
 .\" $FreeBSD$
 .\"
-.Dd October 26, 2014
+.Dd November 5, 2014
 .Dt CTLADM 8
 .Os
 .Sh NAME
@@ -1003,6 +1003,14 @@ Specifies nominal form factor of the dev
 2 -- 3.5", 3 -- 2.5", 4 -- 1.8", 5 -- less then 1.8".
 .It Va unmap
 Set to "on", enables UNMAP support for the LUN, if supported by the backend.
+.It Va avail-threshold
+.It Va used-threshold
+.It Va pool-avail-threshold
+.It Va pool-used-threshold
+Set per-LUN/-pool thin provisioning soft thresholds for ZVOL-backed LUNs.
+LUN will establish UNIT ATTENTION condition if its or pool available space
+get below configured avail values, or its or pool used space get above
+configured used values.
 .It Va writecache
 Set to "off", disables write caching for the LUN, if supported by the backend.
 .El


help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201411200155.sAK1tDAT050034>