Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 5 Jul 2014 05:44:26 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r268284 - in head: sys/cam/ctl usr.sbin/ctladm
Message-ID:  <201407050544.s655iQ79031856@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Sat Jul  5 05:44:26 2014
New Revision: 268284
URL: http://svnweb.freebsd.org/changeset/base/268284

Log:
  Introduce new IOCTL CTL_PORT_LIST reporting in more flexible XML format.
  
  Leave old CTL_GET_PORT_LIST in place so far.  Garbage-collect it later.

Modified:
  head/sys/cam/ctl/ctl.c
  head/sys/cam/ctl/ctl_ioctl.h
  head/usr.sbin/ctladm/ctladm.c

Modified: head/sys/cam/ctl/ctl.c
==============================================================================
--- head/sys/cam/ctl/ctl.c	Sat Jul  5 04:10:24 2014	(r268283)
+++ head/sys/cam/ctl/ctl.c	Sat Jul  5 05:44:26 2014	(r268284)
@@ -3138,6 +3138,104 @@ ctl_ioctl(struct cdev *dev, u_long cmd, 
 		retval = fe->ioctl(dev, cmd, addr, flag, td);
 		break;
 	}
+	case CTL_PORT_LIST: {
+		struct sbuf *sb;
+		struct ctl_port *port;
+		struct ctl_lun_list *list;
+//		struct ctl_option *opt;
+
+		list = (struct ctl_lun_list *)addr;
+
+		sb = sbuf_new(NULL, NULL, list->alloc_len, SBUF_FIXEDLEN);
+		if (sb == NULL) {
+			list->status = CTL_LUN_LIST_ERROR;
+			snprintf(list->error_str, sizeof(list->error_str),
+				 "Unable to allocate %d bytes for LUN list",
+				 list->alloc_len);
+			break;
+		}
+
+		sbuf_printf(sb, "<ctlportlist>\n");
+
+		mtx_lock(&softc->ctl_lock);
+		STAILQ_FOREACH(port, &softc->port_list, links) {
+			retval = sbuf_printf(sb, "<targ_port id=\"%ju\">\n",
+					     (uintmax_t)port->targ_port);
+
+			/*
+			 * Bail out as soon as we see that we've overfilled
+			 * the buffer.
+			 */
+			if (retval != 0)
+				break;
+
+			retval = sbuf_printf(sb, "\t<frontend_type>%s"
+			    "</frontend_type>\n", port->frontend->name);
+			if (retval != 0)
+				break;
+
+			retval = sbuf_printf(sb, "\t<port_type>%d</port_type>\n",
+					     port->port_type);
+			if (retval != 0)
+				break;
+
+			retval = sbuf_printf(sb, "\t<online>%s</online>\n",
+			    (port->status & CTL_PORT_STATUS_ONLINE) ? "YES" : "NO");
+			if (retval != 0)
+				break;
+
+			retval = sbuf_printf(sb, "\t<port_name>%s</port_name>\n",
+			    port->port_name);
+			if (retval != 0)
+				break;
+
+			retval = sbuf_printf(sb, "\t<physical_port>%d</physical_port>\n",
+			    port->physical_port);
+			if (retval != 0)
+				break;
+
+			retval = sbuf_printf(sb, "\t<virtual_port>%d</virtual_port>\n",
+			    port->virtual_port);
+			if (retval != 0)
+				break;
+
+			retval = sbuf_printf(sb, "\t<wwnn>%#jx</wwnn>\n",
+			    (uintmax_t)port->wwnn);
+			if (retval != 0)
+				break;
+
+			retval = sbuf_printf(sb, "\t<wwpn>%#jx</wwpn>\n",
+			    (uintmax_t)port->wwpn);
+			if (retval != 0)
+				break;
+
+			retval = sbuf_printf(sb, "</targ_port>\n");
+			if (retval != 0)
+				break;
+		}
+		mtx_unlock(&softc->ctl_lock);
+
+		if ((retval != 0)
+		 || ((retval = sbuf_printf(sb, "</ctlportlist>\n")) != 0)) {
+			retval = 0;
+			sbuf_delete(sb);
+			list->status = CTL_LUN_LIST_NEED_MORE_SPACE;
+			snprintf(list->error_str, sizeof(list->error_str),
+				 "Out of space, %d bytes is too small",
+				 list->alloc_len);
+			break;
+		}
+
+		sbuf_finish(sb);
+
+		retval = copyout(sbuf_data(sb), list->lun_xml,
+				 sbuf_len(sb) + 1);
+
+		list->fill_len = sbuf_len(sb) + 1;
+		list->status = CTL_LUN_LIST_OK;
+		sbuf_delete(sb);
+		break;
+	}
 	default: {
 		/* XXX KDM should we fix this? */
 #if 0

Modified: head/sys/cam/ctl/ctl_ioctl.h
==============================================================================
--- head/sys/cam/ctl/ctl_ioctl.h	Sat Jul  5 04:10:24 2014	(r268283)
+++ head/sys/cam/ctl/ctl_ioctl.h	Sat Jul  5 05:44:26 2014	(r268284)
@@ -789,6 +789,7 @@ struct ctl_iscsi {
 #define	CTL_ERROR_INJECT_DELETE	_IOW(CTL_MINOR, 0x23, struct ctl_error_desc)
 #define	CTL_SET_PORT_WWNS	_IOW(CTL_MINOR, 0x24, struct ctl_port_entry)
 #define	CTL_ISCSI		_IOWR(CTL_MINOR, 0x25, struct ctl_iscsi)
+#define	CTL_PORT_LIST		_IOWR(CTL_MINOR, 0x26, struct ctl_lun_list)
 
 #endif /* _CTL_IOCTL_H_ */
 

Modified: head/usr.sbin/ctladm/ctladm.c
==============================================================================
--- head/usr.sbin/ctladm/ctladm.c	Sat Jul  5 04:10:24 2014	(r268283)
+++ head/usr.sbin/ctladm/ctladm.c	Sat Jul  5 05:44:26 2014	(r268284)
@@ -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},
@@ -4073,6 +4075,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->pp = 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 +4369,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 +4385,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 +4695,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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201407050544.s655iQ79031856>