From 6414b04c27c11b1fb58b7605fde9797ffe3dfa32 Mon Sep 17 00:00:00 2001 From: mav Date: Thu, 20 Nov 2014 01:55:12 +0000 Subject: 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. --- sys/cam/ctl/ctl.c | 346 +++++++++++++++++++++++++++++++++++++--- sys/cam/ctl/ctl.h | 6 +- sys/cam/ctl/ctl_backend.h | 2 + sys/cam/ctl/ctl_backend_block.c | 44 ++++- sys/cam/ctl/ctl_error.c | 5 + sys/cam/ctl/ctl_private.h | 19 ++- sys/cam/scsi/scsi_all.h | 6 + 7 files changed, 402 insertions(+), 26 deletions(-) (limited to 'sys/cam') 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]; -- cgit v1.1