Changeset View
Changeset View
Standalone View
Standalone View
sys/cam/ctl/ctl.c
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
/*- | /*- | ||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD | ||||
* | * | ||||
* Copyright (c) 2003-2009 Silicon Graphics International Corp. | * Copyright (c) 2003-2009 Silicon Graphics International Corp. | ||||
* Copyright (c) 2012 The FreeBSD Foundation | * Copyright (c) 2012 The FreeBSD Foundation | ||||
* Copyright (c) 2014-2017 Alexander Motin <mav@FreeBSD.org> | * Copyright (c) 2014-2017 Alexander Motin <mav@FreeBSD.org> | ||||
* Copyright (c) 2017 Jakub Wojciech Klama <jceel@FreeBSD.org> | |||||
* Copyright (c) 2018 Marcelo Araujo <araujo@FreeBSD.org> | |||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Portions of this software were developed by Edward Tomasz Napierala | * Portions of this software were developed by Edward Tomasz Napierala | ||||
* under sponsorship from the FreeBSD Foundation. | * under sponsorship from the FreeBSD Foundation. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||
#include <sys/ioccom.h> | #include <sys/ioccom.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <sys/sbuf.h> | #include <sys/sbuf.h> | ||||
#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> | ||||
#include <cam/scsi/scsi_all.h> | #include <cam/scsi/scsi_all.h> | ||||
#include <cam/scsi/scsi_cd.h> | #include <cam/scsi/scsi_cd.h> | ||||
#include <cam/scsi/scsi_da.h> | #include <cam/scsi/scsi_da.h> | ||||
#include <cam/ctl/ctl_io.h> | #include <cam/ctl/ctl_io.h> | ||||
#include <cam/ctl/ctl.h> | #include <cam/ctl/ctl.h> | ||||
▲ Show 20 Lines • Show All 1,788 Lines • ▼ Show 20 Lines | softc = control_softc = malloc(sizeof(*control_softc), M_DEVBUF, | ||||
M_WAITOK | M_ZERO); | M_WAITOK | M_ZERO); | ||||
make_dev_args_init(&args); | make_dev_args_init(&args); | ||||
args.mda_devsw = &ctl_cdevsw; | args.mda_devsw = &ctl_cdevsw; | ||||
args.mda_uid = UID_ROOT; | args.mda_uid = UID_ROOT; | ||||
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); | ||||
control_softc = NULL; | control_softc = NULL; | ||||
return (error); | return (error); | ||||
} | } | ||||
sysctl_ctx_init(&softc->sysctl_ctx); | sysctl_ctx_init(&softc->sysctl_ctx); | ||||
▲ Show 20 Lines • Show All 583 Lines • ▼ Show 20 Lines | snprintf(error_str, error_str_len, "Error copying %d bytes " | ||||
user_addr, kptr); | user_addr, kptr); | ||||
free(kptr, M_CTL); | free(kptr, M_CTL); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
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. | ||||
*/ | */ | ||||
int | int | ||||
ctl_sbuf_printf_esc(struct sbuf *sb, char *str, int size) | ctl_sbuf_printf_esc(struct sbuf *sb, char *str, int size) | ||||
{ | { | ||||
char *end = str + size; | char *end = str + size; | ||||
int retval; | int retval; | ||||
▲ Show 20 Lines • Show All 448 Lines • ▼ Show 20 Lines | case CTL_DUMP_STRUCTS: { | ||||
* to drop the lock before calling the frontend's dump | * to drop the lock before calling the frontend's dump | ||||
* routine anyway. | * routine anyway. | ||||
*/ | */ | ||||
printf("CTL Frontends:\n"); | printf("CTL Frontends:\n"); | ||||
STAILQ_FOREACH(fe, &softc->fe_list, links) { | STAILQ_FOREACH(fe, &softc->fe_list, links) { | ||||
printf(" Frontend '%s'\n", fe->name); | printf(" Frontend '%s'\n", fe->name); | ||||
if (fe->fe_dump != NULL) | if (fe->fe_dump != NULL) | ||||
fe->fe_dump(); | fe->fe_dump(); | ||||
} | } | ||||
mav: I see here lack of error reporting for both practical case of packed_len > lun_req->result_len… | |||||
printf("CTL Frontend information end\n"); | printf("CTL Frontend information end\n"); | ||||
break; | break; | ||||
} | } | ||||
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) { | ||||
lun_req->status = CTL_LUN_ERROR; | lun_req->status = CTL_LUN_ERROR; | ||||
snprintf(lun_req->error_str, | snprintf(lun_req->error_str, | ||||
sizeof(lun_req->error_str), | sizeof(lun_req->error_str), | ||||
"Backend \"%s\" not found.", | "Backend \"%s\" not found.", | ||||
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_nvl = nvlist_unpack(lun_req->args, | ||||
lun_req->be_args, | lun_req->args_len, 0); | ||||
lun_req->error_str, | |||||
sizeof(lun_req->error_str)); | if (lun_req->args_nvl == NULL) { | ||||
if (lun_req->kern_be_args == NULL) { | |||||
lun_req->status = CTL_LUN_ERROR; | lun_req->status = CTL_LUN_ERROR; | ||||
snprintf(lun_req->error_str, sizeof(lun_req->error_str), | |||||
"Cannot unpack args nvlist."); | |||||
break; | 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."); | |||||
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; | 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; | |||||
} | |||||
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; | |||||
int type; | |||||
list = (struct ctl_lun_list *)addr; | list = (struct ctl_lun_list *)addr; | ||||
/* | /* | ||||
* Allocate a fixed length sbuf here, based on the length | * Allocate a fixed length sbuf here, based on the length | ||||
* of the user's buffer. We could allocate an auto-extending | * of the user's buffer. We could allocate an auto-extending | ||||
* buffer, and then tell the user how much larger our | * buffer, and then tell the user how much larger our | ||||
* amount of data is than his buffer, but that presents | * amount of data is than his buffer, but that presents | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | STAILQ_FOREACH(lun, &softc->lun_list, links) { | ||||
retval = sbuf_printf(sb, "\t<backend_type>%s" | retval = sbuf_printf(sb, "\t<backend_type>%s" | ||||
"</backend_type>\n", | "</backend_type>\n", | ||||
(lun->backend == NULL) ? "none" : | (lun->backend == NULL) ? "none" : | ||||
lun->backend->name); | lun->backend->name); | ||||
if (retval != 0) | if (retval != 0) | ||||
break; | break; | ||||
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… | |||||
retval = sbuf_printf(sb, "\t<lun_type>%d</lun_type>\n", | retval = sbuf_printf(sb, "\t<lun_type>%d</lun_type>\n", | ||||
lun->be_lun->lun_type); | lun->be_lun->lun_type); | ||||
if (retval != 0) | if (retval != 0) | ||||
break; | break; | ||||
if (lun->backend == NULL) { | if (lun->backend == NULL) { | ||||
retval = sbuf_printf(sb, "</lun>\n"); | retval = sbuf_printf(sb, "</lun>\n"); | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | STAILQ_FOREACH(lun, &softc->lun_list, links) { | ||||
if (retval != 0) | if (retval != 0) | ||||
break; | break; | ||||
if (lun->backend->lun_info != NULL) { | if (lun->backend->lun_info != NULL) { | ||||
retval = lun->backend->lun_info(lun->be_lun->be_lun, sb); | retval = lun->backend->lun_info(lun->be_lun->be_lun, sb); | ||||
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", | cookie = NULL; | ||||
opt->name, opt->value, opt->name); | while ((name = nvlist_next(lun->be_lun->options, &type, | ||||
if (retval != 0) | &cookie)) != NULL) { | ||||
break; | sbuf_printf(sb, "\t<%s>", name); | ||||
if (type == NV_TYPE_STRING) { | |||||
value = dnvlist_get_string( | |||||
lun->be_lun->options, name, NULL); | |||||
if (value != NULL) | |||||
sbuf_printf(sb, "%s", value); | |||||
} | } | ||||
sbuf_printf(sb, "</%s>\n", name); | |||||
} | |||||
retval = sbuf_printf(sb, "</lun>\n"); | retval = sbuf_printf(sb, "</lun>\n"); | ||||
if (retval != 0) | if (retval != 0) | ||||
break; | break; | ||||
mtx_unlock(&lun->lun_lock); | mtx_unlock(&lun->lun_lock); | ||||
} | } | ||||
if (lun != NULL) | if (lun != NULL) | ||||
mtx_unlock(&lun->lun_lock); | mtx_unlock(&lun->lun_lock); | ||||
Show All 26 Lines | case CTL_ISCSI: { | ||||
ci = (struct ctl_iscsi *)addr; | ci = (struct ctl_iscsi *)addr; | ||||
fe = ctl_frontend_find("iscsi"); | fe = ctl_frontend_find("iscsi"); | ||||
if (fe == NULL) { | if (fe == NULL) { | ||||
ci->status = CTL_ISCSI_ERROR; | ci->status = CTL_ISCSI_ERROR; | ||||
snprintf(ci->error_str, sizeof(ci->error_str), | snprintf(ci->error_str, sizeof(ci->error_str), | ||||
"Frontend \"iscsi\" not found."); | "Frontend \"iscsi\" not found."); | ||||
break; | break; | ||||
Not Done Inline ActionsSame comment as for LUNs. mav: Same comment as for LUNs. | |||||
} | } | ||||
retval = fe->ioctl(dev, cmd, addr, flag, td); | retval = fe->ioctl(dev, cmd, addr, flag, td); | ||||
break; | break; | ||||
} | } | ||||
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) { | ||||
req->status = CTL_LUN_ERROR; | req->status = CTL_LUN_ERROR; | ||||
snprintf(req->error_str, sizeof(req->error_str), | snprintf(req->error_str, sizeof(req->error_str), | ||||
"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_nvl = nvlist_unpack(req->args, | ||||
if (req->kern_args == NULL) { | req->args_len, 0); | ||||
if (req->args_nvl == NULL) { | |||||
req->status = CTL_LUN_ERROR; | req->status = CTL_LUN_ERROR; | ||||
snprintf(req->error_str, sizeof(req->error_str), | |||||
"Cannot unpack args nvlist."); | |||||
break; | 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; | |||||
} | } | ||||
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; | 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; | |||||
} | |||||
case CTL_PORT_LIST: { | case CTL_PORT_LIST: { | ||||
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; | ||||
Done Inline ActionsWhy to use separate lines? mav: Why to use separate lines? | |||||
int j, type; | |||||
uint32_t plun; | uint32_t plun; | ||||
list = (struct ctl_lun_list *)addr; | list = (struct ctl_lun_list *)addr; | ||||
sb = sbuf_new(NULL, NULL, list->alloc_len, SBUF_FIXEDLEN); | sb = sbuf_new(NULL, NULL, list->alloc_len, SBUF_FIXEDLEN); | ||||
if (sb == NULL) { | if (sb == NULL) { | ||||
list->status = CTL_LUN_LIST_ERROR; | list->status = CTL_LUN_LIST_ERROR; | ||||
snprintf(list->error_str, sizeof(list->error_str), | snprintf(list->error_str, sizeof(list->error_str), | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | STAILQ_FOREACH(port, &softc->port_list, links) { | ||||
sbuf_printf(sb, "</port>\n"); | sbuf_printf(sb, "</port>\n"); | ||||
} | } | ||||
if (port->port_info != NULL) { | if (port->port_info != NULL) { | ||||
retval = port->port_info(port->onoff_arg, sb); | retval = port->port_info(port->onoff_arg, sb); | ||||
if (retval != 0) | if (retval != 0) | ||||
break; | break; | ||||
} | } | ||||
STAILQ_FOREACH(opt, &port->options, links) { | |||||
retval = sbuf_printf(sb, "\t<%s>%s</%s>\n", | cookie = NULL; | ||||
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 = dnvlist_get_string(port->options, | |||||
name, NULL); | |||||
if (value != NULL) | |||||
sbuf_printf(sb, "%s", value); | |||||
} | } | ||||
sbuf_printf(sb, "</%s>\n", name); | |||||
} | |||||
if (port->lun_map != NULL) { | if (port->lun_map != NULL) { | ||||
sbuf_printf(sb, "\t<lun_map>on</lun_map>\n"); | sbuf_printf(sb, "\t<lun_map>on</lun_map>\n"); | ||||
for (j = 0; j < port->lun_map_size; j++) { | for (j = 0; j < port->lun_map_size; j++) { | ||||
plun = ctl_lun_map_from_port(port, j); | plun = ctl_lun_map_from_port(port, j); | ||||
if (plun == UINT32_MAX) | if (plun == UINT32_MAX) | ||||
continue; | continue; | ||||
sbuf_printf(sb, | sbuf_printf(sb, | ||||
"\t<lun id=\"%u\">%u</lun>\n", | "\t<lun id=\"%u\">%u</lun>\n", | ||||
▲ Show 20 Lines • Show All 788 Lines • ▼ Show 20 Lines | #endif | ||||
*/ | */ | ||||
if (cylinders > 0xffffff) | if (cylinders > 0xffffff) | ||||
cylinders = 0xffffff; | cylinders = 0xffffff; | ||||
rigid_disk_page = &lun->mode_pages.rigid_disk_page[ | rigid_disk_page = &lun->mode_pages.rigid_disk_page[ | ||||
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); | ||||
} | } | ||||
memcpy(&lun->mode_pages.rigid_disk_page[CTL_PAGE_CURRENT], | memcpy(&lun->mode_pages.rigid_disk_page[CTL_PAGE_CURRENT], | ||||
&lun->mode_pages.rigid_disk_page[CTL_PAGE_DEFAULT], | &lun->mode_pages.rigid_disk_page[CTL_PAGE_DEFAULT], | ||||
sizeof(rigid_disk_page_default)); | sizeof(rigid_disk_page_default)); | ||||
memcpy(&lun->mode_pages.rigid_disk_page[CTL_PAGE_SAVED], | memcpy(&lun->mode_pages.rigid_disk_page[CTL_PAGE_SAVED], | ||||
Show All 36 Lines | case SMS_CACHING_PAGE: { | ||||
memcpy(&lun->mode_pages.caching_page[ | memcpy(&lun->mode_pages.caching_page[ | ||||
CTL_PAGE_CHANGEABLE], &caching_page_changeable, | CTL_PAGE_CHANGEABLE], &caching_page_changeable, | ||||
sizeof(caching_page_changeable)); | sizeof(caching_page_changeable)); | ||||
memcpy(&lun->mode_pages.caching_page[CTL_PAGE_SAVED], | memcpy(&lun->mode_pages.caching_page[CTL_PAGE_SAVED], | ||||
&caching_page_default, | &caching_page_default, | ||||
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], | ||||
&lun->mode_pages.caching_page[CTL_PAGE_SAVED], | &lun->mode_pages.caching_page[CTL_PAGE_SAVED], | ||||
sizeof(caching_page_default)); | sizeof(caching_page_default)); | ||||
page_index->page_data = | page_index->page_data = | ||||
(uint8_t *)lun->mode_pages.caching_page; | (uint8_t *)lun->mode_pages.caching_page; | ||||
break; | break; | ||||
Show All 12 Lines | case SMS_CONTROL_MODE_PAGE: { | ||||
&control_page_changeable, | &control_page_changeable, | ||||
sizeof(control_page_changeable)); | sizeof(control_page_changeable)); | ||||
memcpy(&lun->mode_pages.control_page[ | memcpy(&lun->mode_pages.control_page[ | ||||
CTL_PAGE_SAVED], | CTL_PAGE_SAVED], | ||||
&control_page_default, | &control_page_default, | ||||
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 &= | ||||
~SCP_QUEUE_ALG_MASK; | ~SCP_QUEUE_ALG_MASK; | ||||
control_page->queue_flags |= | control_page->queue_flags |= | ||||
SCP_QUEUE_ALG_UNRESTRICTED; | SCP_QUEUE_ALG_UNRESTRICTED; | ||||
} | } | ||||
memcpy(&lun->mode_pages.control_page[ | memcpy(&lun->mode_pages.control_page[ | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | case SMS_INFO_EXCEPTIONS_PAGE: { | ||||
sizeof(lbp_page_default)); | sizeof(lbp_page_default)); | ||||
memcpy(&lun->mode_pages.lbp_page[ | memcpy(&lun->mode_pages.lbp_page[ | ||||
CTL_PAGE_CHANGEABLE], &lbp_page_changeable, | CTL_PAGE_CHANGEABLE], &lbp_page_changeable, | ||||
sizeof(lbp_page_changeable)); | sizeof(lbp_page_changeable)); | ||||
memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_SAVED], | memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_SAVED], | ||||
&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 | | ||||
SLBPPD_ARMING_DEC; | SLBPPD_ARMING_DEC; | ||||
if (lun->be_lun->blocksize) | if (lun->be_lun->blocksize) | ||||
ival /= lun->be_lun->blocksize; | ival /= lun->be_lun->blocksize; | ||||
else | else | ||||
ival /= 512; | ival /= 512; | ||||
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 | | ||||
SLBPPD_ARMING_INC; | SLBPPD_ARMING_INC; | ||||
if (lun->be_lun->blocksize) | if (lun->be_lun->blocksize) | ||||
ival /= lun->be_lun->blocksize; | ival /= lun->be_lun->blocksize; | ||||
else | else | ||||
ival /= 512; | ival /= 512; | ||||
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 | | ||||
SLBPPD_ARMING_DEC; | SLBPPD_ARMING_DEC; | ||||
if (lun->be_lun->blocksize) | if (lun->be_lun->blocksize) | ||||
ival /= lun->be_lun->blocksize; | ival /= lun->be_lun->blocksize; | ||||
else | else | ||||
ival /= 512; | ival /= 512; | ||||
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 | | ||||
SLBPPD_ARMING_INC; | SLBPPD_ARMING_INC; | ||||
if (lun->be_lun->blocksize) | if (lun->be_lun->blocksize) | ||||
ival /= lun->be_lun->blocksize; | ival /= lun->be_lun->blocksize; | ||||
else | else | ||||
ival /= 512; | ival /= 512; | ||||
▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Lines | ctl_alloc_lun(struct ctl_softc *ctl_softc, struct ctl_lun *ctl_lun, | ||||
lun->pr_keys = malloc(sizeof(uint64_t *) * ctl_max_ports, | lun->pr_keys = malloc(sizeof(uint64_t *) * ctl_max_ports, | ||||
M_DEVBUF, M_WAITOK | M_ZERO); | M_DEVBUF, M_WAITOK | M_ZERO); | ||||
/* Generate LUN ID. */ | /* Generate LUN ID. */ | ||||
devidlen = max(CTL_DEVID_MIN_LEN, | devidlen = max(CTL_DEVID_MIN_LEN, | ||||
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; | ||||
} | } | ||||
lun->lun_devid = malloc(sizeof(struct ctl_devid) + len, | lun->lun_devid = malloc(sizeof(struct ctl_devid) + len, | ||||
M_CTL, M_WAITOK | M_ZERO); | M_CTL, M_WAITOK | M_ZERO); | ||||
desc = (struct scsi_vpd_id_descriptor *)lun->lun_devid->data; | desc = (struct scsi_vpd_id_descriptor *)lun->lun_devid->data; | ||||
desc->proto_codeset = SVPD_ID_CODESET_ASCII; | desc->proto_codeset = SVPD_ID_CODESET_ASCII; | ||||
desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_LUN | SVPD_ID_TYPE_T10; | desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_LUN | SVPD_ID_TYPE_T10; | ||||
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, | ||||
min(sizeof(t10id->vendor), strlen(vendor))); | min(sizeof(t10id->vendor), strlen(vendor))); | ||||
} | } | ||||
strncpy((char *)t10id->vendor_spec_id, | strncpy((char *)t10id->vendor_spec_id, | ||||
(char *)be_lun->device_id, devidlen); | (char *)be_lun->device_id, devidlen); | ||||
if (scsiname != NULL) { | if (scsiname != NULL) { | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | fail: | ||||
if (be_lun->flags & CTL_LUN_FLAG_NO_MEDIA) | if (be_lun->flags & CTL_LUN_FLAG_NO_MEDIA) | ||||
lun->flags |= CTL_LUN_NO_MEDIA; | lun->flags |= CTL_LUN_NO_MEDIA; | ||||
if (be_lun->flags & CTL_LUN_FLAG_STOPPED) | if (be_lun->flags & CTL_LUN_FLAG_STOPPED) | ||||
lun->flags |= CTL_LUN_STOPPED; | lun->flags |= CTL_LUN_STOPPED; | ||||
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; | ||||
} else if (be_lun->lun_type == T_CDROM) | } else if (be_lun->lun_type == T_CDROM) | ||||
lun->flags |= CTL_LUN_REMOVABLE; | lun->flags |= CTL_LUN_REMOVABLE; | ||||
lun->ctl_softc = ctl_softc; | lun->ctl_softc = ctl_softc; | ||||
#ifdef CTL_TIME_IO | #ifdef CTL_TIME_IO | ||||
▲ Show 20 Lines • Show All 5,036 Lines • ▼ Show 20 Lines | ctl_inquiry_evpd_scsi_ports(struct ctl_scsiio *ctsio, int alloc_len) | ||||
return (CTL_RETVAL_COMPLETE); | return (CTL_RETVAL_COMPLETE); | ||||
} | } | ||||
static int | static int | ||||
ctl_inquiry_evpd_block_limits(struct ctl_scsiio *ctsio, int alloc_len) | ctl_inquiry_evpd_block_limits(struct ctl_scsiio *ctsio, int alloc_len) | ||||
{ | { | ||||
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); | ||||
bl_ptr = (struct scsi_vpd_block_limits *)ctsio->kern_data_ptr; | bl_ptr = (struct scsi_vpd_block_limits *)ctsio->kern_data_ptr; | ||||
ctsio->kern_sg_entries = 0; | ctsio->kern_sg_entries = 0; | ||||
ctsio->kern_rel_offset = 0; | ctsio->kern_rel_offset = 0; | ||||
ctsio->kern_sg_entries = 0; | ctsio->kern_sg_entries = 0; | ||||
ctsio->kern_data_len = min(sizeof(*bl_ptr), alloc_len); | ctsio->kern_data_len = min(sizeof(*bl_ptr), alloc_len); | ||||
Show All 13 Lines | ctl_inquiry_evpd_block_limits(struct ctl_scsiio *ctsio, int alloc_len) | ||||
bl_ptr->page_code = SVPD_BLOCK_LIMITS; | bl_ptr->page_code = SVPD_BLOCK_LIMITS; | ||||
scsi_ulto2b(sizeof(*bl_ptr) - 4, bl_ptr->page_length); | scsi_ulto2b(sizeof(*bl_ptr) - 4, bl_ptr->page_length); | ||||
bl_ptr->max_cmp_write_len = 0xff; | bl_ptr->max_cmp_write_len = 0xff; | ||||
scsi_ulto4b(0xffffffff, bl_ptr->max_txfer_len); | scsi_ulto4b(0xffffffff, bl_ptr->max_txfer_len); | ||||
if (lun != NULL) { | if (lun != NULL) { | ||||
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), | ||||
bl_ptr->opt_unmap_grain); | bl_ptr->opt_unmap_grain); | ||||
scsi_ulto4b(0x80000000 | lun->be_lun->ublockoff, | scsi_ulto4b(0x80000000 | lun->be_lun->ublockoff, | ||||
bl_ptr->unmap_grain_align); | bl_ptr->unmap_grain_align); | ||||
} | } | ||||
} | } | ||||
scsi_ulto4b(lun->be_lun->atomicblock, | scsi_ulto4b(lun->be_lun->atomicblock, | ||||
bl_ptr->max_atomic_transfer_length); | bl_ptr->max_atomic_transfer_length); | ||||
scsi_ulto4b(0, bl_ptr->atomic_alignment); | scsi_ulto4b(0, bl_ptr->atomic_alignment); | ||||
scsi_ulto4b(0, bl_ptr->atomic_transfer_length_granularity); | scsi_ulto4b(0, bl_ptr->atomic_transfer_length_granularity); | ||||
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); | ||||
} | } | ||||
ctl_set_success(ctsio); | ctl_set_success(ctsio); | ||||
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; | ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; | ||||
ctsio->be_move_done = ctl_config_move_done; | ctsio->be_move_done = ctl_config_move_done; | ||||
ctl_datamove((union ctl_io *)ctsio); | ctl_datamove((union ctl_io *)ctsio); | ||||
return (CTL_RETVAL_COMPLETE); | return (CTL_RETVAL_COMPLETE); | ||||
Show All 22 Lines | ctl_inquiry_evpd_bdc(struct ctl_scsiio *ctsio, int alloc_len) | ||||
if (lun != NULL) | if (lun != NULL) | ||||
bdc_ptr->device = (SID_QUAL_LU_CONNECTED << 5) | | bdc_ptr->device = (SID_QUAL_LU_CONNECTED << 5) | | ||||
lun->be_lun->lun_type; | lun->be_lun->lun_type; | ||||
else | else | ||||
bdc_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | T_DIRECT; | bdc_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | T_DIRECT; | ||||
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; | ||||
bdc_ptr->wab_wac_ff = (i & 0x0f); | bdc_ptr->wab_wac_ff = (i & 0x0f); | ||||
bdc_ptr->flags = SVPD_FUAB | SVPD_VBULS; | bdc_ptr->flags = SVPD_FUAB | SVPD_VBULS; | ||||
ctl_set_success(ctsio); | ctl_set_success(ctsio); | ||||
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; | ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; | ||||
Show All 28 Lines | else | ||||
lbp_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | T_DIRECT; | lbp_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | T_DIRECT; | ||||
lbp_ptr->page_code = SVPD_LBP; | lbp_ptr->page_code = SVPD_LBP; | ||||
scsi_ulto2b(sizeof(*lbp_ptr) - 4, lbp_ptr->page_length); | scsi_ulto2b(sizeof(*lbp_ptr) - 4, lbp_ptr->page_length); | ||||
lbp_ptr->threshold_exponent = CTL_LBP_EXPONENT; | lbp_ptr->threshold_exponent = CTL_LBP_EXPONENT; | ||||
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; | ||||
else if (strcmp(value, "thin") == 0) | else if (strcmp(value, "thin") == 0) | ||||
lbp_ptr->prov_type = SVPD_LBP_THIN; | lbp_ptr->prov_type = SVPD_LBP_THIN; | ||||
} else | } else | ||||
lbp_ptr->prov_type = SVPD_LBP_THIN; | lbp_ptr->prov_type = SVPD_LBP_THIN; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
ctl_inquiry_std(struct ctl_scsiio *ctsio) | ctl_inquiry_std(struct ctl_scsiio *ctsio) | ||||
{ | { | ||||
struct ctl_softc *softc = CTL_SOFTC(ctsio); | struct ctl_softc *softc = CTL_SOFTC(ctsio); | ||||
struct ctl_port *port = CTL_PORT(ctsio); | struct ctl_port *port = CTL_PORT(ctsio); | ||||
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; | ||||
port_type = port->port_type; | port_type = port->port_type; | ||||
if (port_type == CTL_PORT_IOCTL || port_type == CTL_PORT_INTERNAL) | if (port_type == CTL_PORT_IOCTL || port_type == CTL_PORT_INTERNAL) | ||||
port_type = CTL_PORT_SCSI; | port_type = CTL_PORT_SCSI; | ||||
cdb = (struct scsi_inquiry *)ctsio->cdb; | cdb = (struct scsi_inquiry *)ctsio->cdb; | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | ctl_inquiry_std(struct ctl_scsiio *ctsio) | ||||
if (port_type == CTL_PORT_SCSI) | if (port_type == CTL_PORT_SCSI) | ||||
inq_ptr->flags |= SID_WBus16 | SID_Sync; | inq_ptr->flags |= SID_WBus16 | SID_Sync; | ||||
/* | /* | ||||
* Per SPC-3, unused bytes in ASCII strings are filled with spaces. | * Per SPC-3, unused bytes in ASCII strings are filled with spaces. | ||||
* 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)); | ||||
strncpy(inq_ptr->vendor, val, | strncpy(inq_ptr->vendor, val, | ||||
min(sizeof(inq_ptr->vendor), strlen(val))); | min(sizeof(inq_ptr->vendor), strlen(val))); | ||||
} | } | ||||
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, | ||||
sizeof(inq_ptr->product)); | sizeof(inq_ptr->product)); | ||||
break; | break; | ||||
case T_PROCESSOR: | case T_PROCESSOR: | ||||
strncpy(inq_ptr->product, CTL_PROCESSOR_PRODUCT, | strncpy(inq_ptr->product, CTL_PROCESSOR_PRODUCT, | ||||
sizeof(inq_ptr->product)); | sizeof(inq_ptr->product)); | ||||
Show All 12 Lines | if (lun == NULL) { | ||||
strncpy(inq_ptr->product, val, | strncpy(inq_ptr->product, val, | ||||
min(sizeof(inq_ptr->product), strlen(val))); | min(sizeof(inq_ptr->product), strlen(val))); | ||||
} | } | ||||
/* | /* | ||||
* 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)); | ||||
strncpy(inq_ptr->revision, val, | strncpy(inq_ptr->revision, val, | ||||
min(sizeof(inq_ptr->revision), strlen(val))); | min(sizeof(inq_ptr->revision), strlen(val))); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 3,456 Lines • Show Last 20 Lines |
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.