Improve and document ctladm portlist subcommand.

Make this subcommand less FC-specific, reporting target and port addresses
in more generic way.  Also make it report list of connected initiators in
unified way, working for both FC and iSCSI, and potentially others.

MFC after:	1 week
This commit is contained in:
Alexander Motin 2014-10-12 06:55:34 +00:00
parent 2869fca8b0
commit 555e99a3bf
3 changed files with 144 additions and 28 deletions

View File

@ -2237,6 +2237,43 @@ ctl_sbuf_printf_esc(struct sbuf *sb, char *str)
return (retval);
}
static void
ctl_id_sbuf(struct ctl_devid *id, struct sbuf *sb)
{
struct scsi_vpd_id_descriptor *desc;
int i;
if (id == NULL || id->len < 4)
return;
desc = (struct scsi_vpd_id_descriptor *)id->data;
switch (desc->id_type & SVPD_ID_TYPE_MASK) {
case SVPD_ID_TYPE_T10:
sbuf_printf(sb, "t10.");
break;
case SVPD_ID_TYPE_EUI64:
sbuf_printf(sb, "eui.");
break;
case SVPD_ID_TYPE_NAA:
sbuf_printf(sb, "naa.");
break;
case SVPD_ID_TYPE_SCSI_NAME:
break;
}
switch (desc->proto_codeset & SVPD_ID_CODESET_MASK) {
case SVPD_ID_CODESET_BINARY:
for (i = 0; i < desc->length; i++)
sbuf_printf(sb, "%02x", desc->identifier[i]);
break;
case SVPD_ID_CODESET_ASCII:
sbuf_printf(sb, "%.*s", (int)desc->length,
(char *)desc->identifier);
break;
case SVPD_ID_CODESET_UTF8:
sbuf_printf(sb, "%s", (char *)desc->identifier);
break;
}
}
static int
ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
struct thread *td)
@ -3288,6 +3325,7 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
struct ctl_port *port;
struct ctl_lun_list *list;
struct ctl_option *opt;
int j;
list = (struct ctl_lun_list *)addr;
@ -3344,15 +3382,17 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
if (retval != 0)
break;
retval = sbuf_printf(sb, "\t<wwnn>%#jx</wwnn>\n",
(uintmax_t)port->wwnn);
if (retval != 0)
break;
if (port->target_devid != NULL) {
sbuf_printf(sb, "\t<target>");
ctl_id_sbuf(port->target_devid, sb);
sbuf_printf(sb, "</target>\n");
}
retval = sbuf_printf(sb, "\t<wwpn>%#jx</wwpn>\n",
(uintmax_t)port->wwpn);
if (retval != 0)
break;
if (port->port_devid != NULL) {
sbuf_printf(sb, "\t<port>");
ctl_id_sbuf(port->port_devid, sb);
sbuf_printf(sb, "</port>\n");
}
if (port->port_info != NULL) {
retval = port->port_info(port->onoff_arg, sb);
@ -3366,6 +3406,26 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
break;
}
for (j = 0; j < CTL_MAX_INIT_PER_PORT; j++) {
if (port->wwpn_iid[j].in_use == 0 ||
(port->wwpn_iid[j].wwpn == 0 &&
port->wwpn_iid[j].name == NULL))
continue;
if (port->wwpn_iid[j].name != NULL)
retval = sbuf_printf(sb,
"\t<initiator>%u %s</initiator>\n",
j, port->wwpn_iid[j].name);
else
retval = sbuf_printf(sb,
"\t<initiator>%u naa.%08jx</initiator>\n",
j, port->wwpn_iid[j].wwpn);
if (retval != 0)
break;
}
if (retval != 0)
break;
retval = sbuf_printf(sb, "</targ_port>\n");
if (retval != 0)
break;

View File

@ -34,7 +34,7 @@
.\" $Id: //depot/users/kenm/FreeBSD-test2/usr.sbin/ctladm/ctladm.8#3 $
.\" $FreeBSD$
.\"
.Dd October 8, 2014
.Dd October 12, 2014
.Dt CTLADM 8
.Os
.Sh NAME
@ -193,6 +193,14 @@
.Op Fl q
.Op Fl x
.Nm
.Ic portlist
.Op Fl f Ar frontend
.Op Fl i
.Op Fl p Ar targ_port
.Op Fl q
.Op Fl v
.Op Fl x
.Nm
.Ic dumpooa
.Nm
.Ic dumpstructs
@ -768,6 +776,22 @@ As a general rule, the WWPN must be different for every port in the system.
.It Fl x
Output the port list in XML format.
.El
.It Ic portlist
List CTL frontend ports.
.Bl -tag -width 12n
.It Fl f Ar frontend
Specify the frontend type.
.It Fl i
Report target and connected initiators addresses
.It Fl p Ar targ_port
Specify the frontend port number.
.It Fl q
Omit the header in the port list output.
.It Fl v
Enable verbose output (report all port options).
.It Fl x
Output the port list in XML format.
.El
.It Ic dumpooa
Dump the OOA (Order Of Arrival) queue for each LUN registered with CTL.
.It Ic dumpstructs

