summaryrefslogtreecommitdiffstats
path: root/usr.sbin/ctladm
diff options
context:
space:
mode:
authorsjg <sjg@FreeBSD.org>2014-08-19 06:50:54 +0000
committersjg <sjg@FreeBSD.org>2014-08-19 06:50:54 +0000
commitd7cd1d425cc1ea9451fa235e3af9b6625c3e0de2 (patch)
treeb04f4bd7cd887f50e7d98af35f46b9834ff86c80 /usr.sbin/ctladm
parent3c8e37b1d04827f33c0c9a7594bd1b1ef7cdb3d3 (diff)
parent4fbde208c6460d576f64d6dc3cdc6cab085a4283 (diff)
downloadFreeBSD-src-d7cd1d425cc1ea9451fa235e3af9b6625c3e0de2.zip
FreeBSD-src-d7cd1d425cc1ea9451fa235e3af9b6625c3e0de2.tar.gz
Merge head from 7/28
Diffstat (limited to 'usr.sbin/ctladm')
-rw-r--r--usr.sbin/ctladm/ctladm.843
-rw-r--r--usr.sbin/ctladm/ctladm.c275
2 files changed, 314 insertions, 4 deletions
diff --git a/usr.sbin/ctladm/ctladm.8 b/usr.sbin/ctladm/ctladm.8
index 005225c..f58a760 100644
--- a/usr.sbin/ctladm/ctladm.8
+++ b/usr.sbin/ctladm/ctladm.8
@@ -34,7 +34,7 @@
.\" $Id: //depot/users/kenm/FreeBSD-test2/usr.sbin/ctladm/ctladm.8#3 $
.\" $FreeBSD$
.\"
-.Dd October 30, 2013
+.Dd July 9, 2014
.Dt CTLADM 8
.Os
.Sh NAME
@@ -499,7 +499,7 @@ Specify relative addressing for the starting LBA. CTL does not support
relative addressing, since it only works for linked commands, and CTL
does not support linked commands.
.It Fl i
-Tell the target to return status immediately after issuing the SYHCHRONIZE CACHE
+Tell the target to return status immediately after issuing the SYNCHRONIZE CACHE
command rather than waiting for the cache to finish syncing. CTL does not
support this bit.
.It Fl c Ar cdbsize
@@ -933,6 +933,43 @@ Display
.Nm
usage information.
.El
+.Sh OPTIONS
+Number of additional configuration options may be specified for LUNs.
+Some options are global, others are backend-specific.
+.Pp
+Global options:
+.Bl -tag -width 12n
+.It Va vendor
+Specifies LUN vendor string up to 8 chars.
+.It Va product
+Specifies LUN product string up to 16 chars.
+.It Va revision
+Specifies LUN revision string up to 4 chars.
+.It Va scsiname
+Specifies LUN SCSI name string.
+.It Va eui
+Specifies LUN EUI-64 identifier.
+.It Va naa
+Specifies LUN NAA identifier.
+Either EUI or NAA identifier should be set to UNIQUE value to allow
+EXTENDED COPY command access the LUN.
+Non-unique LUN identifiers may lead to data corruption.
+.It Va insecure_tpc
+Setting to "on" allows EXTENDED COPY command sent to this LUN access
+other LUNs on this host, not accessible otherwise.
+This allows to offload copying between different iSCSI targets residing
+on the same host in trusted environments.
+.It Va unmap
+Set to "on", enables UNMAP support for the LUN.
+.El
+.Pp
+Options specific for block backend:
+.Bl -tag -width 12n
+.It Va file
+Specifies file or device name to use for backing store.
+.It Va num_threads
+Specifies number of backend threads to use for this LUN.
+.El
.Sh EXAMPLES
.Dl ctladm tur 0:1
.Pp
@@ -1030,4 +1067,4 @@ The
utility was originally written during the Winter/Spring of 2003 as an
interface to CTL.
.Sh AUTHORS
-.An Ken Merry Aq ken@FreeBSD.org
+.An Ken Merry Aq Mt ken@FreeBSD.org
diff --git a/usr.sbin/ctladm/ctladm.c b/usr.sbin/ctladm/ctladm.c
index 7833155..c362f5c 100644
--- a/usr.sbin/ctladm/ctladm.c
+++ b/usr.sbin/ctladm/ctladm.c
@@ -95,6 +95,7 @@ typedef enum {
CTLADM_CMD_READ,
CTLADM_CMD_WRITE,
CTLADM_CMD_PORT,
+ CTLADM_CMD_PORTLIST,
CTLADM_CMD_READCAPACITY,
CTLADM_CMD_MODESENSE,
CTLADM_CMD_DUMPOOA,
@@ -190,6 +191,7 @@ static struct ctladm_opts option_table[] = {
{"modesense", CTLADM_CMD_MODESENSE, CTLADM_ARG_NEED_TL, "P:S:dlm:c:"},
{"modify", CTLADM_CMD_MODIFY, CTLADM_ARG_NONE, "b:l:s:"},
{"port", CTLADM_CMD_PORT, CTLADM_ARG_NONE, "lo:p:qt:w:W:x"},
+ {"portlist", CTLADM_CMD_PORTLIST, CTLADM_ARG_NONE, "f:vx"},
{"prin", CTLADM_CMD_PRES_IN, CTLADM_ARG_NEED_TL, "a:"},
{"prout", CTLADM_CMD_PRES_OUT, CTLADM_ARG_NEED_TL, "a:k:r:s:"},
{"read", CTLADM_CMD_READ, CTLADM_ARG_NEED_TL, rw_opts},
@@ -498,6 +500,9 @@ retry:
case CTL_PORT_ISCSI:
type = "ISCSI";
break;
+ case CTL_PORT_SAS:
+ type = "SAS";
+ break;
default:
type = "UNKNOWN";
break;
@@ -588,6 +593,7 @@ static struct ctladm_opts cctl_fe_table[] = {
{"scsi", CTL_PORT_SCSI, CTLADM_ARG_NONE, NULL},
{"internal", CTL_PORT_INTERNAL, CTLADM_ARG_NONE, NULL},
{"iscsi", CTL_PORT_ISCSI, CTLADM_ARG_NONE, NULL},
+ {"sas", CTL_PORT_SAS, CTLADM_ARG_NONE, NULL},
{"all", CTL_PORT_ALL, CTLADM_ARG_NONE, NULL},
{NULL, 0, 0, NULL}
};
@@ -4073,6 +4079,269 @@ bailout:
return (retval);
}
+/*
+ * Port information.
+ */
+struct cctl_port {
+ uint64_t port_id;
+ char *online;
+ char *frontend_type;
+ char *name;
+ int pp, vp;
+ char *wwnn, *wwpn;
+ STAILQ_HEAD(,cctl_lun_nv) attr_list;
+ STAILQ_ENTRY(cctl_port) links;
+};
+
+struct cctl_portlist_data {
+ int num_ports;
+ STAILQ_HEAD(,cctl_port) port_list;
+ struct cctl_port *cur_port;
+ int level;
+ struct sbuf *cur_sb[32];
+};
+
+static void
+cctl_start_pelement(void *user_data, const char *name, const char **attr)
+{
+ int i;
+ struct cctl_portlist_data *portlist;
+ struct cctl_port *cur_port;
+
+ portlist = (struct cctl_portlist_data *)user_data;
+ cur_port = portlist->cur_port;
+ portlist->level++;
+ if ((u_int)portlist->level >= (sizeof(portlist->cur_sb) /
+ sizeof(portlist->cur_sb[0])))
+ errx(1, "%s: too many nesting levels, %zd max", __func__,
+ sizeof(portlist->cur_sb) / sizeof(portlist->cur_sb[0]));
+
+ portlist->cur_sb[portlist->level] = sbuf_new_auto();
+ if (portlist->cur_sb[portlist->level] == NULL)
+ err(1, "%s: Unable to allocate sbuf", __func__);
+
+ if (strcmp(name, "targ_port") == 0) {
+ if (cur_port != NULL)
+ errx(1, "%s: improper port element nesting", __func__);
+
+ cur_port = calloc(1, sizeof(*cur_port));
+ if (cur_port == NULL)
+ err(1, "%s: cannot allocate %zd bytes", __func__,
+ sizeof(*cur_port));
+
+ portlist->num_ports++;
+ portlist->cur_port = cur_port;
+
+ STAILQ_INIT(&cur_port->attr_list);
+ STAILQ_INSERT_TAIL(&portlist->port_list, cur_port, links);
+
+ for (i = 0; attr[i] != NULL; i += 2) {
+ if (strcmp(attr[i], "id") == 0) {
+ cur_port->port_id = strtoull(attr[i+1], NULL, 0);
+ } else {
+ errx(1, "%s: invalid LUN attribute %s = %s",
+ __func__, attr[i], attr[i+1]);
+ }
+ }
+ }
+}
+
+static void
+cctl_end_pelement(void *user_data, const char *name)
+{
+ struct cctl_portlist_data *portlist;
+ struct cctl_port *cur_port;
+ char *str;
+
+ portlist = (struct cctl_portlist_data *)user_data;
+ cur_port = portlist->cur_port;
+
+ if ((cur_port == NULL)
+ && (strcmp(name, "ctlportlist") != 0))
+ errx(1, "%s: cur_port == NULL! (name = %s)", __func__, name);
+
+ if (portlist->cur_sb[portlist->level] == NULL)
+ errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
+ portlist->level, name);
+
+ if (sbuf_finish(portlist->cur_sb[portlist->level]) != 0)
+ err(1, "%s: sbuf_finish", __func__);
+ str = strdup(sbuf_data(portlist->cur_sb[portlist->level]));
+ if (str == NULL)
+ err(1, "%s can't allocate %zd bytes for string", __func__,
+ sbuf_len(portlist->cur_sb[portlist->level]));
+
+ if (strlen(str) == 0) {
+ free(str);
+ str = NULL;
+ }
+
+ sbuf_delete(portlist->cur_sb[portlist->level]);
+ portlist->cur_sb[portlist->level] = NULL;
+ portlist->level--;
+
+ if (strcmp(name, "frontend_type") == 0) {
+ cur_port->frontend_type = str;
+ str = NULL;
+ } else if (strcmp(name, "port_name") == 0) {
+ cur_port->name = str;
+ str = NULL;
+ } else if (strcmp(name, "online") == 0) {
+ cur_port->online = str;
+ str = NULL;
+ } else if (strcmp(name, "physical_port") == 0) {
+ cur_port->pp = strtoull(str, NULL, 0);
+ } else if (strcmp(name, "virtual_port") == 0) {
+ cur_port->vp = strtoull(str, NULL, 0);
+ } else if (strcmp(name, "wwnn") == 0) {
+ cur_port->wwnn = str;
+ str = NULL;
+ } else if (strcmp(name, "wwpn") == 0) {
+ cur_port->wwpn = str;
+ str = NULL;
+ } else if (strcmp(name, "targ_port") == 0) {
+ portlist->cur_port = NULL;
+ } else if (strcmp(name, "ctlportlist") == 0) {
+
+ } else {
+ struct cctl_lun_nv *nv;
+
+ nv = calloc(1, sizeof(*nv));
+ if (nv == NULL)
+ err(1, "%s: can't allocate %zd bytes for nv pair",
+ __func__, sizeof(*nv));
+
+ nv->name = strdup(name);
+ if (nv->name == NULL)
+ err(1, "%s: can't allocated %zd bytes for string",
+ __func__, strlen(name));
+
+ nv->value = str;
+ str = NULL;
+ STAILQ_INSERT_TAIL(&cur_port->attr_list, nv, links);
+ }
+
+ free(str);
+}
+
+static void
+cctl_char_phandler(void *user_data, const XML_Char *str, int len)
+{
+ struct cctl_portlist_data *portlist;
+
+ portlist = (struct cctl_portlist_data *)user_data;
+
+ sbuf_bcat(portlist->cur_sb[portlist->level], str, len);
+}
+
+static int
+cctl_portlist(int fd, int argc, char **argv, char *combinedopt)
+{
+ struct ctl_lun_list list;
+ struct cctl_portlist_data portlist;
+ struct cctl_port *port;
+ XML_Parser parser;
+ char *port_str;
+ int port_len;
+ int dump_xml = 0;
+ int retval, c;
+ char *frontend = NULL;
+ int verbose = 0;
+
+ retval = 0;
+ port_len = 4096;
+
+ bzero(&portlist, sizeof(portlist));
+ STAILQ_INIT(&portlist.port_list);
+
+ while ((c = getopt(argc, argv, combinedopt)) != -1) {
+ switch (c) {
+ case 'f':
+ frontend = strdup(optarg);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'x':
+ dump_xml = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+retry:
+ port_str = malloc(port_len);
+
+ bzero(&list, sizeof(list));
+ list.alloc_len = port_len;
+ list.status = CTL_LUN_LIST_NONE;
+ list.lun_xml = port_str;
+
+ if (ioctl(fd, CTL_PORT_LIST, &list) == -1) {
+ warn("%s: error issuing CTL_PORT_LIST ioctl", __func__);
+ retval = 1;
+ goto bailout;
+ }
+
+ if (list.status == CTL_LUN_LIST_ERROR) {
+ warnx("%s: error returned from CTL_PORT_LIST ioctl:\n%s",
+ __func__, list.error_str);
+ } else if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
+ port_len = port_len << 1;
+ goto retry;
+ }
+
+ if (dump_xml != 0) {
+ printf("%s", port_str);
+ goto bailout;
+ }
+
+ parser = XML_ParserCreate(NULL);
+ if (parser == NULL) {
+ warn("%s: Unable to create XML parser", __func__);
+ retval = 1;
+ goto bailout;
+ }
+
+ XML_SetUserData(parser, &portlist);
+ XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement);
+ XML_SetCharacterDataHandler(parser, cctl_char_phandler);
+
+ retval = XML_Parse(parser, port_str, strlen(port_str), 1);
+ XML_ParserFree(parser);
+ if (retval != 1) {
+ retval = 1;
+ goto bailout;
+ }
+
+ printf("Port Online Frontend %-12s pp vp %-18s %-18s\n",
+ "Name", "WWNN", "WWPN");
+ STAILQ_FOREACH(port, &portlist.port_list, links) {
+ struct cctl_lun_nv *nv;
+
+ if ((frontend != NULL)
+ && (strcmp(port->frontend_type, frontend) != 0))
+ continue;
+
+ printf("%-4ju %-6s %-8s %-12s %-2d %-2d %-18s %-18s\n",
+ (uintmax_t)port->port_id, port->online,
+ port->frontend_type, port->name, port->pp, port->vp,
+ port->wwnn, port->wwpn);
+
+ if (verbose == 0)
+ continue;
+
+ STAILQ_FOREACH(nv, &port->attr_list, links) {
+ printf(" %s=%s\n", nv->name, nv->value);
+ }
+ }
+bailout:
+ free(port_str);
+
+ return (retval);
+}
+
void
usage(int error)
{
@@ -4104,7 +4373,7 @@ usage(int error)
" [-S serial_num] [-t dev_type]\n"
" ctladm remove <-b backend> <-l lun_id> [-o name=value]\n"
" ctladm modify <-b backend> <-l lun_id> <-s size_bytes>\n"
-" ctladm devlist [-b][-v][-x]\n"
+" ctladm devlist [-b backend] [-v] [-x]\n"
" ctladm shutdown\n"
" ctladm startup\n"
" ctladm hardstop\n"
@@ -4120,6 +4389,7 @@ usage(int error)
" [-s len fmt [args]] [-c] [-d delete_id]\n"
" ctladm port <-l | -o <on|off> | [-w wwnn][-W wwpn]>\n"
" [-p targ_port] [-t port_type] [-q] [-x]\n"
+" ctladm portlist [-f frontend] [-v] [-x]\n"
" ctladm islist [-v | -x]\n"
" ctladm islogout <-a | -c connection-id | -i name | -p portal>\n"
" ctladm isterminate <-a | -c connection-id | -i name | -p portal>\n"
@@ -4429,6 +4699,9 @@ main(int argc, char **argv)
case CTLADM_CMD_PORT:
retval = cctl_port(fd, argc, argv, combinedopt);
break;
+ case CTLADM_CMD_PORTLIST:
+ retval = cctl_portlist(fd, argc, argv, combinedopt);
+ break;
case CTLADM_CMD_READCAPACITY:
retval = cctl_read_capacity(fd, target, lun, initid, retries,
argc, argv, combinedopt);
OpenPOWER on IntegriCloud