Changeset View
Changeset View
Standalone View
Standalone View
sys/cam/ctl/ctl.c
Context not available. | |||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/endian.h> | #include <sys/endian.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/nv.h> | |||||
#include <sys/dnv.h> | |||||
#include <vm/uma.h> | #include <vm/uma.h> | ||||
#include <cam/cam.h> | #include <cam/cam.h> | ||||
Context not available. | |||||
args.mda_gid = GID_OPERATOR; | args.mda_gid = GID_OPERATOR; | ||||
args.mda_mode = 0600; | args.mda_mode = 0600; | ||||
args.mda_si_drv1 = softc; | args.mda_si_drv1 = softc; | ||||
args.mda_si_drv2 = NULL; | |||||
error = make_dev_s(&args, &softc->dev, "cam/ctl"); | error = make_dev_s(&args, &softc->dev, "cam/ctl"); | ||||
if (error != 0) { | if (error != 0) { | ||||
free(softc, M_DEVBUF); | free(softc, M_DEVBUF); | ||||
Context not available. | |||||
return (kptr); | 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. | * Escape characters that are illegal or not recommended in XML. | ||||
*/ | */ | ||||
Context not available. | |||||
case CTL_LUN_REQ: { | case CTL_LUN_REQ: { | ||||
struct ctl_lun_req *lun_req; | struct ctl_lun_req *lun_req; | ||||
struct ctl_backend_driver *backend; | struct ctl_backend_driver *backend; | ||||
void *packed; | |||||
nvlist_t *tmp_args_nvl; | |||||
size_t packed_len; | |||||
lun_req = (struct ctl_lun_req *)addr; | lun_req = (struct ctl_lun_req *)addr; | ||||
tmp_args_nvl = lun_req->args_nvl; | |||||
backend = ctl_backend_find(lun_req->backend); | backend = ctl_backend_find(lun_req->backend); | ||||
if (backend == NULL) { | if (backend == NULL) { | ||||
Context not available. | |||||
lun_req->backend); | lun_req->backend); | ||||
break; | break; | ||||
} | } | ||||
if (lun_req->num_be_args > 0) { | |||||
lun_req->kern_be_args = ctl_copyin_args( | if (lun_req->args != NULL) { | ||||
lun_req->num_be_args, | lun_req->args = ctl_copyin_alloc(lun_req->args, | ||||
lun_req->be_args, | lun_req->args_len, lun_req->error_str, | ||||
lun_req->error_str, | sizeof(lun_req->error_str)); | ||||
sizeof(lun_req->error_str)); | |||||
if (lun_req->kern_be_args == NULL) { | if (lun_req->args == NULL) { | ||||
lun_req->status = CTL_LUN_ERROR; | lun_req->status = CTL_LUN_ERROR; | ||||
break; | 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); | 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) { | if (lun_req->result_nvl != NULL) { | ||||
ctl_copyout_args(lun_req->num_be_args, | if (lun_req->result != NULL) { | ||||
lun_req->kern_be_args); | packed = nvlist_pack(lun_req->result_nvl, | ||||
ctl_free_args(lun_req->num_be_args, | &packed_len); | ||||
lun_req->kern_be_args); | if (packed == NULL) { | ||||
lun_req->status = CTL_LUN_ERROR; | |||||
snprintf(lun_req->error_str, | |||||
sizeof(lun_req->error_str), | |||||
"Cannot pack result nvlist."); | |||||
mav: I see here lack of error reporting for both practical case of packed_len > lun_req->result_len… | |||||
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; | break; | ||||
} | } | ||||
Context not available. | |||||
case CTL_LUN_LIST: { | case CTL_LUN_LIST: { | ||||
struct sbuf *sb; | struct sbuf *sb; | ||||
struct ctl_lun_list *list; | 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; | list = (struct ctl_lun_list *)addr; | ||||
Not Done Inline ActionsShould we also encode type name (string, number, possibly also bool, double and so on) in the XML? jceel: Should we also encode type name (string, number, possibly also bool, double and so on) in the… | |||||
Not Done Inline ActionsThings were much easier when there were only strings. There were couple of exceptions for return values, but they were a very dirty hacks to keep them. mav: Things were much easier when there were only strings. There were couple of exceptions for… | |||||
Context not available. | |||||
if (retval != 0) | if (retval != 0) | ||||
break; | break; | ||||
} | } | ||||
STAILQ_FOREACH(opt, &lun->be_lun->options, links) { | |||||
retval = sbuf_printf(sb, "\t<%s>%s</%s>\n", | while ((name = nvlist_next(lun->be_lun->options, &type, | ||||
opt->name, opt->value, opt->name); | &cookie)) != NULL) { | ||||
if (retval != 0) | sbuf_printf(sb, "\t<%s>", name); | ||||
break; | |||||
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, "</%s>\n", name); | |||||
} | } | ||||
retval = sbuf_printf(sb, "</lun>\n"); | retval = sbuf_printf(sb, "</lun>\n"); | ||||
Context not available. | |||||
case CTL_PORT_REQ: { | case CTL_PORT_REQ: { | ||||
struct ctl_req *req; | struct ctl_req *req; | ||||
struct ctl_frontend *fe; | struct ctl_frontend *fe; | ||||
void *packed; | |||||
nvlist_t *tmp_args_nvl; | |||||
size_t packed_len; | |||||
req = (struct ctl_req *)addr; | req = (struct ctl_req *)addr; | ||||
tmp_args_nvl = req->args_nvl; | |||||
fe = ctl_frontend_find(req->driver); | fe = ctl_frontend_find(req->driver); | ||||
if (fe == NULL) { | if (fe == NULL) { | ||||
Context not available. | |||||
"Frontend \"%s\" not found.", req->driver); | "Frontend \"%s\" not found.", req->driver); | ||||
break; | break; | ||||
} | } | ||||
if (req->num_args > 0) { | |||||
req->kern_args = ctl_copyin_args(req->num_args, | if (req->args != NULL) { | ||||
req->args, req->error_str, sizeof(req->error_str)); | req->args = ctl_copyin_alloc(req->args, | ||||
if (req->kern_args == NULL) { | req->args_len, req->error_str, | ||||
sizeof(req->error_str)); | |||||
if (req->args == NULL) { | |||||
req->status = CTL_LUN_ERROR; | req->status = CTL_LUN_ERROR; | ||||
snprintf(req->error_str, sizeof(req->error_str), | |||||
"Cannot copyin args."); | |||||
break; | 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) | if (fe->ioctl) | ||||
retval = fe->ioctl(dev, cmd, addr, flag, td); | retval = fe->ioctl(dev, cmd, addr, flag, td); | ||||
else | else | ||||
retval = ENODEV; | retval = ENODEV; | ||||
if (req->num_args > 0) { | nvlist_destroy(req->args_nvl); | ||||
ctl_copyout_args(req->num_args, req->kern_args); | req->args_nvl = tmp_args_nvl; | ||||
ctl_free_args(req->num_args, req->kern_args); | |||||
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; | |||||
} | |||||
Not Done Inline ActionsSame comment as for LUNs. mav: Same comment as for LUNs. | |||||
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; | break; | ||||
} | } | ||||
Context not available. | |||||
struct sbuf *sb; | struct sbuf *sb; | ||||
struct ctl_port *port; | struct ctl_port *port; | ||||
struct ctl_lun_list *list; | struct ctl_lun_list *list; | ||||
struct ctl_option *opt; | const char *name, *value; | ||||
int j; | void *cookie = NULL; | ||||
int j, type; | |||||
uint64_t valuei; | |||||
uint32_t plun; | uint32_t plun; | ||||
list = (struct ctl_lun_list *)addr; | list = (struct ctl_lun_list *)addr; | ||||
Done Inline ActionsWhy to use separate lines? mav: Why to use separate lines? | |||||
Context not available. | |||||
if (retval != 0) | if (retval != 0) | ||||
break; | break; | ||||
} | } | ||||
STAILQ_FOREACH(opt, &port->options, links) { | |||||
retval = sbuf_printf(sb, "\t<%s>%s</%s>\n", | printf("port_name = %s, port_options = %p\n", port->port_name, port->options); | ||||
opt->name, opt->value, opt->name); | while ((name = nvlist_next(port->options, &type, | ||||
if (retval != 0) | &cookie)) != NULL) { | ||||
break; | 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, "</%s>\n", name); | |||||
} | } | ||||
if (port->lun_map != NULL) { | if (port->lun_map != NULL) { | ||||
Context not available. | |||||
CTL_PAGE_DEFAULT]; | CTL_PAGE_DEFAULT]; | ||||
scsi_ulto3b(cylinders, rigid_disk_page->cylinders); | scsi_ulto3b(cylinders, rigid_disk_page->cylinders); | ||||
if ((value = ctl_get_opt(&lun->be_lun->options, | if ((value = dnvlist_get_string(lun->be_lun->options, | ||||
"rpm")) != NULL) { | "rpm", NULL)) != NULL) { | ||||
scsi_ulto2b(strtol(value, NULL, 0), | scsi_ulto2b(strtol(value, NULL, 0), | ||||
rigid_disk_page->rotation_rate); | rigid_disk_page->rotation_rate); | ||||
} | } | ||||
Context not available. | |||||
sizeof(caching_page_default)); | sizeof(caching_page_default)); | ||||
caching_page = &lun->mode_pages.caching_page[ | caching_page = &lun->mode_pages.caching_page[ | ||||
CTL_PAGE_SAVED]; | 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) | if (value != NULL && strcmp(value, "off") == 0) | ||||
caching_page->flags1 &= ~SCP_WCE; | 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) | if (value != NULL && strcmp(value, "off") == 0) | ||||
caching_page->flags1 |= SCP_RCD; | caching_page->flags1 |= SCP_RCD; | ||||
memcpy(&lun->mode_pages.caching_page[CTL_PAGE_CURRENT], | memcpy(&lun->mode_pages.caching_page[CTL_PAGE_CURRENT], | ||||
Context not available. | |||||
sizeof(control_page_default)); | sizeof(control_page_default)); | ||||
control_page = &lun->mode_pages.control_page[ | control_page = &lun->mode_pages.control_page[ | ||||
CTL_PAGE_SAVED]; | CTL_PAGE_SAVED]; | ||||
value = ctl_get_opt(&lun->be_lun->options, | value = dnvlist_get_string(lun->be_lun->options, | ||||
"reordering"); | "reordering", NULL); | ||||
if (value != NULL && | if (value != NULL && | ||||
strcmp(value, "unrestricted") == 0) { | strcmp(value, "unrestricted") == 0) { | ||||
control_page->queue_flags &= | control_page->queue_flags &= | ||||
Context not available. | |||||
&lbp_page_default, | &lbp_page_default, | ||||
sizeof(lbp_page_default)); | sizeof(lbp_page_default)); | ||||
page = &lun->mode_pages.lbp_page[CTL_PAGE_SAVED]; | page = &lun->mode_pages.lbp_page[CTL_PAGE_SAVED]; | ||||
value = ctl_get_opt(&lun->be_lun->options, | value = dnvlist_get_string(lun->be_lun->options, | ||||
"avail-threshold"); | "avail-threshold", NULL); | ||||
if (value != NULL && | if (value != NULL && | ||||
ctl_expand_number(value, &ival) == 0) { | ctl_expand_number(value, &ival) == 0) { | ||||
page->descr[0].flags |= SLBPPD_ENABLED | | page->descr[0].flags |= SLBPPD_ENABLED | | ||||
Context not available. | |||||
scsi_ulto4b(ival >> CTL_LBP_EXPONENT, | scsi_ulto4b(ival >> CTL_LBP_EXPONENT, | ||||
page->descr[0].count); | page->descr[0].count); | ||||
} | } | ||||
value = ctl_get_opt(&lun->be_lun->options, | value = dnvlist_get_string(lun->be_lun->options, | ||||
"used-threshold"); | "used-threshold", NULL); | ||||
if (value != NULL && | if (value != NULL && | ||||
ctl_expand_number(value, &ival) == 0) { | ctl_expand_number(value, &ival) == 0) { | ||||
page->descr[1].flags |= SLBPPD_ENABLED | | page->descr[1].flags |= SLBPPD_ENABLED | | ||||
Context not available. | |||||
scsi_ulto4b(ival >> CTL_LBP_EXPONENT, | scsi_ulto4b(ival >> CTL_LBP_EXPONENT, | ||||
page->descr[1].count); | page->descr[1].count); | ||||
} | } | ||||
value = ctl_get_opt(&lun->be_lun->options, | value = dnvlist_get_string(lun->be_lun->options, | ||||
"pool-avail-threshold"); | "pool-avail-threshold", NULL); | ||||
if (value != NULL && | if (value != NULL && | ||||
ctl_expand_number(value, &ival) == 0) { | ctl_expand_number(value, &ival) == 0) { | ||||
page->descr[2].flags |= SLBPPD_ENABLED | | page->descr[2].flags |= SLBPPD_ENABLED | | ||||
Context not available. | |||||
scsi_ulto4b(ival >> CTL_LBP_EXPONENT, | scsi_ulto4b(ival >> CTL_LBP_EXPONENT, | ||||
page->descr[2].count); | page->descr[2].count); | ||||
} | } | ||||
value = ctl_get_opt(&lun->be_lun->options, | value = dnvlist_get_string(lun->be_lun->options, | ||||
"pool-used-threshold"); | "pool-used-threshold", NULL); | ||||
if (value != NULL && | if (value != NULL && | ||||
ctl_expand_number(value, &ival) == 0) { | ctl_expand_number(value, &ival) == 0) { | ||||
page->descr[3].flags |= SLBPPD_ENABLED | | page->descr[3].flags |= SLBPPD_ENABLED | | ||||
Context not available. | |||||
strnlen(be_lun->device_id, CTL_DEVID_LEN)); | strnlen(be_lun->device_id, CTL_DEVID_LEN)); | ||||
idlen1 = sizeof(*t10id) + devidlen; | idlen1 = sizeof(*t10id) + devidlen; | ||||
len = sizeof(struct scsi_vpd_id_descriptor) + idlen1; | 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) { | if (scsiname != NULL) { | ||||
idlen2 = roundup2(strlen(scsiname) + 1, 4); | idlen2 = roundup2(strlen(scsiname) + 1, 4); | ||||
len += sizeof(struct scsi_vpd_id_descriptor) + idlen2; | 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) { | if (eui != NULL) { | ||||
len += sizeof(struct scsi_vpd_id_descriptor) + 16; | 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) { | if (naa != NULL) { | ||||
len += sizeof(struct scsi_vpd_id_descriptor) + 16; | 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) { | if (uuid != NULL) { | ||||
len += sizeof(struct scsi_vpd_id_descriptor) + 18; | len += sizeof(struct scsi_vpd_id_descriptor) + 18; | ||||
} | } | ||||
Context not available. | |||||
desc->length = idlen1; | desc->length = idlen1; | ||||
t10id = (struct scsi_vpd_id_t10 *)&desc->identifier[0]; | t10id = (struct scsi_vpd_id_t10 *)&desc->identifier[0]; | ||||
memset(t10id->vendor, ' ', sizeof(t10id->vendor)); | 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)); | strncpy((char *)t10id->vendor, CTL_VENDOR, sizeof(t10id->vendor)); | ||||
} else { | } else { | ||||
strncpy(t10id->vendor, vendor, | strncpy(t10id->vendor, vendor, | ||||
Context not available. | |||||
if (be_lun->flags & CTL_LUN_FLAG_PRIMARY) | if (be_lun->flags & CTL_LUN_FLAG_PRIMARY) | ||||
lun->flags |= CTL_LUN_PRIMARY_SC; | 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 (value != NULL) { | ||||
if (strcmp(value, "on") == 0) | if (strcmp(value, "on") == 0) | ||||
lun->flags |= CTL_LUN_REMOVABLE; | lun->flags |= CTL_LUN_REMOVABLE; | ||||
Context not available. | |||||
{ | { | ||||
struct ctl_lun *lun = CTL_LUN(ctsio); | struct ctl_lun *lun = CTL_LUN(ctsio); | ||||
struct scsi_vpd_block_limits *bl_ptr; | struct scsi_vpd_block_limits *bl_ptr; | ||||
const char *val; | |||||
uint64_t ival; | uint64_t ival; | ||||
ctsio->kern_data_ptr = malloc(sizeof(*bl_ptr), M_CTL, M_WAITOK | M_ZERO); | ctsio->kern_data_ptr = malloc(sizeof(*bl_ptr), M_CTL, M_WAITOK | M_ZERO); | ||||
Context not available. | |||||
scsi_ulto4b(lun->be_lun->opttxferlen, bl_ptr->opt_txfer_len); | scsi_ulto4b(lun->be_lun->opttxferlen, bl_ptr->opt_txfer_len); | ||||
if (lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) { | if (lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) { | ||||
ival = 0xffffffff; | ival = 0xffffffff; | ||||
ctl_get_opt_number(&lun->be_lun->options, | val = dnvlist_get_string(lun->be_lun->options, | ||||
"unmap_max_lba", &ival); | "unmap_max_lba", NULL); | ||||
if (val != NULL) | |||||
ctl_expand_number(val, &ival); | |||||
scsi_ulto4b(ival, bl_ptr->max_unmap_lba_cnt); | scsi_ulto4b(ival, bl_ptr->max_unmap_lba_cnt); | ||||
ival = 0xffffffff; | ival = 0xffffffff; | ||||
ctl_get_opt_number(&lun->be_lun->options, | val = dnvlist_get_string(lun->be_lun->options, | ||||
"unmap_max_descr", &ival); | "unmap_max_descr", NULL); | ||||
if (val != NULL) | |||||
ctl_expand_number(val, &ival); | |||||
scsi_ulto4b(ival, bl_ptr->max_unmap_blk_cnt); | scsi_ulto4b(ival, bl_ptr->max_unmap_blk_cnt); | ||||
if (lun->be_lun->ublockexp != 0) { | if (lun->be_lun->ublockexp != 0) { | ||||
scsi_ulto4b((1 << lun->be_lun->ublockexp), | scsi_ulto4b((1 << lun->be_lun->ublockexp), | ||||
Context not available. | |||||
scsi_ulto4b(0, bl_ptr->max_atomic_transfer_length_with_atomic_boundary); | scsi_ulto4b(0, bl_ptr->max_atomic_transfer_length_with_atomic_boundary); | ||||
scsi_ulto4b(0, bl_ptr->max_atomic_boundary_size); | scsi_ulto4b(0, bl_ptr->max_atomic_boundary_size); | ||||
ival = UINT64_MAX; | 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); | scsi_u64to8b(ival, bl_ptr->max_write_same_length); | ||||
} | } | ||||
Context not available. | |||||
bdc_ptr->page_code = SVPD_BDC; | bdc_ptr->page_code = SVPD_BDC; | ||||
scsi_ulto2b(sizeof(*bdc_ptr) - 4, bdc_ptr->page_length); | scsi_ulto2b(sizeof(*bdc_ptr) - 4, bdc_ptr->page_length); | ||||
if (lun != NULL && | 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); | i = strtol(value, NULL, 0); | ||||
else | else | ||||
i = CTL_DEFAULT_ROTATION_RATE; | i = CTL_DEFAULT_ROTATION_RATE; | ||||
scsi_ulto2b(i, bdc_ptr->medium_rotation_rate); | scsi_ulto2b(i, bdc_ptr->medium_rotation_rate); | ||||
if (lun != NULL && | 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); | i = strtol(value, NULL, 0); | ||||
else | else | ||||
i = 0; | i = 0; | ||||
Context not available. | |||||
if (lun != NULL && lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) { | if (lun != NULL && lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) { | ||||
lbp_ptr->flags = SVPD_LBP_UNMAP | SVPD_LBP_WS16 | | lbp_ptr->flags = SVPD_LBP_UNMAP | SVPD_LBP_WS16 | | ||||
SVPD_LBP_WS10 | SVPD_LBP_RZ | SVPD_LBP_ANC_SUP; | 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 (value != NULL) { | ||||
if (strcmp(value, "resource") == 0) | if (strcmp(value, "resource") == 0) | ||||
lbp_ptr->prov_type = SVPD_LBP_RESOURCE; | lbp_ptr->prov_type = SVPD_LBP_RESOURCE; | ||||
Context not available. | |||||
struct ctl_lun *lun = CTL_LUN(ctsio); | struct ctl_lun *lun = CTL_LUN(ctsio); | ||||
struct scsi_inquiry_data *inq_ptr; | struct scsi_inquiry_data *inq_ptr; | ||||
struct scsi_inquiry *cdb; | struct scsi_inquiry *cdb; | ||||
char *val; | const char *val; | ||||
uint32_t alloc_len, data_len; | uint32_t alloc_len, data_len; | ||||
ctl_port_type port_type; | ctl_port_type port_type; | ||||
Context not available. | |||||
* We have 8 bytes for the vendor name, and 16 bytes for the device | * We have 8 bytes for the vendor name, and 16 bytes for the device | ||||
* name and 4 bytes for the revision. | * name and 4 bytes for the revision. | ||||
*/ | */ | ||||
if (lun == NULL || (val = ctl_get_opt(&lun->be_lun->options, | if (lun == NULL || (val = dnvlist_get_string(lun->be_lun->options, | ||||
"vendor")) == NULL) { | "vendor", NULL)) == NULL) { | ||||
strncpy(inq_ptr->vendor, CTL_VENDOR, sizeof(inq_ptr->vendor)); | strncpy(inq_ptr->vendor, CTL_VENDOR, sizeof(inq_ptr->vendor)); | ||||
} else { | } else { | ||||
memset(inq_ptr->vendor, ' ', sizeof(inq_ptr->vendor)); | memset(inq_ptr->vendor, ' ', sizeof(inq_ptr->vendor)); | ||||
Context not available. | |||||
if (lun == NULL) { | if (lun == NULL) { | ||||
strncpy(inq_ptr->product, CTL_DIRECT_PRODUCT, | strncpy(inq_ptr->product, CTL_DIRECT_PRODUCT, | ||||
sizeof(inq_ptr->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) { | switch (lun->be_lun->lun_type) { | ||||
case T_DIRECT: | case T_DIRECT: | ||||
strncpy(inq_ptr->product, CTL_DIRECT_PRODUCT, | strncpy(inq_ptr->product, CTL_DIRECT_PRODUCT, | ||||
Context not available. | |||||
* XXX make this a macro somewhere so it automatically gets | * XXX make this a macro somewhere so it automatically gets | ||||
* incremented when we make changes. | * incremented when we make changes. | ||||
*/ | */ | ||||
if (lun == NULL || (val = ctl_get_opt(&lun->be_lun->options, | if (lun == NULL || (val = dnvlist_get_string(lun->be_lun->options, | ||||
"revision")) == NULL) { | "revision", NULL)) == NULL) { | ||||
strncpy(inq_ptr->revision, "0001", sizeof(inq_ptr->revision)); | strncpy(inq_ptr->revision, "0001", sizeof(inq_ptr->revision)); | ||||
} else { | } else { | ||||
memset(inq_ptr->revision, ' ', sizeof(inq_ptr->revision)); | memset(inq_ptr->revision, ' ', sizeof(inq_ptr->revision)); | ||||
Context not available. |
I see here lack of error reporting for both practical case of packed_len > lun_req->result_len and theoretical case of copyout() error. In first case I guess caller now will just try to access memory it did not allocated, while even allocated memory wasn't even written by kernel. I don't know what us supposed reaction of nvlist_unpack() on partial data, may partial return is better then none, but some status should probably be returned here.