Index: sys/cam/ctl/ctl.h =================================================================== --- sys/cam/ctl/ctl.h +++ sys/cam/ctl/ctl.h @@ -194,24 +194,6 @@ void ctl_isc_announce_mode(struct ctl_lun *lun, uint32_t initidx, uint8_t page, uint8_t subpage); -/* - * KPI to manipulate LUN/port options - */ - -struct ctl_option { - STAILQ_ENTRY(ctl_option) links; - char *name; - char *value; -}; -typedef STAILQ_HEAD(ctl_options, ctl_option) ctl_options_t; - -struct ctl_be_arg; -void ctl_init_opts(ctl_options_t *opts, int num_args, struct ctl_be_arg *args); -void ctl_update_opts(ctl_options_t *opts, int num_args, - struct ctl_be_arg *args); -void ctl_free_opts(ctl_options_t *opts); -char * ctl_get_opt(ctl_options_t *opts, const char *name); -int ctl_get_opt_number(ctl_options_t *opts, const char *name, uint64_t *num); int ctl_expand_number(const char *buf, uint64_t *num); #endif /* _KERNEL */ Index: sys/cam/ctl/ctl.c =================================================================== --- sys/cam/ctl/ctl.c +++ sys/cam/ctl/ctl.c @@ -65,6 +65,8 @@ #include #include #include +#include +#include #include #include @@ -2414,105 +2416,6 @@ return (kptr); } -static void -ctl_free_args(int num_args, struct ctl_be_arg *args) -{ - int i; - - if (args == NULL) - return; - - for (i = 0; i < num_args; i++) { - free(args[i].kname, M_CTL); - free(args[i].kvalue, M_CTL); - } - - free(args, M_CTL); -} - -static struct ctl_be_arg * -ctl_copyin_args(int num_args, struct ctl_be_arg *uargs, - char *error_str, size_t error_str_len) -{ - struct ctl_be_arg *args; - int i; - - args = ctl_copyin_alloc(uargs, num_args * sizeof(*args), - error_str, error_str_len); - - if (args == NULL) - goto bailout; - - for (i = 0; i < num_args; i++) { - args[i].kname = NULL; - args[i].kvalue = NULL; - } - - for (i = 0; i < num_args; i++) { - uint8_t *tmpptr; - - if (args[i].namelen == 0) { - snprintf(error_str, error_str_len, "Argument %d " - "name length is zero", i); - goto bailout; - } - - args[i].kname = ctl_copyin_alloc(args[i].name, - args[i].namelen, error_str, error_str_len); - if (args[i].kname == NULL) - goto bailout; - - if (args[i].kname[args[i].namelen - 1] != '\0') { - snprintf(error_str, error_str_len, "Argument %d " - "name is not NUL-terminated", i); - goto bailout; - } - - if (args[i].flags & CTL_BEARG_RD) { - if (args[i].vallen == 0) { - snprintf(error_str, error_str_len, "Argument %d " - "value length is zero", i); - goto bailout; - } - - tmpptr = ctl_copyin_alloc(args[i].value, - args[i].vallen, error_str, error_str_len); - if (tmpptr == NULL) - goto bailout; - - if ((args[i].flags & CTL_BEARG_ASCII) - && (tmpptr[args[i].vallen - 1] != '\0')) { - snprintf(error_str, error_str_len, "Argument " - "%d value is not NUL-terminated", i); - free(tmpptr, M_CTL); - goto bailout; - } - args[i].kvalue = tmpptr; - } else { - args[i].kvalue = malloc(args[i].vallen, - M_CTL, M_WAITOK | M_ZERO); - } - } - - return (args); -bailout: - - ctl_free_args(num_args, args); - - return (NULL); -} - -static void -ctl_copyout_args(int num_args, struct ctl_be_arg *args) -{ - int i; - - for (i = 0; i < num_args; i++) { - if (args[i].flags & CTL_BEARG_WR) - copyout(args[i].kvalue, args[i].value, args[i].vallen); - } -} - /* * Escape characters that are illegal or not recommended in XML. */ @@ -2984,8 +2887,12 @@ case CTL_LUN_REQ: { struct ctl_lun_req *lun_req; struct ctl_backend_driver *backend; + void *packed; + nvlist_t *tmp_args_nvl; + size_t packed_len; lun_req = (struct ctl_lun_req *)addr; + tmp_args_nvl = lun_req->args_nvl; backend = ctl_backend_find(lun_req->backend); if (backend == NULL) { @@ -2996,25 +2903,44 @@ lun_req->backend); break; } - if (lun_req->num_be_args > 0) { - lun_req->kern_be_args = ctl_copyin_args( - lun_req->num_be_args, - lun_req->be_args, - lun_req->error_str, - sizeof(lun_req->error_str)); - if (lun_req->kern_be_args == NULL) { + + if (lun_req->args != NULL) { + lun_req->args = ctl_copyin_alloc(lun_req->args, + lun_req->args_len, lun_req->error_str, + sizeof(lun_req->error_str)); + + if (lun_req->args == NULL) { lun_req->status = CTL_LUN_ERROR; break; } - } + lun_req->args_nvl = nvlist_unpack(lun_req->args, + lun_req->args_len, 0); + + if (lun_req->args_nvl == NULL) { + lun_req->status = CTL_LUN_ERROR; + break; + } + } else + lun_req->args_nvl = nvlist_create(0); + retval = backend->ioctl(dev, cmd, addr, flag, td); + nvlist_destroy(lun_req->args_nvl); + lun_req->args_nvl = tmp_args_nvl; - if (lun_req->num_be_args > 0) { - ctl_copyout_args(lun_req->num_be_args, - lun_req->kern_be_args); - ctl_free_args(lun_req->num_be_args, - lun_req->kern_be_args); + if (lun_req->result_nvl != NULL) { + packed = nvlist_pack(lun_req->result_nvl, &packed_len); + if (packed == NULL) { + lun_req->status = CTL_LUN_ERROR; + break; + } + + if (packed_len <= lun_req->result_len) + copyout(packed, lun_req->result, packed_len); + + lun_req->result_len = packed_len; + free(packed, M_NVLIST); + nvlist_destroy(lun_req->result_nvl); } break; } @@ -3021,7 +2947,10 @@ case CTL_LUN_LIST: { struct sbuf *sb; struct ctl_lun_list *list; - struct ctl_option *opt; + const char *name, *value; + void *cookie = NULL; + int type; + uint64_t valuei; list = (struct ctl_lun_list *)addr; @@ -3147,11 +3076,24 @@ if (retval != 0) break; } - STAILQ_FOREACH(opt, &lun->be_lun->options, links) { - retval = sbuf_printf(sb, "\t<%s>%s\n", - opt->name, opt->value, opt->name); - if (retval != 0) - break; + + while ((name = nvlist_next(lun->be_lun->options, &type, + &cookie)) != NULL) { + sbuf_printf(sb, "\t<%s>", name); + + if (type == NV_TYPE_STRING) { + value = nvlist_get_string( + lun->be_lun->options, name); + sbuf_printf(sb, "%s", value); + } + + if (type == NV_TYPE_NUMBER) { + valuei = nvlist_get_number( + lun->be_lun->options, name); + sbuf_printf(sb, "%lu", valuei); + } + + sbuf_printf(sb, "\n", name); } retval = sbuf_printf(sb, "\n"); @@ -3205,8 +3147,12 @@ case CTL_PORT_REQ: { struct ctl_req *req; struct ctl_frontend *fe; + void *packed; + nvlist_t *tmp_args_nvl; + size_t packed_len; req = (struct ctl_req *)addr; + tmp_args_nvl = req->args_nvl; fe = ctl_frontend_find(req->driver); if (fe == NULL) { @@ -3215,23 +3161,54 @@ "Frontend \"%s\" not found.", req->driver); break; } - if (req->num_args > 0) { - req->kern_args = ctl_copyin_args(req->num_args, - req->args, req->error_str, sizeof(req->error_str)); - if (req->kern_args == NULL) { + + if (req->args != NULL) { + req->args = ctl_copyin_alloc(req->args, + req->args_len, req->error_str, + sizeof(req->error_str)); + + if (req->args == NULL) { req->status = CTL_LUN_ERROR; + snprintf(req->error_str, sizeof(req->error_str), + "Cannot copyin args."); break; } - } + req->args_nvl = nvlist_unpack(req->args, + req->args_len, 0); + + if (req->args_nvl == NULL) { + req->status = CTL_LUN_ERROR; + snprintf(req->error_str, sizeof(req->error_str), + "Cannot unpack args nvlist."); + break; + } + } else + req->args_nvl = nvlist_create(0); + if (fe->ioctl) retval = fe->ioctl(dev, cmd, addr, flag, td); else retval = ENODEV; - if (req->num_args > 0) { - ctl_copyout_args(req->num_args, req->kern_args); - ctl_free_args(req->num_args, req->kern_args); + nvlist_destroy(req->args_nvl); + req->args_nvl = tmp_args_nvl; + + if (req->result_nvl != NULL) { + packed = nvlist_pack(req->result_nvl, &packed_len); + if (packed == NULL) { + req->status = CTL_LUN_ERROR; + snprintf(req->error_str, sizeof(req->error_str), + "Cannot pack result nvlist."); + break; + } + + if (packed_len <= req->result_len) + copyout(packed, req->result, packed_len); + + req->result_len = packed_len; + free(packed, M_NVLIST); + nvlist_destroy(req->result_nvl); } break; } @@ -3239,8 +3216,10 @@ struct sbuf *sb; struct ctl_port *port; struct ctl_lun_list *list; - struct ctl_option *opt; - int j; + const char *name, *value; + void *cookie = NULL; + int j, type; + uint64_t valuei; uint32_t plun; list = (struct ctl_lun_list *)addr; @@ -3315,11 +3294,25 @@ if (retval != 0) break; } - STAILQ_FOREACH(opt, &port->options, links) { - retval = sbuf_printf(sb, "\t<%s>%s\n", - opt->name, opt->value, opt->name); - if (retval != 0) - break; + + printf("port_name = %s, port_options = %p\n", port->port_name, port->options); + while ((name = nvlist_next(port->options, &type, + &cookie)) != NULL) { + sbuf_printf(sb, "\t<%s>", name); + + if (type == NV_TYPE_STRING) { + value = nvlist_get_string(port->options, + name); + sbuf_printf(sb, "%s", value); + } + + if (type == NV_TYPE_NUMBER) { + valuei = nvlist_get_number(port->options, + name); + sbuf_printf(sb, "%lu", valuei); + } + + sbuf_printf(sb, "\n", name); } if (port->lun_map != NULL) { @@ -4126,8 +4119,8 @@ CTL_PAGE_DEFAULT]; scsi_ulto3b(cylinders, rigid_disk_page->cylinders); - if ((value = ctl_get_opt(&lun->be_lun->options, - "rpm")) != NULL) { + if ((value = dnvlist_get_string(lun->be_lun->options, + "rpm", NULL)) != NULL) { scsi_ulto2b(strtol(value, NULL, 0), rigid_disk_page->rotation_rate); } @@ -4180,10 +4173,12 @@ sizeof(caching_page_default)); caching_page = &lun->mode_pages.caching_page[ CTL_PAGE_SAVED]; - value = ctl_get_opt(&lun->be_lun->options, "writecache"); + value = dnvlist_get_string(lun->be_lun->options, + "writecache", NULL); if (value != NULL && strcmp(value, "off") == 0) caching_page->flags1 &= ~SCP_WCE; - value = ctl_get_opt(&lun->be_lun->options, "readcache"); + value = dnvlist_get_string(lun->be_lun->options, + "readcache", NULL); if (value != NULL && strcmp(value, "off") == 0) caching_page->flags1 |= SCP_RCD; memcpy(&lun->mode_pages.caching_page[CTL_PAGE_CURRENT], @@ -4212,8 +4207,8 @@ sizeof(control_page_default)); control_page = &lun->mode_pages.control_page[ CTL_PAGE_SAVED]; - value = ctl_get_opt(&lun->be_lun->options, - "reordering"); + value = dnvlist_get_string(lun->be_lun->options, + "reordering", NULL); if (value != NULL && strcmp(value, "unrestricted") == 0) { control_page->queue_flags &= @@ -4288,8 +4283,8 @@ &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"); + value = dnvlist_get_string(lun->be_lun->options, + "avail-threshold", NULL); if (value != NULL && ctl_expand_number(value, &ival) == 0) { page->descr[0].flags |= SLBPPD_ENABLED | @@ -4301,8 +4296,8 @@ scsi_ulto4b(ival >> CTL_LBP_EXPONENT, page->descr[0].count); } - value = ctl_get_opt(&lun->be_lun->options, - "used-threshold"); + value = dnvlist_get_string(lun->be_lun->options, + "used-threshold", NULL); if (value != NULL && ctl_expand_number(value, &ival) == 0) { page->descr[1].flags |= SLBPPD_ENABLED | @@ -4314,8 +4309,8 @@ scsi_ulto4b(ival >> CTL_LBP_EXPONENT, page->descr[1].count); } - value = ctl_get_opt(&lun->be_lun->options, - "pool-avail-threshold"); + value = dnvlist_get_string(lun->be_lun->options, + "pool-avail-threshold", NULL); if (value != NULL && ctl_expand_number(value, &ival) == 0) { page->descr[2].flags |= SLBPPD_ENABLED | @@ -4327,8 +4322,8 @@ scsi_ulto4b(ival >> CTL_LBP_EXPONENT, page->descr[2].count); } - value = ctl_get_opt(&lun->be_lun->options, - "pool-used-threshold"); + value = dnvlist_get_string(lun->be_lun->options, + "pool-used-threshold", NULL); if (value != NULL && ctl_expand_number(value, &ival) == 0) { page->descr[3].flags |= SLBPPD_ENABLED | @@ -4520,16 +4515,16 @@ strnlen(be_lun->device_id, CTL_DEVID_LEN)); idlen1 = sizeof(*t10id) + devidlen; len = sizeof(struct scsi_vpd_id_descriptor) + idlen1; - scsiname = ctl_get_opt(&be_lun->options, "scsiname"); + scsiname = dnvlist_get_string(be_lun->options, "scsiname", NULL); if (scsiname != NULL) { idlen2 = roundup2(strlen(scsiname) + 1, 4); len += sizeof(struct scsi_vpd_id_descriptor) + idlen2; } - eui = ctl_get_opt(&be_lun->options, "eui"); + eui = dnvlist_get_string(be_lun->options, "eui", NULL); if (eui != NULL) { len += sizeof(struct scsi_vpd_id_descriptor) + 16; } - naa = ctl_get_opt(&be_lun->options, "naa"); + naa = dnvlist_get_string(be_lun->options, "naa", NULL); if (naa != NULL) { len += sizeof(struct scsi_vpd_id_descriptor) + 16; } @@ -4545,7 +4540,7 @@ desc->length = idlen1; t10id = (struct scsi_vpd_id_t10 *)&desc->identifier[0]; memset(t10id->vendor, ' ', sizeof(t10id->vendor)); - if ((vendor = ctl_get_opt(&be_lun->options, "vendor")) == NULL) { + if ((vendor = dnvlist_get_string(be_lun->options, "vendor", NULL)) == NULL) { strncpy((char *)t10id->vendor, CTL_VENDOR, sizeof(t10id->vendor)); } else { strncpy(t10id->vendor, vendor, @@ -4658,7 +4653,7 @@ if (be_lun->flags & CTL_LUN_FLAG_PRIMARY) lun->flags |= CTL_LUN_PRIMARY_SC; - value = ctl_get_opt(&be_lun->options, "removable"); + value = dnvlist_get_string(be_lun->options, "removable", NULL); if (value != NULL) { if (strcmp(value, "on") == 0) lun->flags |= CTL_LUN_REMOVABLE; @@ -9745,12 +9740,16 @@ scsi_ulto4b(lun->be_lun->opttxferlen, bl_ptr->opt_txfer_len); if (lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) { ival = 0xffffffff; - ctl_get_opt_number(&lun->be_lun->options, - "unmap_max_lba", &ival); + val = dnvlist_get_string(lun->be_lun->options, + "unmap_max_lba", NULL); + if (val != NULL) + ctl_expand_number(val, &ival); scsi_ulto4b(ival, bl_ptr->max_unmap_lba_cnt); ival = 0xffffffff; - ctl_get_opt_number(&lun->be_lun->options, - "unmap_max_descr", &ival); + val = dnvlist_get_string(lun->be_lun->options, + "unmap_max_descr", NULL); + if (val != NULL) + ctl_expand_number(val, &ival); scsi_ulto4b(ival, bl_ptr->max_unmap_blk_cnt); if (lun->be_lun->ublockexp != 0) { scsi_ulto4b((1 << lun->be_lun->ublockexp), @@ -9766,7 +9765,10 @@ scsi_ulto4b(0, bl_ptr->max_atomic_transfer_length_with_atomic_boundary); scsi_ulto4b(0, bl_ptr->max_atomic_boundary_size); ival = UINT64_MAX; - ctl_get_opt_number(&lun->be_lun->options, "write_same_max_lba", &ival); + val = dnvlist_get_string(lun->be_lun->options, + "write_same_max_lba", NULL); + if (val != NULL) + ctl_expand_number(val, &ival); scsi_u64to8b(ival, bl_ptr->max_write_same_length); } @@ -9805,13 +9807,13 @@ bdc_ptr->page_code = SVPD_BDC; scsi_ulto2b(sizeof(*bdc_ptr) - 4, bdc_ptr->page_length); if (lun != NULL && - (value = ctl_get_opt(&lun->be_lun->options, "rpm")) != NULL) + (value = dnvlist_get_string(lun->be_lun->options, "rpm", NULL)) != NULL) i = strtol(value, NULL, 0); else i = CTL_DEFAULT_ROTATION_RATE; scsi_ulto2b(i, bdc_ptr->medium_rotation_rate); if (lun != NULL && - (value = ctl_get_opt(&lun->be_lun->options, "formfactor")) != NULL) + (value = dnvlist_get_string(lun->be_lun->options, "formfactor", NULL)) != NULL) i = strtol(value, NULL, 0); else i = 0; @@ -9856,7 +9858,8 @@ if (lun != NULL && lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) { lbp_ptr->flags = SVPD_LBP_UNMAP | SVPD_LBP_WS16 | SVPD_LBP_WS10 | SVPD_LBP_RZ | SVPD_LBP_ANC_SUP; - value = ctl_get_opt(&lun->be_lun->options, "provisioning_type"); + value = dnvlist_get_string(lun->be_lun->options, + "provisioning_type", NULL); if (value != NULL) { if (strcmp(value, "resource") == 0) lbp_ptr->prov_type = SVPD_LBP_RESOURCE; @@ -10028,8 +10031,8 @@ * We have 8 bytes for the vendor name, and 16 bytes for the device * name and 4 bytes for the revision. */ - if (lun == NULL || (val = ctl_get_opt(&lun->be_lun->options, - "vendor")) == NULL) { + if (lun == NULL || (val = dnvlist_get_string(lun->be_lun->options, + "vendor", NULL)) == NULL) { strncpy(inq_ptr->vendor, CTL_VENDOR, sizeof(inq_ptr->vendor)); } else { memset(inq_ptr->vendor, ' ', sizeof(inq_ptr->vendor)); @@ -10039,7 +10042,8 @@ if (lun == NULL) { strncpy(inq_ptr->product, CTL_DIRECT_PRODUCT, sizeof(inq_ptr->product)); - } else if ((val = ctl_get_opt(&lun->be_lun->options, "product")) == NULL) { + } else if ((val = dnvlist_get_string(lun->be_lun->options, "product", + NULL)) == NULL) { switch (lun->be_lun->lun_type) { case T_DIRECT: strncpy(inq_ptr->product, CTL_DIRECT_PRODUCT, @@ -10068,8 +10072,8 @@ * XXX make this a macro somewhere so it automatically gets * incremented when we make changes. */ - if (lun == NULL || (val = ctl_get_opt(&lun->be_lun->options, - "revision")) == NULL) { + if (lun == NULL || (val = dnvlist_get_string(lun->be_lun->options, + "revision", NULL)) == NULL) { strncpy(inq_ptr->revision, "0001", sizeof(inq_ptr->revision)); } else { memset(inq_ptr->revision, ' ', sizeof(inq_ptr->revision)); Index: sys/cam/ctl/ctl_backend.h =================================================================== --- sys/cam/ctl/ctl_backend.h +++ sys/cam/ctl/ctl_backend.h @@ -86,6 +86,8 @@ typedef void (*be_lun_config_t)(void *be_lun, ctl_lun_config_status status); +#include + /* * The lun_type field is the SCSI device type of this particular LUN. In * general, this should be T_DIRECT, although backends will want to create @@ -173,7 +175,7 @@ be_lun_config_t lun_config_status; /* passed to CTL */ struct ctl_backend_driver *be; /* passed to CTL */ void *ctl_lun; /* used by CTL */ - ctl_options_t options; /* passed to CTL */ + nvlist_t *options; /* passed to CTL */ STAILQ_ENTRY(ctl_be_lun) links; /* used by CTL */ }; Index: sys/cam/ctl/ctl_backend.c =================================================================== --- sys/cam/ctl/ctl_backend.c +++ sys/cam/ctl/ctl_backend.c @@ -139,93 +139,3 @@ return (NULL); } -void -ctl_init_opts(ctl_options_t *opts, int num_args, struct ctl_be_arg *args) -{ - struct ctl_option *opt; - int i; - - STAILQ_INIT(opts); - for (i = 0; i < num_args; i++) { - if ((args[i].flags & CTL_BEARG_RD) == 0) - continue; - if ((args[i].flags & CTL_BEARG_ASCII) == 0) - continue; - opt = malloc(sizeof(*opt), M_CTL, M_WAITOK); - opt->name = strdup(args[i].kname, M_CTL); - opt->value = strdup(args[i].kvalue, M_CTL); - STAILQ_INSERT_TAIL(opts, opt, links); - } -} - -void -ctl_update_opts(ctl_options_t *opts, int num_args, struct ctl_be_arg *args) -{ - struct ctl_option *opt; - int i; - - for (i = 0; i < num_args; i++) { - if ((args[i].flags & CTL_BEARG_RD) == 0) - continue; - if ((args[i].flags & CTL_BEARG_ASCII) == 0) - continue; - STAILQ_FOREACH(opt, opts, links) { - if (strcmp(opt->name, args[i].kname) == 0) - break; - } - if (args[i].kvalue != NULL && - ((char *)args[i].kvalue)[0] != 0) { - if (opt) { - free(opt->value, M_CTL); - opt->value = strdup(args[i].kvalue, M_CTL); - } else { - opt = malloc(sizeof(*opt), M_CTL, M_WAITOK); - opt->name = strdup(args[i].kname, M_CTL); - opt->value = strdup(args[i].kvalue, M_CTL); - STAILQ_INSERT_TAIL(opts, opt, links); - } - } else if (opt) { - STAILQ_REMOVE(opts, opt, ctl_option, links); - free(opt->name, M_CTL); - free(opt->value, M_CTL); - free(opt, M_CTL); - } - } -} - -void -ctl_free_opts(ctl_options_t *opts) -{ - struct ctl_option *opt; - - while ((opt = STAILQ_FIRST(opts)) != NULL) { - STAILQ_REMOVE_HEAD(opts, links); - free(opt->name, M_CTL); - free(opt->value, M_CTL); - free(opt, M_CTL); - } -} - -char * -ctl_get_opt(ctl_options_t *opts, const char *name) -{ - struct ctl_option *opt; - - STAILQ_FOREACH(opt, opts, links) { - if (strcmp(opt->name, name) == 0) { - return (opt->value); - } - } - return (NULL); -} - -int -ctl_get_opt_number(ctl_options_t *opts, const char *name, uint64_t *val) -{ - const char *value; - - value = ctl_get_opt(opts, name); - if (value == NULL) - return (-2); - return (ctl_expand_number(value, val)); -} Index: sys/cam/ctl/ctl_backend_block.c =================================================================== --- sys/cam/ctl/ctl_backend_block.c +++ sys/cam/ctl/ctl_backend_block.c @@ -76,6 +76,8 @@ #include #include #include +#include +#include #include @@ -1815,7 +1817,7 @@ struct ctl_be_lun *cbe_lun; struct ctl_be_block_filedata *file_data; struct ctl_lun_create_params *params; - char *value; + const char *value; struct vattr vattr; off_t ps, pss, po, pos, us, uss, uo, uos; int error; @@ -1865,10 +1867,10 @@ us = ps = vattr.va_blocksize; uo = po = 0; - value = ctl_get_opt(&cbe_lun->options, "pblocksize"); + value = dnvlist_get_string(cbe_lun->options, "pblocksize", NULL); if (value != NULL) ctl_expand_number(value, &ps); - value = ctl_get_opt(&cbe_lun->options, "pblockoffset"); + value = dnvlist_get_string(cbe_lun->options, "pblockoffset", NULL); if (value != NULL) ctl_expand_number(value, &po); pss = ps / cbe_lun->blocksize; @@ -1879,10 +1881,10 @@ cbe_lun->pblockoff = (pss - pos) % pss; } - value = ctl_get_opt(&cbe_lun->options, "ublocksize"); + value = dnvlist_get_string(cbe_lun->options, "ublocksize", NULL); if (value != NULL) ctl_expand_number(value, &us); - value = ctl_get_opt(&cbe_lun->options, "ublockoffset"); + value = dnvlist_get_string(cbe_lun->options, "ublockoffset", NULL); if (value != NULL) ctl_expand_number(value, &uo); uss = us / cbe_lun->blocksize; @@ -1915,7 +1917,7 @@ struct ctl_lun_create_params *params; struct cdevsw *csw; struct cdev *dev; - char *value; + const char *value; int error, atomic, maxio, ref, unmap, tmp; off_t ps, pss, po, pos, us, uss, uo, uos, otmp; @@ -2031,10 +2033,10 @@ us = ps; uo = po; - value = ctl_get_opt(&cbe_lun->options, "pblocksize"); + value = dnvlist_get_string(cbe_lun->options, "pblocksize", NULL); if (value != NULL) ctl_expand_number(value, &ps); - value = ctl_get_opt(&cbe_lun->options, "pblockoffset"); + value = dnvlist_get_string(cbe_lun->options, "pblockoffset", NULL); if (value != NULL) ctl_expand_number(value, &po); pss = ps / cbe_lun->blocksize; @@ -2045,10 +2047,10 @@ cbe_lun->pblockoff = (pss - pos) % pss; } - value = ctl_get_opt(&cbe_lun->options, "ublocksize"); + value = dnvlist_get_string(cbe_lun->options, "ublocksize", NULL); if (value != NULL) ctl_expand_number(value, &us); - value = ctl_get_opt(&cbe_lun->options, "ublockoffset"); + value = dnvlist_get_string(cbe_lun->options, "ublockoffset", NULL); if (value != NULL) ctl_expand_number(value, &uo); uss = us / cbe_lun->blocksize; @@ -2073,7 +2075,7 @@ curthread); unmap = (error == 0) ? arg.value.i : 0; } - value = ctl_get_opt(&cbe_lun->options, "unmap"); + value = dnvlist_get_string(cbe_lun->options, "unmap", NULL); if (value != NULL) unmap = (strcmp(value, "on") == 0); if (unmap) @@ -2123,7 +2125,7 @@ { struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; struct nameidata nd; - char *value; + const char *value; int error, flags; error = 0; @@ -2134,7 +2136,7 @@ } pwd_ensure_dirs(); - value = ctl_get_opt(&cbe_lun->options, "file"); + value = dnvlist_get_string(cbe_lun->options, "file", NULL); if (value == NULL) { snprintf(req->error_str, sizeof(req->error_str), "no file argument specified"); @@ -2144,7 +2146,7 @@ be_lun->dev_path = strdup(value, M_CTLBLK); flags = FREAD; - value = ctl_get_opt(&cbe_lun->options, "readonly"); + value = dnvlist_get_string(cbe_lun->options, "readonly", NULL); if (value != NULL) { if (strcmp(value, "on") != 0) flags |= FWRITE; @@ -2203,7 +2205,7 @@ cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; if (be_lun->dispatch != ctl_be_block_dispatch_dev) cbe_lun->serseq = CTL_LUN_SERSEQ_READ; - value = ctl_get_opt(&cbe_lun->options, "serseq"); + value = dnvlist_get_string(cbe_lun->options, "serseq", NULL); if (value != NULL && strcmp(value, "on") == 0) cbe_lun->serseq = CTL_LUN_SERSEQ_ON; else if (value != NULL && strcmp(value, "read") == 0) @@ -2221,7 +2223,7 @@ struct ctl_lun_create_params *params; char num_thread_str[16]; char tmpstr[32]; - char *value; + const char *value; int retval, num_threads; int tmp_num_threads; @@ -2241,8 +2243,7 @@ sprintf(be_lun->lunname, "cblk%d", softc->num_luns); mtx_init(&be_lun->io_lock, "cblk io lock", NULL, MTX_DEF); mtx_init(&be_lun->queue_lock, "cblk queue lock", NULL, MTX_DEF); - ctl_init_opts(&cbe_lun->options, - req->num_be_args, req->kern_be_args); + cbe_lun->options = nvlist_clone(req->args_nvl); be_lun->lun_zone = uma_zcreate(be_lun->lunname, CTLBLK_MAX_SEG, NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0); if (be_lun->lun_zone == NULL) { @@ -2257,7 +2258,7 @@ cbe_lun->lun_type = T_DIRECT; be_lun->flags = CTL_BE_BLOCK_LUN_UNCONFIGURED; cbe_lun->flags = 0; - value = ctl_get_opt(&cbe_lun->options, "ha_role"); + value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); if (value != NULL) { if (strcmp(value, "primary") == 0) cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; @@ -2290,7 +2291,7 @@ num_threads = 1; } - value = ctl_get_opt(&cbe_lun->options, "num_threads"); + value = dnvlist_get_string(cbe_lun->options, "num_threads", NULL); if (value != NULL) { tmp_num_threads = strtol(value, NULL, 0); @@ -2455,7 +2456,7 @@ free(be_lun->dev_path, M_CTLBLK); if (be_lun->lun_zone != NULL) uma_zdestroy(be_lun->lun_zone); - ctl_free_opts(&cbe_lun->options); + nvlist_destroy(cbe_lun->options); mtx_destroy(&be_lun->queue_lock); mtx_destroy(&be_lun->io_lock); free(be_lun, M_CTLBLK); @@ -2539,7 +2540,7 @@ uma_zdestroy(be_lun->lun_zone); - ctl_free_opts(&cbe_lun->options); + nvlist_destroy(cbe_lun->options); free(be_lun->dev_path, M_CTLBLK); mtx_destroy(&be_lun->queue_lock); mtx_destroy(&be_lun->io_lock); @@ -2559,7 +2560,7 @@ struct ctl_lun_modify_params *params; struct ctl_be_block_lun *be_lun; struct ctl_be_lun *cbe_lun; - char *value; + const char *value; uint64_t oldsize; int error, wasprim; @@ -2581,10 +2582,12 @@ if (params->lun_size_bytes != 0) be_lun->params.lun_size_bytes = params->lun_size_bytes; - ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); + nvlist_destroy(cbe_lun->options); + cbe_lun->options = nvlist_clone(req->args_nvl); + wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); - value = ctl_get_opt(&cbe_lun->options, "ha_role"); + value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); if (value != NULL) { if (strcmp(value, "primary") == 0) cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; Index: sys/cam/ctl/ctl_backend_ramdisk.c =================================================================== --- sys/cam/ctl/ctl_backend_ramdisk.c +++ sys/cam/ctl/ctl_backend_ramdisk.c @@ -58,6 +58,8 @@ #include #include #include +#include +#include #include #include @@ -465,7 +467,7 @@ if (retval == 0) { taskqueue_drain_all(be_lun->io_taskqueue); taskqueue_free(be_lun->io_taskqueue); - ctl_free_opts(&be_lun->cbe_lun.options); + nvlist_destroy(be_lun->cbe_lun.options); mtx_destroy(&be_lun->queue_lock); free(be_lun, M_RAMDISK); } @@ -485,7 +487,7 @@ struct ctl_be_ramdisk_lun *be_lun; struct ctl_be_lun *cbe_lun; struct ctl_lun_create_params *params; - char *value; + const char *value; char tmpstr[32]; int retval; @@ -495,10 +497,10 @@ be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | M_WAITOK); cbe_lun = &be_lun->cbe_lun; cbe_lun->be_lun = be_lun; + cbe_lun->options = nvlist_clone(req->args_nvl); be_lun->params = req->reqdata.create; be_lun->softc = softc; sprintf(be_lun->lunname, "cram%d", softc->num_luns); - ctl_init_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); if (params->flags & CTL_LUN_FLAG_DEV_TYPE) cbe_lun->lun_type = params->device_type; @@ -506,7 +508,7 @@ cbe_lun->lun_type = T_DIRECT; be_lun->flags = CTL_BE_RAMDISK_LUN_UNCONFIGURED; cbe_lun->flags = 0; - value = ctl_get_opt(&cbe_lun->options, "ha_role"); + value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); if (value != NULL) { if (strcmp(value, "primary") == 0) cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; @@ -538,10 +540,10 @@ params->blocksize_bytes = cbe_lun->blocksize; params->lun_size_bytes = be_lun->size_bytes; - value = ctl_get_opt(&cbe_lun->options, "unmap"); + value = dnvlist_get_string(cbe_lun->options, "unmap", NULL); if (value != NULL && strcmp(value, "on") == 0) cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; - value = ctl_get_opt(&cbe_lun->options, "readonly"); + value = dnvlist_get_string(cbe_lun->options, "readonly", NULL); if (value != NULL) { if (strcmp(value, "on") == 0) cbe_lun->flags |= CTL_LUN_FLAG_READONLY; @@ -548,7 +550,7 @@ } else if (cbe_lun->lun_type != T_DIRECT) cbe_lun->flags |= CTL_LUN_FLAG_READONLY; cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; - value = ctl_get_opt(&cbe_lun->options, "serseq"); + value = dnvlist_get_string(cbe_lun->options, "serseq", NULL); if (value != NULL && strcmp(value, "on") == 0) cbe_lun->serseq = CTL_LUN_SERSEQ_ON; else if (value != NULL && strcmp(value, "read") == 0) @@ -671,7 +673,7 @@ if (be_lun->io_taskqueue != NULL) { taskqueue_free(be_lun->io_taskqueue); } - ctl_free_opts(&cbe_lun->options); + nvlist_destroy(cbe_lun->options); mtx_destroy(&be_lun->queue_lock); free(be_lun, M_RAMDISK); } @@ -685,7 +687,7 @@ struct ctl_be_ramdisk_lun *be_lun; struct ctl_be_lun *cbe_lun; struct ctl_lun_modify_params *params; - char *value; + const char *value; uint32_t blocksize; int wasprim; @@ -707,10 +709,12 @@ if (params->lun_size_bytes != 0) be_lun->params.lun_size_bytes = params->lun_size_bytes; - ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); + nvlist_destroy(cbe_lun->options); + cbe_lun->options = nvlist_clone(req->args_nvl); + wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); - value = ctl_get_opt(&cbe_lun->options, "ha_role"); + value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); if (value != NULL) { if (strcmp(value, "primary") == 0) cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; Index: sys/cam/ctl/ctl_frontend.h =================================================================== --- sys/cam/ctl/ctl_frontend.h +++ sys/cam/ctl/ctl_frontend.h @@ -42,6 +42,8 @@ #include +#include + typedef enum { CTL_PORT_STATUS_NONE = 0x00, CTL_PORT_STATUS_ONLINE = 0x01, @@ -235,7 +237,7 @@ uint64_t wwnn; /* set by CTL before online */ uint64_t wwpn; /* set by CTL before online */ ctl_port_status status; /* used by CTL */ - ctl_options_t options; /* passed to CTL */ + nvlist_t *options; /* passed to CTL */ struct ctl_devid *port_devid; /* passed to CTL */ struct ctl_devid *target_devid; /* passed to CTL */ struct ctl_devid *init_devid; /* passed to CTL */ Index: sys/cam/ctl/ctl_frontend.c =================================================================== --- sys/cam/ctl/ctl_frontend.c +++ sys/cam/ctl/ctl_frontend.c @@ -50,6 +50,8 @@ #include #include #include +#include +#include #include #include @@ -238,7 +240,7 @@ mtx_unlock(&softc->ctl_lock); ctl_pool_free(pool); - ctl_free_opts(&port->options); + nvlist_destroy(port->options); ctl_lun_map_deinit(port); free(port->port_devid, M_CTL); @@ -329,7 +331,7 @@ port->port_online(port->onoff_arg); mtx_lock(&softc->ctl_lock); if (softc->is_single == 0) { - value = ctl_get_opt(&port->options, "ha_shared"); + value = dnvlist_get_string(port->options, "ha_shared", NULL); if (value != NULL && strcmp(value, "on") == 0) port->status |= CTL_PORT_STATUS_HA_SHARED; else Index: sys/cam/ctl/ctl_frontend_ioctl.c =================================================================== --- sys/cam/ctl/ctl_frontend_ioctl.c +++ sys/cam/ctl/ctl_frontend_ioctl.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include Index: sys/cam/ctl/ctl_frontend_iscsi.c =================================================================== --- sys/cam/ctl/ctl_frontend_iscsi.c +++ sys/cam/ctl/ctl_frontend_iscsi.c @@ -54,6 +54,8 @@ #include #include #include +#include +#include #include #include @@ -2074,30 +2076,29 @@ { struct cfiscsi_target *ct; struct ctl_port *port; - const char *target, *alias, *tags; + const char *target, *alias; struct scsi_vpd_id_descriptor *desc; - ctl_options_t opts; int retval, len, idlen; - uint16_t tag; + int64_t tag; - ctl_init_opts(&opts, req->num_args, req->kern_args); - target = ctl_get_opt(&opts, "cfiscsi_target"); - alias = ctl_get_opt(&opts, "cfiscsi_target_alias"); - tags = ctl_get_opt(&opts, "cfiscsi_portal_group_tag"); - if (target == NULL || tags == NULL) { + target = dnvlist_get_string(req->args_nvl, "cfiscsi_target", NULL); + alias = dnvlist_get_string(req->args_nvl, "cfiscsi_target_alias", NULL); + tag = (int64_t)dnvlist_get_number(req->args_nvl, + "cfiscsi_portal_group_tag", (uint64_t)-1); + + if (target == NULL || tag == -1) { req->status = CTL_LUN_ERROR; snprintf(req->error_str, sizeof(req->error_str), "Missing required argument"); - ctl_free_opts(&opts); return; } - tag = strtol(tags, (char **)NULL, 10); - ct = cfiscsi_target_find_or_create(&cfiscsi_softc, target, alias, tag); + + ct = cfiscsi_target_find_or_create(&cfiscsi_softc, target, alias, + (uint16_t)tag); if (ct == NULL) { req->status = CTL_LUN_ERROR; snprintf(req->error_str, sizeof(req->error_str), "failed to create target \"%s\"", target); - ctl_free_opts(&opts); return; } if (ct->ct_state == CFISCSI_TARGET_STATE_ACTIVE) { @@ -2106,7 +2107,6 @@ "target \"%s\" for portal group tag %u already exists", target, tag); cfiscsi_target_release(ct); - ctl_free_opts(&opts); return; } port = &ct->ct_port; @@ -2119,7 +2119,7 @@ /* XXX KDM what should the real number be here? */ port->num_requested_ctl_io = 4096; port->port_name = "iscsi"; - port->physical_port = tag; + port->physical_port = (int)tag; port->virtual_port = ct->ct_target_id; port->port_online = cfiscsi_online; port->port_offline = cfiscsi_offline; @@ -2128,10 +2128,8 @@ port->fe_datamove = cfiscsi_datamove; port->fe_done = cfiscsi_done; port->targ_port = -1; + port->options = nvlist_clone(req->args_nvl); - port->options = opts; - STAILQ_INIT(&opts); - /* Generate Port ID. */ idlen = strlen(target) + strlen(",t,0x0001") + 1; idlen = roundup2(idlen, 4); @@ -2144,7 +2142,7 @@ desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT | SVPD_ID_TYPE_SCSI_NAME; desc->length = idlen; - snprintf(desc->identifier, idlen, "%s,t,0x%4.4x", target, tag); + snprintf(desc->identifier, idlen, "%s,t,0x%4.4lx", target, tag); /* Generate Target ID. */ idlen = strlen(target) + 1; @@ -2162,7 +2160,6 @@ retval = ctl_port_register(port); if (retval != 0) { - ctl_free_opts(&port->options); cfiscsi_target_release(ct); free(port->port_devid, M_CFISCSI); free(port->target_devid, M_CFISCSI); @@ -2174,8 +2171,8 @@ done: ct->ct_state = CFISCSI_TARGET_STATE_ACTIVE; req->status = CTL_LUN_OK; - memcpy(req->kern_args[0].kvalue, &port->targ_port, - sizeof(port->targ_port)); //XXX + req->result_nvl = nvlist_create(0); + nvlist_add_number(req->result_nvl, "port_id", port->targ_port); } static void @@ -2182,24 +2179,22 @@ cfiscsi_ioctl_port_remove(struct ctl_req *req) { struct cfiscsi_target *ct; - const char *target, *tags; - ctl_options_t opts; + const char *target; uint16_t tag; - ctl_init_opts(&opts, req->num_args, req->kern_args); - target = ctl_get_opt(&opts, "cfiscsi_target"); - tags = ctl_get_opt(&opts, "cfiscsi_portal_group_tag"); - if (target == NULL || tags == NULL) { - ctl_free_opts(&opts); + target = dnvlist_get_string(req->args_nvl, "cfiscsi_target", NULL); + tag = (uint16_t)dnvlist_get_number(req->args_nvl, + "cfiscsi_portal_group_tag", 0); + + if (target == NULL || tag == 0) { req->status = CTL_LUN_ERROR; snprintf(req->error_str, sizeof(req->error_str), "Missing required argument"); return; } - tag = strtol(tags, (char **)NULL, 10); + ct = cfiscsi_target_find(&cfiscsi_softc, target, tag); if (ct == NULL) { - ctl_free_opts(&opts); req->status = CTL_LUN_ERROR; snprintf(req->error_str, sizeof(req->error_str), "can't find target \"%s\"", target); @@ -2206,13 +2201,11 @@ return; } if (ct->ct_state != CFISCSI_TARGET_STATE_ACTIVE) { - ctl_free_opts(&opts); req->status = CTL_LUN_ERROR; snprintf(req->error_str, sizeof(req->error_str), "target \"%s\" is already dying", target); return; } - ctl_free_opts(&opts); ct->ct_state = CFISCSI_TARGET_STATE_DYING; ctl_port_offline(&ct->ct_port); Index: sys/cam/ctl/ctl_ioctl.h =================================================================== --- sys/cam/ctl/ctl_ioctl.h +++ sys/cam/ctl/ctl_ioctl.h @@ -46,6 +46,7 @@ #endif #include +#include #define CTL_DEFAULT_DEV "/dev/cam/ctl" /* @@ -334,34 +335,6 @@ #define CTL_BEARG_RW (CTL_BEARG_RD|CTL_BEARG_WR) #define CTL_BEARG_ASCII 0x04 -/* - * Backend Argument: - * - * namelen: Length of the name field, including the terminating NUL. - * - * name: Name of the parameter. This must be NUL-terminated. - * - * flags: Flags for the parameter, see above for values. - * - * vallen: Length of the value in bytes, including the terminating NUL. - * - * value: Value to be set/fetched. This must be NUL-terminated. - * - * kname: For kernel use only. - * - * kvalue: For kernel use only. - */ -struct ctl_be_arg { - unsigned int namelen; - char *name; - int flags; - unsigned int vallen; - void *value; - - char *kname; - void *kvalue; -}; - typedef enum { CTL_LUNREQ_CREATE, CTL_LUNREQ_RM, @@ -537,11 +510,14 @@ char backend[CTL_BE_NAME_LEN]; ctl_lunreq_type reqtype; union ctl_lunreq_data reqdata; - int num_be_args; - struct ctl_be_arg *be_args; + void * args; + nvlist_t * args_nvl; + size_t args_len; + void * result; + nvlist_t * result_nvl; + size_t result_len; ctl_lun_status status; char error_str[CTL_ERROR_STR_LEN]; - struct ctl_be_arg *kern_be_args; }; /* @@ -630,11 +606,14 @@ struct ctl_req { char driver[CTL_DRIVER_NAME_LEN]; ctl_req_type reqtype; - int num_args; - struct ctl_be_arg *args; + void * args; + nvlist_t * args_nvl; + size_t args_len; + void * result; + nvlist_t * result_nvl; + size_t result_len; ctl_lun_status status; char error_str[CTL_ERROR_STR_LEN]; - struct ctl_be_arg *kern_args; }; /* Index: sys/cam/ctl/ctl_tpc.c =================================================================== --- sys/cam/ctl/ctl_tpc.c +++ sys/cam/ctl/ctl_tpc.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -1652,7 +1654,7 @@ struct scsi_ec_segment *seg; struct tpc_list *list, *tlist; uint8_t *ptr; - char *value; + const char *value; int len, off, lencscd, lenseg, leninl, nseg; CTL_DEBUG_PRINT(("ctl_extended_copy_lid1\n")); @@ -1715,7 +1717,7 @@ list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO); list->service_action = cdb->service_action; - value = ctl_get_opt(&lun->be_lun->options, "insecure_tpc"); + value = dnvlist_get_string(lun->be_lun->options, "insecure_tpc", NULL); if (value != NULL && strcmp(value, "on") == 0) list->init_port = -1; else @@ -1806,7 +1808,7 @@ struct scsi_ec_segment *seg; struct tpc_list *list, *tlist; uint8_t *ptr; - char *value; + const char *value; int len, off, lencscd, lenseg, leninl, nseg; CTL_DEBUG_PRINT(("ctl_extended_copy_lid4\n")); @@ -1869,7 +1871,7 @@ list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO); list->service_action = cdb->service_action; - value = ctl_get_opt(&lun->be_lun->options, "insecure_tpc"); + value = dnvlist_get_string(lun->be_lun->options, "insecure_tpc", NULL); if (value != NULL && strcmp(value, "on") == 0) list->init_port = -1; else Index: usr.sbin/ctladm/Makefile =================================================================== --- usr.sbin/ctladm/Makefile +++ usr.sbin/ctladm/Makefile @@ -14,7 +14,7 @@ WARNS?= 3 .endif -LIBADD= cam sbuf bsdxml util +LIBADD= cam sbuf bsdxml util nv MAN= ctladm.8 .include Index: usr.sbin/ctladm/ctladm.c =================================================================== --- usr.sbin/ctladm/ctladm.c +++ usr.sbin/ctladm/ctladm.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -151,6 +152,14 @@ const char *subopt; }; +struct cctl_req_option { + char *name; + int namelen; + char *value; + int vallen; + STAILQ_ENTRY(cctl_req_option) links; +}; + typedef enum { CC_OR_NOT_FOUND, CC_OR_AMBIGUOUS, @@ -393,8 +402,11 @@ cctl_port_mode port_mode = CCTL_PORT_MODE_NONE; struct ctl_port_entry entry; ctl_port_type port_type = CTL_PORT_NONE; + STAILQ_HEAD(, cctl_req_option) option_list; int quiet = 0, xml = 0; + STAILQ_INIT(&option_list); + while ((c = getopt(argc, argv, combinedopt)) != -1) { switch (c) { case 'l': @@ -403,7 +415,7 @@ port_mode = CCTL_PORT_MODE_LIST; break; - case 'o': + case 'i': if (port_mode != CCTL_PORT_MODE_NONE) goto bailout_badarg; @@ -412,7 +424,7 @@ else if (strcasecmp(optarg, "off") == 0) port_mode = CCTL_PORT_MODE_OFF; else { - warnx("Invalid -o argument %s, \"on\" or " + warnx("Invalid -i argument %s, \"on\" or " "\"off\" are the only valid args", optarg); retval = 1; @@ -419,6 +431,40 @@ goto bailout; } break; + case 'o': { + struct cctl_req_option *option; + char *tmpstr; + char *name, *value; + + tmpstr = strdup(optarg); + name = strsep(&tmpstr, "="); + if (name == NULL) { + warnx("%s: option -o takes \"name=value\"" + "argument", __func__); + retval = 1; + goto bailout; + } + value = strsep(&tmpstr, "="); + if (value == NULL) { + warnx("%s: option -o takes \"name=value\"" + "argument", __func__); + retval = 1; + goto bailout; + } + option = malloc(sizeof(*option)); + if (option == NULL) { + warn("%s: error allocating %zd bytes", + __func__, sizeof(*option)); + retval = 1; + goto bailout; + } + option->name = strdup(name); + option->value = strdup(value); + free(tmpstr); + + STAILQ_INSERT_TAIL(&option_list, option, links); + break; + } case 'p': targ_port = strtol(optarg, NULL, 0); break; @@ -2271,14 +2317,6 @@ return (retval); } -struct cctl_req_option { - char *name; - int namelen; - char *value; - int vallen; - STAILQ_ENTRY(cctl_req_option) links; -}; - static int cctl_create_lun(int fd, int argc, char **argv, char *combinedopt) { @@ -2413,15 +2451,13 @@ req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID; } - req.num_be_args = num_options; - if (num_options > 0) { + if (!STAILQ_EMPTY(&option_list)) { struct cctl_req_option *option, *next_option; int i; - req.be_args = malloc(num_options * sizeof(*req.be_args)); - if (req.be_args == NULL) { - warn("%s: error allocating %zd bytes", __func__, - num_options * sizeof(*req.be_args)); + req.args_nvl = nvlist_create(0); + if (req.args_nvl == NULL) { + warn("%s: error allocating nvlist", __func__); retval = 1; goto bailout; } @@ -2429,24 +2465,21 @@ for (i = 0, option = STAILQ_FIRST(&option_list); i < num_options; i++, option = next_option) { next_option = STAILQ_NEXT(option, links); - - req.be_args[i].namelen = option->namelen; - req.be_args[i].name = strdup(option->name); - req.be_args[i].vallen = option->vallen; - req.be_args[i].value = strdup(option->value); - /* - * XXX KDM do we want a way to specify a writeable - * flag of some sort? Do we want a way to specify - * binary data? - */ - req.be_args[i].flags = CTL_BEARG_ASCII | CTL_BEARG_RD; - + nvlist_add_string(req.args_nvl, option->name, + option->value); STAILQ_REMOVE(&option_list, option, cctl_req_option, - links); + links); free(option->name); free(option->value); free(option); } + + req.args = nvlist_pack(req.args_nvl, &req.args_len); + if (req.args == NULL) { + warn("%s: error packing nvlist", __func__); + retval = 1; + goto bailout; + } } if (ioctl(fd, CTL_LUN_REQ, &req) == -1) { @@ -2480,7 +2513,7 @@ req.reqdata.create.blocksize_bytes); fprintf(stdout, "LUN ID: %d\n", req.reqdata.create.req_lun_id); fprintf(stdout, "Serial Number: %s\n", req.reqdata.create.serial_num); - fprintf(stdout, "Device ID; %s\n", req.reqdata.create.device_id); + fprintf(stdout, "Device ID: %s\n", req.reqdata.create.device_id); bailout: return (retval); @@ -2563,15 +2596,14 @@ req.reqdata.rm.lun_id = lun_id; - req.num_be_args = num_options; - if (num_options > 0) { + if (!STAILQ_EMPTY(&option_list)) { struct cctl_req_option *option, *next_option; int i; - req.be_args = malloc(num_options * sizeof(*req.be_args)); - if (req.be_args == NULL) { - warn("%s: error allocating %zd bytes", __func__, - num_options * sizeof(*req.be_args)); + req.args_nvl = nvlist_create(0); + + if (req.args_nvl == NULL) { + warn("%s: error allocating nvlist", __func__); retval = 1; goto bailout; } @@ -2579,24 +2611,21 @@ for (i = 0, option = STAILQ_FIRST(&option_list); i < num_options; i++, option = next_option) { next_option = STAILQ_NEXT(option, links); - - req.be_args[i].namelen = option->namelen; - req.be_args[i].name = strdup(option->name); - req.be_args[i].vallen = option->vallen; - req.be_args[i].value = strdup(option->value); - /* - * XXX KDM do we want a way to specify a writeable - * flag of some sort? Do we want a way to specify - * binary data? - */ - req.be_args[i].flags = CTL_BEARG_ASCII | CTL_BEARG_RD; - + nvlist_add_string(req.args_nvl, option->name, + option->value); STAILQ_REMOVE(&option_list, option, cctl_req_option, - links); + links); free(option->name); free(option->value); free(option); } + + req.args = nvlist_pack(req.args_nvl, &req.args_len); + if (req.args == NULL) { + warn("%s: error packing nvlist", __func__); + retval = 1; + goto bailout; + } } if (ioctl(fd, CTL_LUN_REQ, &req) == -1) { @@ -2721,15 +2750,14 @@ req.reqdata.modify.lun_id = lun_id; req.reqdata.modify.lun_size_bytes = lun_size; - req.num_be_args = num_options; - if (num_options > 0) { + if (!STAILQ_EMPTY(&option_list)) { struct cctl_req_option *option, *next_option; int i; - req.be_args = malloc(num_options * sizeof(*req.be_args)); - if (req.be_args == NULL) { - warn("%s: error allocating %zd bytes", __func__, - num_options * sizeof(*req.be_args)); + req.args_nvl = nvlist_create(0); + + if (req.args_nvl == NULL) { + warn("%s: error allocating nvlist", __func__); retval = 1; goto bailout; } @@ -2737,24 +2765,21 @@ for (i = 0, option = STAILQ_FIRST(&option_list); i < num_options; i++, option = next_option) { next_option = STAILQ_NEXT(option, links); - - req.be_args[i].namelen = option->namelen; - req.be_args[i].name = strdup(option->name); - req.be_args[i].vallen = option->vallen; - req.be_args[i].value = strdup(option->value); - /* - * XXX KDM do we want a way to specify a writeable - * flag of some sort? Do we want a way to specify - * binary data? - */ - req.be_args[i].flags = CTL_BEARG_ASCII | CTL_BEARG_RD; - + nvlist_add_string(req.args_nvl, option->name, + option->value); STAILQ_REMOVE(&option_list, option, cctl_req_option, - links); + links); free(option->name); free(option->value); free(option); } + + req.args = nvlist_pack(req.args_nvl, &req.args_len); + if (req.args == NULL) { + warn("%s: error packing nvlist", __func__); + retval = 1; + goto bailout; + } } if (ioctl(fd, CTL_LUN_REQ, &req) == -1) { Index: usr.sbin/ctld/Makefile =================================================================== --- usr.sbin/ctld/Makefile +++ usr.sbin/ctld/Makefile @@ -13,7 +13,7 @@ #CFLAGS+= -DICL_KERNEL_PROXY MAN= ctld.8 ctl.conf.5 -LIBADD= bsdxml l md sbuf util ucl m +LIBADD= bsdxml l md sbuf util ucl m nv YFLAGS+= -v CLEANFILES= y.tab.c y.tab.h y.output Index: usr.sbin/ctld/ctld.h =================================================================== --- usr.sbin/ctld/ctld.h +++ usr.sbin/ctld/ctld.h @@ -150,7 +150,9 @@ struct pport *p_pport; struct target *p_target; int p_foreign; - + int p_ioctl_port; + int p_ioctl_pp; + int p_ioctl_vp; uint32_t p_ctl_port; }; @@ -367,6 +369,8 @@ struct port *port_new(struct conf *conf, struct target *target, struct portal_group *pg); +struct port *port_new_ioctl(struct conf *conf, struct target *target, + int pp, int vp); struct port *port_new_pp(struct conf *conf, struct target *target, struct pport *pp); struct port *port_find(const struct conf *conf, const char *name); Index: usr.sbin/ctld/ctld.c =================================================================== --- usr.sbin/ctld/ctld.c +++ usr.sbin/ctld/ctld.c @@ -1232,6 +1232,7 @@ log_err(1, "calloc"); port->p_conf = conf; port->p_name = name; + port->p_ioctl_port = 0; TAILQ_INSERT_TAIL(&conf->conf_ports, port, p_next); TAILQ_INSERT_TAIL(&target->t_ports, port, p_ts); port->p_target = target; @@ -1242,6 +1243,51 @@ } struct port * +port_new_ioctl(struct conf *conf, struct target *target, int pp, int vp) +{ + struct pport *pport; + struct port *port; + char *pname; + char *name; + int ret; + + ret = asprintf(&pname, "ioctl/%d/%d", pp, vp); + if (ret <= 0) { + log_err(1, "asprintf"); + return (NULL); + } + + pport = pport_find(conf, pname); + if (pport != NULL) { + free(pname); + return (port_new_pp(conf, target, pport)); + } + + ret = asprintf(&name, "%s-%s", pname, target->t_name); + free(pname); + + if (ret <= 0) + log_err(1, "asprintf"); + if (port_find(conf, name) != NULL) { + log_warnx("duplicate port \"%s\"", name); + free(name); + return (NULL); + } + port = calloc(1, sizeof(*port)); + if (port == NULL) + log_err(1, "calloc"); + port->p_conf = conf; + port->p_name = name; + port->p_ioctl_port = 1; + port->p_ioctl_pp = pp; + port->p_ioctl_vp = vp; + TAILQ_INSERT_TAIL(&conf->conf_ports, port, p_next); + TAILQ_INSERT_TAIL(&target->t_ports, port, p_ts); + port->p_target = target; + return (port); +} + +struct port * port_new_pp(struct conf *conf, struct target *target, struct pport *pp) { struct port *port; @@ -1613,9 +1659,9 @@ TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) fprintf(stderr, "\t initiator-name %s\n", auth_name->an_initator_name); - TAILQ_FOREACH(auth_portal, &ag->ag_portals, an_next) + TAILQ_FOREACH(auth_portal, &ag->ag_portals, ap_next) fprintf(stderr, "\t initiator-portal %s\n", - auth_portal->an_initator_portal); + auth_portal->ap_initator_portal); fprintf(stderr, "}\n"); } TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { @@ -1629,7 +1675,7 @@ fprintf(stderr, "\t\tpath %s\n", lun->l_path); TAILQ_FOREACH(o, &lun->l_options, o_next) fprintf(stderr, "\t\toption %s %s\n", - lo->o_name, lo->o_value); + o->o_name, o->o_value); fprintf(stderr, "\t}\n"); } TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { Index: usr.sbin/ctld/kernel.c =================================================================== --- usr.sbin/ctld/kernel.c +++ usr.sbin/ctld/kernel.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,8 @@ #include #endif +#define NVLIST_BUFSIZE 1024 + extern bool proxy_mode; static int ctl_fd = 0; @@ -642,23 +645,12 @@ return (conf); } -static void -str_arg(struct ctl_be_arg *arg, const char *name, const char *value) -{ - - arg->namelen = strlen(name) + 1; - arg->name = __DECONST(char *, name); - arg->vallen = strlen(value) + 1; - arg->value = __DECONST(char *, value); - arg->flags = CTL_BEARG_ASCII | CTL_BEARG_RD; -} - int kernel_lun_add(struct lun *lun) { struct option *o; struct ctl_lun_req req; - int error, i, num_options; + int error; bzero(&req, sizeof(req)); @@ -714,29 +706,26 @@ assert(o != NULL); } - num_options = 0; - TAILQ_FOREACH(o, &lun->l_options, o_next) - num_options++; - - req.num_be_args = num_options; - if (num_options > 0) { - req.be_args = malloc(num_options * sizeof(*req.be_args)); - if (req.be_args == NULL) { - log_warn("error allocating %zd bytes", - num_options * sizeof(*req.be_args)); + if (!TAILQ_EMPTY(&lun->l_options)) { + req.args_nvl = nvlist_create(0); + if (req.args_nvl == NULL) { + log_warn("error allocating nvlist"); return (1); } - i = 0; - TAILQ_FOREACH(o, &lun->l_options, o_next) { - str_arg(&req.be_args[i], o->o_name, o->o_value); - i++; + TAILQ_FOREACH(o, &lun->l_options, o_next) + nvlist_add_string(req.args_nvl, o->o_name, o->o_value); + + req.args = nvlist_pack(req.args_nvl, &req.args_len); + if (req.args == NULL) { + log_warn("error packing nvlist"); + return (1); } - assert(i == num_options); } error = ioctl(ctl_fd, CTL_LUN_REQ, &req); - free(req.be_args); + nvlist_destroy(req.args_nvl); + if (error != 0) { log_warn("error issuing CTL_LUN_REQ ioctl"); return (1); @@ -766,7 +755,7 @@ { struct option *o; struct ctl_lun_req req; - int error, i, num_options; + int error; bzero(&req, sizeof(req)); @@ -776,29 +765,26 @@ req.reqdata.modify.lun_id = lun->l_ctl_lun; req.reqdata.modify.lun_size_bytes = lun->l_size; - num_options = 0; - TAILQ_FOREACH(o, &lun->l_options, o_next) - num_options++; - - req.num_be_args = num_options; - if (num_options > 0) { - req.be_args = malloc(num_options * sizeof(*req.be_args)); - if (req.be_args == NULL) { - log_warn("error allocating %zd bytes", - num_options * sizeof(*req.be_args)); + if (!TAILQ_EMPTY(&lun->l_options)) { + req.args_nvl = nvlist_create(0); + if (req.args_nvl == NULL) { + log_warn("error allocating nvlist"); return (1); } - i = 0; - TAILQ_FOREACH(o, &lun->l_options, o_next) { - str_arg(&req.be_args[i], o->o_name, o->o_value); - i++; + TAILQ_FOREACH(o, &lun->l_options, o_next) + nvlist_add_string(req.args_nvl, o->o_name, o->o_value); + + req.args = nvlist_pack(req.args_nvl, &req.args_len); + if (req.args == NULL) { + log_warn("error packing nvlist"); + return (1); } - assert(i == num_options); } error = ioctl(ctl_fd, CTL_LUN_REQ, &req); - free(req.be_args); + nvlist_destroy(req.args_nvl); + if (error != 0) { log_warn("error issuing CTL_LUN_REQ ioctl"); return (1); @@ -978,37 +964,54 @@ struct ctl_lun_map lm; struct target *targ = port->p_target; struct portal_group *pg = port->p_portal_group; - char tagstr[16]; - int error, i, n; + char result_buf[NVLIST_BUFSIZE]; + int error, i; /* Create iSCSI port. */ - if (port->p_portal_group) { + if (port->p_portal_group || port->p_ioctl_port) { bzero(&req, sizeof(req)); - strlcpy(req.driver, "iscsi", sizeof(req.driver)); req.reqtype = CTL_REQ_CREATE; - req.num_args = 5; - TAILQ_FOREACH(o, &pg->pg_options, o_next) - req.num_args++; - req.args = malloc(req.num_args * sizeof(*req.args)); - if (req.args == NULL) - log_err(1, "malloc"); - n = 0; - req.args[n].namelen = sizeof("port_id"); - req.args[n].name = __DECONST(char *, "port_id"); - req.args[n].vallen = sizeof(port->p_ctl_port); - req.args[n].value = &port->p_ctl_port; - req.args[n++].flags = CTL_BEARG_WR; - str_arg(&req.args[n++], "cfiscsi_target", targ->t_name); - snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag); - str_arg(&req.args[n++], "cfiscsi_portal_group_tag", tagstr); - if (targ->t_alias) - str_arg(&req.args[n++], "cfiscsi_target_alias", targ->t_alias); - str_arg(&req.args[n++], "ctld_portal_group_name", pg->pg_name); - TAILQ_FOREACH(o, &pg->pg_options, o_next) - str_arg(&req.args[n++], o->o_name, o->o_value); - req.num_args = n; + + if (port->p_portal_group) { + strlcpy(req.driver, "iscsi", sizeof(req.driver)); + req.args_nvl = nvlist_create(0); + nvlist_add_string(req.args_nvl, "cfiscsi_target", + targ->t_name); + nvlist_add_string(req.args_nvl, + "ctld_portal_group_name", pg->pg_name); + nvlist_add_number(req.args_nvl, + "cfiscsi_portal_group_tag", pg->pg_tag); + + if (targ->t_alias) { + nvlist_add_string(req.args_nvl, + "cfiscsi_target_alias", targ->t_alias); + } + + TAILQ_FOREACH(o, &pg->pg_options, o_next) + nvlist_add_string(req.args_nvl, o->o_name, + o->o_value); + } + + if (port->p_ioctl_port) { + strlcpy(req.driver, "ioctl", sizeof(req.driver)); + req.args_nvl = nvlist_create(0); + nvlist_add_number(req.args_nvl, "pp", + port->p_ioctl_pp); + nvlist_add_number(req.args_nvl, "vp", + port->p_ioctl_vp); + } + + req.args = nvlist_pack(req.args_nvl, &req.args_len); + if (req.args == NULL) { + log_warn("error packing nvlist"); + return (1); + } + + req.result = result_buf; + req.result_len = sizeof(result_buf); error = ioctl(ctl_fd, CTL_PORT_REQ, &req); - free(req.args); + nvlist_destroy(req.args_nvl); + if (error != 0) { log_warn("error issuing CTL_PORT_REQ ioctl"); return (1); @@ -1023,6 +1026,15 @@ req.status); return (1); } + + req.result_nvl = nvlist_unpack(result_buf, req.result_len, 0); + if (req.result_nvl == NULL) { + log_warnx("error unpacking result nvlist"); + return (1); + } + + port->p_ctl_port = nvlist_get_number(req.result_nvl, "port_id"); + nvlist_destroy(req.result_nvl); } else if (port->p_pport) { port->p_ctl_port = port->p_pport->pp_ctl_port; @@ -1106,7 +1118,6 @@ struct ctl_port_entry entry; struct ctl_lun_map lm; struct ctl_req req; - char tagstr[16]; struct target *targ = port->p_target; struct portal_group *pg = port->p_portal_group; int error; @@ -1120,20 +1131,35 @@ return (-1); } - /* Remove iSCSI port. */ - if (port->p_portal_group) { + /* Remove iSCSI or ioctl port. */ + if (port->p_portal_group || port->p_ioctl_port) { bzero(&req, sizeof(req)); - strlcpy(req.driver, "iscsi", sizeof(req.driver)); + strlcpy(req.driver, port->p_ioctl_port ? "ioctl" : "iscsi", + sizeof(req.driver)); req.reqtype = CTL_REQ_REMOVE; - req.num_args = 2; - req.args = malloc(req.num_args * sizeof(*req.args)); - if (req.args == NULL) - log_err(1, "malloc"); - str_arg(&req.args[0], "cfiscsi_target", targ->t_name); - snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag); - str_arg(&req.args[1], "cfiscsi_portal_group_tag", tagstr); + req.args_nvl = nvlist_create(0); + if (req.args_nvl == NULL) + log_err(1, "nvlist_create"); + + if (port->p_ioctl_port) + nvlist_add_number(req.args_nvl, "port_id", + port->p_ctl_port); + else { + nvlist_add_string(req.args_nvl, "cfiscsi_target", + targ->t_name); + nvlist_add_number(req.args_nvl, "cfiscsi_portal_group_tag", + pg->pg_tag); + } + + req.args = nvlist_pack(req.args_nvl, &req.args_len); + if (req.args == NULL) { + log_warn("error packing nvlist"); + return (1); + } + error = ioctl(ctl_fd, CTL_PORT_REQ, &req); - free(req.args); + nvlist_destroy(req.args_nvl); + if (error != 0) { log_warn("error issuing CTL_PORT_REQ ioctl"); return (1); Index: usr.sbin/ctld/parse.y =================================================================== --- usr.sbin/ctld/parse.y +++ usr.sbin/ctld/parse.y @@ -766,28 +766,41 @@ { struct pport *pp; struct port *tp; + int ret, i_pp, i_vp = 0; - pp = pport_find(conf, $2); - if (pp == NULL) { - log_warnx("unknown port \"%s\" for target \"%s\"", - $2, target->t_name); - free($2); - return (1); + ret = sscanf($2, "ioctl/%d/%d", &i_pp, &i_vp); + if (ret > 0) { + tp = port_new_ioctl(conf, target, i_pp, i_vp); + if (tp == NULL) { + log_warnx("can't create new ioctl port for " + "target \"%s\"", target->t_name); + free($2); + return (1); + } + } else { + pp = pport_find(conf, $2); + if (pp == NULL) { + log_warnx("unknown port \"%s\" for target \"%s\"", + $2, target->t_name); + free($2); + return (1); + } + if (!TAILQ_EMPTY(&pp->pp_ports)) { + log_warnx("can't link port \"%s\" to target \"%s\", " + "port already linked to some target", + $2, target->t_name); + free($2); + return (1); + } + tp = port_new_pp(conf, target, pp); + if (tp == NULL) { + log_warnx("can't link port \"%s\" to target \"%s\"", + $2, target->t_name); + free($2); + return (1); + } } - if (!TAILQ_EMPTY(&pp->pp_ports)) { - log_warnx("can't link port \"%s\" to target \"%s\", " - "port already linked to some target", - $2, target->t_name); - free($2); - return (1); - } - tp = port_new_pp(conf, target, pp); - if (tp == NULL) { - log_warnx("can't link port \"%s\" to target \"%s\"", - $2, target->t_name); - free($2); - return (1); - } + free($2); } ; Index: usr.sbin/ctld/uclparse.c =================================================================== --- usr.sbin/ctld/uclparse.c +++ usr.sbin/ctld/uclparse.c @@ -754,7 +754,20 @@ struct pport *pp; struct port *tp; const char *value = ucl_object_tostring(obj); + int ret, i_pp, i_vp = 0; + ret = sscanf(value, "ioctl/%d/%d", &i_pp, &i_vp); + if (ret > 0) { + tp = port_new_ioctl(conf, target, i_pp, i_vp); + if (tp == NULL) { + log_warnx("can't create new ioctl port " + "for target \"%s\"", target->t_name); + return (1); + } + + return (0); + } + pp = pport_find(conf, value); if (pp == NULL) { log_warnx("unknown port \"%s\" for target \"%s\"",