View File

@ -191,7 +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"},
{"portlist", CTLADM_CMD_PORTLIST, CTLADM_ARG_NONE, "f:ip:qvx"},
{"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},
@ -4100,7 +4100,8 @@ struct cctl_port {
char *frontend_type;
char *name;
int pp, vp;
char *wwnn, *wwpn;
char *target, *port;
STAILQ_HEAD(,cctl_lun_nv) init_list;
STAILQ_HEAD(,cctl_lun_nv) attr_list;
STAILQ_ENTRY(cctl_port) links;
};
@ -4144,6 +4145,7 @@ cctl_start_pelement(void *user_data, const char *name, const char **attr)
portlist->num_ports++;
portlist->cur_port = cur_port;
STAILQ_INIT(&cur_port->init_list);
STAILQ_INIT(&cur_port->attr_list);
STAILQ_INSERT_TAIL(&portlist->port_list, cur_port, links);
@ -4205,11 +4207,11 @@ cctl_end_pelement(void *user_data, const char *name)
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;
} else if (strcmp(name, "target") == 0) {
cur_port->target = str;
str = NULL;
} else if (strcmp(name, "wwpn") == 0) {
cur_port->wwpn = str;
} else if (strcmp(name, "port") == 0) {
cur_port->port = str;
str = NULL;
} else if (strcmp(name, "targ_port") == 0) {
portlist->cur_port = NULL;
@ -4230,7 +4232,10 @@ cctl_end_pelement(void *user_data, const char *name)
nv->value = str;
str = NULL;
STAILQ_INSERT_TAIL(&cur_port->attr_list, nv, links);
if (strcmp(name, "initiator") == 0)
STAILQ_INSERT_TAIL(&cur_port->init_list, nv, links);
else
STAILQ_INSERT_TAIL(&cur_port->attr_list, nv, links);
}
free(str);
@ -4258,7 +4263,8 @@ cctl_portlist(int fd, int argc, char **argv, char *combinedopt)
int dump_xml = 0;
int retval, c;
char *frontend = NULL;
int verbose = 0;
uint64_t portarg = UINT64_MAX;
int verbose = 0, init = 0, quiet = 0;
retval = 0;
port_len = 4096;
@ -4271,6 +4277,15 @@ cctl_portlist(int fd, int argc, char **argv, char *combinedopt)
case 'f':
frontend = strdup(optarg);
break;
case 'i':
init++;
break;
case 'p':
portarg = strtoll(optarg, NULL, 0);
break;
case 'q':
quiet++;
break;
case 'v':
verbose++;
break;
@ -4327,8 +4342,8 @@ cctl_portlist(int fd, int argc, char **argv, char *combinedopt)
goto bailout;
}
printf("Port Online Frontend %-12s pp vp %-18s %-18s\n",
"Name", "WWNN", "WWPN");
if (quiet == 0)
printf("Port Online Frontend Name pp vp\n");
STAILQ_FOREACH(port, &portlist.port_list, links) {
struct cctl_lun_nv *nv;
@ -4336,16 +4351,26 @@ cctl_portlist(int fd, int argc, char **argv, char *combinedopt)
&& (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)
if ((portarg != UINT64_MAX) && (portarg != port->port_id))
continue;
STAILQ_FOREACH(nv, &port->attr_list, links) {
printf(" %s=%s\n", nv->name, nv->value);
printf("%-4ju %-6s %-8s %-8s %-2d %-2d %s\n",
(uintmax_t)port->port_id, port->online,
port->frontend_type, port->name, port->pp, port->vp,
port->port ? port->port : "");
if (init || verbose) {
if (port->target)
printf(" Target: %s\n", port->target);
STAILQ_FOREACH(nv, &port->init_list, links) {
printf(" Initiator: %s\n", nv->value);
}
}
if (verbose) {
STAILQ_FOREACH(nv, &port->attr_list, links) {
printf(" %s=%s\n", nv->name, nv->value);
}
}
}
bailout:
@ -4401,7 +4426,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 portlist [-f frontend] [-i] [-p targ_port] [-q] [-v] [-x]\n"
" ctladm islist [-v | -x]\n"
" ctladm islogout <-a | -c connection-id | -i name | -p portal>\n"
" ctladm isterminate <-a | -c connection-id | -i name | -p portal>\n"
@ -4487,6 +4512,13 @@ usage(int error)
"-p targ_port : specify target port number\n"
"-q : omit header in list output\n"
"-x : output port list in XML format\n"
"portlist options:\n"
"-f fronetnd : specify frontend type\n"
"-i : report target and initiators addresses\n"
"-p targ_port : specify target port number\n"
"-q : omit header in list output\n"
"-v : verbose output (report all port options)\n"
"-x : output port list in XML format\n"
"bbrread options:\n"
"-l lba : starting LBA\n"
"-d datalen : length, in bytes, to read\n",