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 @@ -1841,6 +1843,7 @@ args.mda_gid = GID_OPERATOR; args.mda_mode = 0600; args.mda_si_drv1 = softc; + args.mda_si_drv2 = NULL; error = make_dev_s(&args, &softc->dev, "cam/ctl"); if (error != 0) { free(softc, M_DEVBUF); @@ -2415,105 +2418,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. */ @@ -2985,8 +2889,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) { @@ -2997,25 +2905,66 @@ 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) { + if (lun_req->result != NULL) { + packed = nvlist_pack(lun_req->result_nvl, + &packed_len); + if (packed == NULL) { + lun_req->status = CTL_LUN_ERROR; + snprintf(lun_req->error_str, + sizeof(lun_req->error_str), + "Cannot pack result nvlist."); + break; + } + + if (packed_len > lun_req->result_len) { + lun_req->status = CTL_LUN_ERROR; + snprintf(lun_req->error_str, + sizeof(lun_req->error_str), + "Result nvlist too large."); + free(packed, M_NVLIST); + break; + } + + if (copyout(packed, lun_req->result, packed_len)) { + lun_req->status = CTL_LUN_ERROR; + snprintf(lun_req->error_str, + sizeof(lun_req->error_str), + "Cannot copyout() the result."); + free(packed, M_NVLIST); + break; + } + + lun_req->result_len = packed_len; + free(packed, M_NVLIST); + } + + nvlist_destroy(lun_req->result_nvl); } break; } @@ -3022,7 +2971,9 @@ 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; list = (struct ctl_lun_list *)addr; @@ -3148,11 +3099,18 @@ 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); + } + + sbuf_printf(sb, "\n", name); } retval = sbuf_printf(sb, "\n"); @@ -3206,8 +3164,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) { @@ -3216,23 +3178,74 @@ "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) { + if (req->result != 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) { + req->status = CTL_LUN_ERROR; + snprintf(req->error_str, + sizeof(req->error_str), + "Result nvlist too large."); + free(packed, M_NVLIST); + break; + } + + if (copyout(packed, req->result, packed_len)) { + req->status = CTL_LUN_ERROR; + snprintf(req->error_str, + sizeof(req->error_str), + "Cannot copyout() the result."); + free(packed, M_NVLIST); + break; + } + + req->result_len = packed_len; + free(packed, M_NVLIST); + } + + nvlist_destroy(req->result_nvl); } break; } @@ -3240,8 +3253,9 @@ 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; uint32_t plun; list = (struct ctl_lun_list *)addr; @@ -3316,11 +3330,18 @@ 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; + + 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); + } + + sbuf_printf(sb, "\n", name); } if (port->lun_map != NULL) { @@ -4127,8 +4148,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); } @@ -4181,10 +4202,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], @@ -4213,8 +4236,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 &= @@ -4289,8 +4312,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 | @@ -4302,8 +4325,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 | @@ -4315,8 +4338,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 | @@ -4328,8 +4351,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 | @@ -4521,20 +4544,20 @@ 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; } - uuid = ctl_get_opt(&be_lun->options, "uuid"); + uuid = dnvlist_get_string(be_lun->options, "uuid", NULL); if (uuid != NULL) { len += sizeof(struct scsi_vpd_id_descriptor) + 18; } @@ -4546,7 +4569,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, @@ -4659,7 +4682,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; @@ -9715,6 +9738,7 @@ { struct ctl_lun *lun = CTL_LUN(ctsio); struct scsi_vpd_block_limits *bl_ptr; + const char *val; uint64_t ival; ctsio->kern_data_ptr = malloc(sizeof(*bl_ptr), M_CTL, M_WAITOK | M_ZERO); @@ -9744,12 +9768,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), @@ -9765,7 +9793,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); } @@ -9804,13 +9835,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; @@ -9855,7 +9886,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; @@ -9949,7 +9981,7 @@ struct ctl_lun *lun = CTL_LUN(ctsio); struct scsi_inquiry_data *inq_ptr; struct scsi_inquiry *cdb; - char *val; + const char *val; uint32_t alloc_len, data_len; ctl_port_type port_type; @@ -10027,8 +10059,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)); @@ -10038,7 +10070,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, @@ -10067,8 +10100,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 @@ -41,6 +41,7 @@ #define _CTL_BACKEND_H_ #include +#include typedef enum { CTL_LUN_SERSEQ_OFF, @@ -173,7 +174,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 @@ -60,6 +60,8 @@ #include #include #include +#include +#include #include #include @@ -949,7 +951,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); free(be_lun->zero_page, M_RAMDISK); ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir); sx_destroy(&be_lun->page_lock); @@ -972,7 +974,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]; uint64_t t; int retval; @@ -983,10 +985,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; @@ -994,7 +996,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; @@ -1002,7 +1004,7 @@ cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; be_lun->pblocksize = PAGE_SIZE; - value = ctl_get_opt(&cbe_lun->options, "pblocksize"); + value = dnvlist_get_string(cbe_lun->options, "pblocksize", NULL); if (value != NULL) { ctl_expand_number(value, &t); be_lun->pblocksize = t; @@ -1051,7 +1053,7 @@ cbe_lun->ublockoff = 0; cbe_lun->atomicblock = be_lun->pblocksize; cbe_lun->opttxferlen = SGPP * be_lun->pblocksize; - value = ctl_get_opt(&cbe_lun->options, "capacity"); + value = dnvlist_get_string(cbe_lun->options, "capacity", NULL); if (value != NULL) ctl_expand_number(value, &be_lun->cap_bytes); } else { @@ -1063,10 +1065,10 @@ params->blocksize_bytes = cbe_lun->blocksize; params->lun_size_bytes = be_lun->size_bytes; - value = ctl_get_opt(&cbe_lun->options, "unmap"); - if (value == NULL || strcmp(value, "off") != 0) + value = dnvlist_get_string(cbe_lun->options, "unmap", NULL); + if (value != NULL && strcmp(value, "off") != 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; @@ -1073,7 +1075,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) @@ -1202,7 +1204,7 @@ if (be_lun != NULL) { if (be_lun->io_taskqueue != NULL) taskqueue_free(be_lun->io_taskqueue); - ctl_free_opts(&cbe_lun->options); + nvlist_destroy(cbe_lun->options); free(be_lun->zero_page, M_RAMDISK); ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir); sx_destroy(&be_lun->page_lock); @@ -1219,7 +1221,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; @@ -1241,10 +1243,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 @@ -41,6 +41,7 @@ #define _CTL_FRONTEND_H_ #include +#include typedef enum { CTL_PORT_STATUS_NONE = 0x00, @@ -235,7 +236,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 @@ -198,8 +200,8 @@ } port->targ_port = port_num; port->ctl_pool_ref = pool; - if (port->options.stqh_first == NULL) - STAILQ_INIT(&port->options); + if (port->options == NULL) + port->options = nvlist_create(0); port->stats.item = port_num; mtx_init(&port->port_lock, "CTL port", NULL, MTX_DEF); @@ -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); @@ -331,7 +333,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 @@ -68,22 +70,41 @@ ctl_fe_ioctl_state state; }; -struct cfi_softc { +struct cfi_port { + TAILQ_ENTRY(cfi_port) link; uint32_t cur_tag_num; + struct cdev * dev; struct ctl_port port; }; +struct cfi_softc { + TAILQ_HEAD(, cfi_port) ports; +}; + + static struct cfi_softc cfi_softc; + static int cfi_init(void); static int cfi_shutdown(void); static void cfi_datamove(union ctl_io *io); static void cfi_done(union ctl_io *io); +static int cfi_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, + struct thread *td); +static void cfi_ioctl_port_create(struct ctl_req *req); +static void cfi_ioctl_port_remove(struct ctl_req *req); +static struct cdevsw cfi_cdevsw = { + .d_version = D_VERSION, + .d_flags = 0, + .d_ioctl = ctl_ioctl_io +}; + static struct ctl_frontend cfi_frontend = { .name = "ioctl", .init = cfi_init, + .ioctl = cfi_ioctl, .shutdown = cfi_shutdown, }; CTL_FRONTEND_DECLARE(ctlioctl, cfi_frontend); @@ -92,12 +113,15 @@ cfi_init(void) { struct cfi_softc *isoftc = &cfi_softc; + struct cfi_port *cfi; struct ctl_port *port; int error = 0; memset(isoftc, 0, sizeof(*isoftc)); + TAILQ_INIT(&isoftc->ports); - port = &isoftc->port; + cfi = malloc(sizeof(*cfi), M_CTL, M_WAITOK | M_ZERO); + port = &cfi->port; port->frontend = &cfi_frontend; port->port_type = CTL_PORT_IOCTL; port->num_requested_ctl_io = 100; @@ -104,14 +128,16 @@ port->port_name = "ioctl"; port->fe_datamove = cfi_datamove; port->fe_done = cfi_done; + port->physical_port = 0; port->targ_port = -1; - port->max_initiators = 1; if ((error = ctl_port_register(port)) != 0) { printf("%s: ioctl port registration failed\n", __func__); return (error); } + ctl_port_online(port); + TAILQ_INSERT_TAIL(&isoftc->ports, cfi, link); return (0); } @@ -119,15 +145,187 @@ cfi_shutdown(void) { struct cfi_softc *isoftc = &cfi_softc; - struct ctl_port *port = &isoftc->port; - int error = 0; + struct cfi_port *cfi, *temp; + struct ctl_port *port; + int error; - ctl_port_offline(port); - if ((error = ctl_port_deregister(port)) != 0) - printf("%s: ioctl port deregistration failed\n", __func__); - return (error); + TAILQ_FOREACH_SAFE(cfi, &isoftc->ports, link, temp) { + port = &cfi->port; + ctl_port_offline(port); + error = ctl_port_deregister(port); + if (error != 0) { + printf("%s: ctl_frontend_deregister() failed\n", + __func__); + return (error); + } + + TAILQ_REMOVE(&isoftc->ports, cfi, link); + free(cfi, M_CTL); + } + + return (0); } +static void +cfi_ioctl_port_create(struct ctl_req *req) +{ + struct cfi_softc *isoftc = &cfi_softc; + struct cfi_port *cfi; + struct ctl_port *port; + struct make_dev_args args; + const char *val; + int retval; + int pp = -1, vp = 0; + + val = dnvlist_get_string(req->args_nvl, "pp", NULL); + if (val != NULL) + pp = strtol(val, NULL, 10); + + val = dnvlist_get_string(req->args_nvl, "vp", NULL); + if (val != NULL) + vp = strtol(val, NULL, 10); + + if (pp != -1) { + /* Check for duplicates */ + TAILQ_FOREACH(cfi, &isoftc->ports, link) { + if (pp == cfi->port.physical_port && + vp == cfi->port.virtual_port) { + req->status = CTL_LUN_ERROR; + snprintf(req->error_str, sizeof(req->error_str), + "port %d already exists", pp); + + return; + } + } + } else { + /* Find free port number */ + TAILQ_FOREACH(cfi, &isoftc->ports, link) { + pp = MAX(pp, cfi->port.physical_port); + } + + pp++; + } + + cfi = malloc(sizeof(*cfi), M_CTL, M_WAITOK | M_ZERO); + port = &cfi->port; + port->frontend = &cfi_frontend; + port->port_type = CTL_PORT_IOCTL; + port->num_requested_ctl_io = 100; + port->port_name = "ioctl"; + port->fe_datamove = cfi_datamove; + port->fe_done = cfi_done; + port->physical_port = pp; + port->virtual_port = vp; + port->targ_port = -1; + + retval = ctl_port_register(port); + if (retval != 0) { + req->status = CTL_LUN_ERROR; + snprintf(req->error_str, sizeof(req->error_str), + "ctl_port_register() failed with error %d", retval); + free(port, M_CTL); + return; + } + + req->result_nvl = nvlist_create(0); + nvlist_add_number(req->result_nvl, "port_id", port->targ_port); + ctl_port_online(port); + + make_dev_args_init(&args); + args.mda_devsw = &cfi_cdevsw; + args.mda_uid = UID_ROOT; + args.mda_gid = GID_OPERATOR; + args.mda_mode = 0600; + args.mda_si_drv1 = NULL; + args.mda_si_drv2 = cfi; + + retval = make_dev_s(&args, &cfi->dev, "cam/ctl%d.%d", pp, vp); + if (retval != 0) { + req->status = CTL_LUN_ERROR; + snprintf(req->error_str, sizeof(req->error_str), + "make_dev_s() failed with error %d", retval); + free(port, M_CTL); + return; + } + + req->status = CTL_LUN_OK; + TAILQ_INSERT_TAIL(&isoftc->ports, cfi, link); +} + +static void +cfi_ioctl_port_remove(struct ctl_req *req) +{ + struct cfi_softc *isoftc = &cfi_softc; + struct cfi_port *cfi = NULL; + const char *val; + int port_id = -1; + + val = dnvlist_get_string(req->args_nvl, "port_id", NULL); + if (val != NULL) + port_id = strtol(val, NULL, 10); + + if (port_id == -1) { + req->status = CTL_LUN_ERROR; + snprintf(req->error_str, sizeof(req->error_str), + "port_id not provided"); + return; + } + + TAILQ_FOREACH(cfi, &isoftc->ports, link) { + if (cfi->port.targ_port == port_id) + break; + } + + if (cfi == NULL) { + req->status = CTL_LUN_ERROR; + snprintf(req->error_str, sizeof(req->error_str), + "cannot find port %d", port_id); + + return; + } + + if (cfi->port.physical_port == 0 && cfi->port.virtual_port == 0) { + req->status = CTL_LUN_ERROR; + snprintf(req->error_str, sizeof(req->error_str), + "cannot destroy default ioctl port"); + + return; + } + + ctl_port_offline(&cfi->port); + ctl_port_deregister(&cfi->port); + TAILQ_REMOVE(&isoftc->ports, cfi, link); + destroy_dev(cfi->dev); + free(cfi, M_CTL); + req->status = CTL_LUN_OK; +} + +static int +cfi_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, + struct thread *td) +{ + struct ctl_req *req; + + if (cmd == CTL_PORT_REQ) { + req = (struct ctl_req *)addr; + switch (req->reqtype) { + case CTL_REQ_CREATE: + cfi_ioctl_port_create(req); + break; + case CTL_REQ_REMOVE: + cfi_ioctl_port_remove(req); + break; + default: + req->status = CTL_LUN_ERROR; + snprintf(req->error_str, sizeof(req->error_str), + "Unsupported request type %d", req->reqtype); + } + return (0); + } + + return (ENOTTY); +} + /* * Data movement routine for the CTL ioctl frontend port. */ @@ -389,18 +587,26 @@ ctl_ioctl_io(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) { + struct cfi_port *cfi; union ctl_io *io; void *pool_tmp, *sc_tmp; int retval = 0; + if (cmd != CTL_IO) + return (ENOTTY); + + cfi = dev->si_drv2 == NULL + ? TAILQ_FIRST(&cfi_softc.ports) + : dev->si_drv2; + /* * If we haven't been "enabled", don't allow any SCSI I/O * to this FETD. */ - if ((cfi_softc.port.status & CTL_PORT_STATUS_ONLINE) == 0) + if ((cfi->port.status & CTL_PORT_STATUS_ONLINE) == 0) return (EPERM); - io = ctl_alloc_io(cfi_softc.port.ctl_pool_ref); + io = ctl_alloc_io(cfi->port.ctl_pool_ref); /* * Need to save the pool reference so it doesn't get @@ -420,15 +626,16 @@ /* * The user sets the initiator ID, target and LUN IDs. */ - io->io_hdr.nexus.targ_port = cfi_softc.port.targ_port; + io->io_hdr.nexus.targ_port = cfi->port.targ_port; io->io_hdr.flags |= CTL_FLAG_USER_REQ; if ((io->io_hdr.io_type == CTL_IO_SCSI) && (io->scsiio.tag_type != CTL_TAG_UNTAGGED)) - io->scsiio.tag_num = cfi_softc.cur_tag_num++; + io->scsiio.tag_num = cfi->cur_tag_num++; retval = cfi_submit_wait(io); if (retval == 0) memcpy((void *)addr, io, sizeof(*io)); + ctl_free_io(io); return (retval); } 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,30 @@ { struct cfiscsi_target *ct; struct ctl_port *port; - const char *target, *alias, *tags; + const char *target, *alias, *val; struct scsi_vpd_id_descriptor *desc; - ctl_options_t opts; int retval, len, idlen; uint16_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); + val = dnvlist_get_string(req->args_nvl, "cfiscsi_portal_group_tag", + NULL); + + + if (target == NULL || val == NULL) { 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); + + tag = strtoul(val, NULL, 0); ct = cfiscsi_target_find_or_create(&cfiscsi_softc, target, alias, 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 +2108,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 +2120,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 +2129,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); @@ -2162,7 +2161,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 +2172,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 +2180,23 @@ cfiscsi_ioctl_port_remove(struct ctl_req *req) { struct cfiscsi_target *ct; - const char *target, *tags; - ctl_options_t opts; + const char *target, *val; 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); + val = dnvlist_get_string(req->args_nvl, "cfiscsi_portal_group_tag", + NULL); + + if (target == NULL || val == NULL) { req->status = CTL_LUN_ERROR; snprintf(req->error_str, sizeof(req->error_str), "Missing required argument"); return; } - tag = strtol(tags, (char **)NULL, 10); + + tag = strtoul(val, NULL, 0); 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 +2203,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" /* @@ -329,39 +330,6 @@ #define CTL_ERROR_STR_LEN 160 -#define CTL_BEARG_RD 0x01 -#define CTL_BEARG_WR 0x02 -#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 +505,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 +601,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 @@ -1666,7 +1668,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")); @@ -1729,7 +1731,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 @@ -1820,7 +1822,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")); @@ -1883,7 +1885,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 @@ -178,7 +179,7 @@ {"lunmap", CTLADM_CMD_LUNMAP, CTLADM_ARG_NONE, "p:l:L:"}, {"modesense", CTLADM_CMD_MODESENSE, CTLADM_ARG_NEED_TL, "P:S:dlm:c:"}, {"modify", CTLADM_CMD_MODIFY, CTLADM_ARG_NONE, "b:l:o:s:"}, - {"port", CTLADM_CMD_PORT, CTLADM_ARG_NONE, "lo:p:qt:w:W:x"}, + {"port", CTLADM_CMD_PORT, CTLADM_ARG_NONE, "li:o:d:crp:qt:w:W:x"}, {"portlist", CTLADM_CMD_PORTLIST, CTLADM_ARG_NONE, "f:ilp:qvx"}, {"prin", CTLADM_CMD_PRES_IN, CTLADM_ARG_NEED_TL, "a:"}, {"prout", CTLADM_CMD_PRES_OUT, CTLADM_ARG_NEED_TL, "a:k:r:s:"}, @@ -369,7 +370,9 @@ CCTL_PORT_MODE_LIST, CCTL_PORT_MODE_SET, CCTL_PORT_MODE_ON, - CCTL_PORT_MODE_OFF + CCTL_PORT_MODE_OFF, + CCTL_PORT_MODE_CREATE, + CCTL_PORT_MODE_REMOVE } cctl_port_mode; static struct ctladm_opts cctl_fe_table[] = { @@ -392,9 +395,16 @@ uint64_t wwnn = 0, wwpn = 0; cctl_port_mode port_mode = CCTL_PORT_MODE_NONE; struct ctl_port_entry entry; + struct ctl_req req; + char *driver = NULL; + nvlist_t *option_list; ctl_port_type port_type = CTL_PORT_NONE; int quiet = 0, xml = 0; + option_list = nvlist_create(0); + if (option_list == NULL) + err(1, "%s: unable to allocate nvlist", __func__); + while ((c = getopt(argc, argv, combinedopt)) != -1) { switch (c) { case 'l': @@ -403,7 +413,13 @@ port_mode = CCTL_PORT_MODE_LIST; break; - case 'o': + case 'c': + port_mode = CCTL_PORT_MODE_CREATE; + break; + case 'r': + port_mode = CCTL_PORT_MODE_REMOVE; + break; + case 'i': if (port_mode != CCTL_PORT_MODE_NONE) goto bailout_badarg; @@ -412,7 +428,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 +435,40 @@ goto bailout; } break; + case 'o': { + 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; + } + + free(tmpstr); + nvlist_add_string(option_list, name, value); + break; + } + case 'd': + if (driver != NULL) { + warnx("%s: option -d cannot be specified twice", + __func__); + retval = 1; + goto bailout; + } + + driver = strdup(optarg); + break; case 'p': targ_port = strtol(optarg, NULL, 0); break; @@ -474,6 +524,9 @@ } } + if (driver == NULL) + driver = strdup("ioctl"); + /* * The user can specify either one or more frontend types (-t), or * a specific frontend, but not both. @@ -515,6 +568,56 @@ cctl_portlist(fd, argcx, argvx, opts); break; } + case CCTL_PORT_MODE_REMOVE: + if (targ_port == -1) { + warnx("%s: -r require -p", __func__); + retval = 1; + goto bailout; + } + case CCTL_PORT_MODE_CREATE: { + bzero(&req, sizeof(req)); + strlcpy(req.driver, driver, sizeof(req.driver)); + + if (port_mode == CCTL_PORT_MODE_REMOVE) { + req.reqtype = CTL_REQ_REMOVE; + nvlist_add_stringf(option_list, "port_id", "%d", + targ_port); + } else + req.reqtype = CTL_REQ_CREATE; + + req.args = nvlist_pack(option_list, &req.args_len); + if (req.args == NULL) { + warn("%s: error packing nvlist", __func__); + retval = 1; + goto bailout; + } + + retval = ioctl(fd, CTL_PORT_REQ, &req); + free(req.args) + if (retval == -1) { + warn("%s: CTL_PORT_REQ ioctl failed", __func__); + retval = 1; + goto bailout; + } + + switch (req.status) { + case CTL_LUN_ERROR: + warnx("error: %s", req.error_str); + retval = 1; + goto bailout; + case CTL_LUN_WARNING: + warnx("warning: %s", req.error_str); + break; + case CTL_LUN_OK: + break; + default: + warnx("unknown status: %d", req.status); + retval = 1; + goto bailout; + } + + break; + } case CCTL_PORT_MODE_SET: if (targ_port == -1) { warnx("%s: -w and -W require -n", __func__); @@ -561,7 +664,8 @@ } bailout: - + nvlist_destroy(req.args_nvl); + free(driver); return (retval); bailout_badarg: @@ -2271,14 +2375,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) { @@ -2290,11 +2386,12 @@ char *device_id = NULL; int lun_size_set = 0, blocksize_set = 0, lun_id_set = 0; char *backend_name = NULL; - STAILQ_HEAD(, cctl_req_option) option_list; - int num_options = 0; + nvlist_t *option_list; int retval = 0, c; - STAILQ_INIT(&option_list); + option_list = nvlist_create(0); + if (option_list == NULL) + err(1, "%s: unable to allocate nvlist", __func__); while ((c = getopt(argc, argv, combinedopt)) != -1) { switch (c) { @@ -2313,7 +2410,6 @@ lun_id_set = 1; break; case 'o': { - struct cctl_req_option *option; char *tmpstr; char *name, *value; @@ -2332,21 +2428,9 @@ 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->namelen = strlen(name) + 1; - option->value = strdup(value); - option->vallen = strlen(value) + 1; + free(tmpstr); - - STAILQ_INSERT_TAIL(&option_list, option, links); - num_options++; + nvlist_add_string(option_list, name, value); break; } case 's': @@ -2413,43 +2497,16 @@ req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID; } - req.num_be_args = num_options; - if (num_options > 0) { - 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)); - retval = 1; - goto bailout; - } - - 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; - - STAILQ_REMOVE(&option_list, option, cctl_req_option, - links); - free(option->name); - free(option->value); - free(option); - } + req.args = nvlist_pack(option_list, &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) { + retval = ioctl(fd, CTL_LUN_REQ, &req); + free(req.args); + if (retval == -1) { warn("%s: error issuing CTL_LUN_REQ ioctl", __func__); retval = 1; goto bailout; @@ -2480,9 +2537,10 @@ 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: + nvlist_destroy(req.args_nvl); return (retval); } @@ -2493,11 +2551,12 @@ uint32_t lun_id = 0; int lun_id_set = 0; char *backend_name = NULL; - STAILQ_HEAD(, cctl_req_option) option_list; - int num_options = 0; + nvlist_t *option_list; int retval = 0, c; - STAILQ_INIT(&option_list); + option_list = nvlist_create(0); + if (option_list == NULL) + err(1, "%s: unable to allocate nvlist", __func__); while ((c = getopt(argc, argv, combinedopt)) != -1) { switch (c) { @@ -2509,7 +2568,6 @@ lun_id_set = 1; break; case 'o': { - struct cctl_req_option *option; char *tmpstr; char *name, *value; @@ -2528,21 +2586,9 @@ 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->namelen = strlen(name) + 1; - option->value = strdup(value); - option->vallen = strlen(value) + 1; + free(tmpstr); - - STAILQ_INSERT_TAIL(&option_list, option, links); - num_options++; + nvlist_add_string(option_list, name, value); break; } default: @@ -2562,44 +2608,17 @@ req.reqtype = CTL_LUNREQ_RM; req.reqdata.rm.lun_id = lun_id; - - req.num_be_args = num_options; - if (num_options > 0) { - 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)); - retval = 1; - goto bailout; - } - - 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; - - STAILQ_REMOVE(&option_list, option, cctl_req_option, - links); - free(option->name); - free(option->value); - free(option); - } + + req.args = nvlist_pack(option_list, &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) { + retval = ioctl(fd, CTL_LUN_REQ, &req); + free(req.args); + if (retval == -1) { warn("%s: error issuing CTL_LUN_REQ ioctl", __func__); retval = 1; goto bailout; @@ -2624,6 +2643,7 @@ printf("LUN %d removed successfully\n", lun_id); bailout: + nvlist_destroy(req.args_nvl); return (retval); } @@ -2635,11 +2655,13 @@ uint32_t lun_id = 0; int lun_id_set = 0, lun_size_set = 0; char *backend_name = NULL; - STAILQ_HEAD(, cctl_req_option) option_list; - int num_options = 0; + nvlist_t *option_list; int retval = 0, c; - STAILQ_INIT(&option_list); + option_list = nvlist_create(0); + if (option_list == NULL) + err(1, "%s: unable to allocate nvlist", __func__); + while ((c = getopt(argc, argv, combinedopt)) != -1) { switch (c) { case 'b': @@ -2650,7 +2672,6 @@ lun_id_set = 1; break; case 'o': { - struct cctl_req_option *option; char *tmpstr; char *name, *value; @@ -2669,21 +2690,9 @@ 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->namelen = strlen(name) + 1; - option->value = strdup(value); - option->vallen = strlen(value) + 1; + free(tmpstr); - - STAILQ_INSERT_TAIL(&option_list, option, links); - num_options++; + nvlist_add_string(option_list, name, value); break; } case 's': @@ -2709,7 +2718,7 @@ if (lun_id_set == 0) errx(1, "%s: LUN id (-l) must be specified", __func__); - if (lun_size_set == 0 && num_options == 0) + if (lun_size_set == 0 && nvlist_empty(option_list)) errx(1, "%s: size (-s) or options (-o) must be specified", __func__); @@ -2721,43 +2730,16 @@ 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) { - 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)); - retval = 1; - goto bailout; - } - - 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; - - STAILQ_REMOVE(&option_list, option, cctl_req_option, - links); - free(option->name); - free(option->value); - free(option); - } + req.args = nvlist_pack(option_list, &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) { + retval = ioctl(fd, CTL_LUN_REQ, &req); + free(req.args); + if (retval == -1) { warn("%s: error issuing CTL_LUN_REQ ioctl", __func__); retval = 1; goto bailout; @@ -2782,6 +2764,7 @@ printf("LUN %d modified successfully\n", lun_id); bailout: + nvlist_destroy(req.args_nvl); return (retval); } @@ -3874,8 +3857,10 @@ " [-t secs]\n" " ctladm inject [dev_id] <-i action> <-p pattern> [-r lba,len]\n" " [-s len fmt [args]] [-c] [-d delete_id]\n" -" ctladm port <-o | [-w wwnn][-W wwpn]>\n" +" ctladm port <-i | [-w wwnn][-W wwpn]>\n" " [-p targ_port] [-t port_type]\n" +" <-c> [-d driver] [-o name=value]\n" +" <-d> <-p targ_port>\n" " ctladm portlist [-f frontend] [-i] [-p targ_port] [-q] [-v] [-x]\n" " ctladm islist [-v | -x]\n" " ctladm islogout <-a | -c connection-id | -i name | -p portal>\n" 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_stringf(req.args_nvl, + "cfiscsi_portal_group_tag", "%u", 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_stringf(req.args_nvl, "pp", "%d", + port->p_ioctl_pp); + nvlist_add_stringf(req.args_nvl, "vp", "%d", + 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_stringf(req.args_nvl, "port_id", "%d", + port->p_ctl_port); + else { + nvlist_add_string(req.args_nvl, "cfiscsi_target", + targ->t_name); + nvlist_add_stringf(req.args_nvl, + "cfiscsi_portal_group_tag", "%u", 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\"",