Blame rport.c

Packit 2e24a8
/*
Packit 2e24a8
 * Copyright (c) 2008, Intel Corporation.
Packit 2e24a8
 *
Packit 2e24a8
 * This program is free software; you can redistribute it and/or modify it
Packit 2e24a8
 * under the terms and conditions of the GNU Lesser General Public License,
Packit 2e24a8
 * version 2.1, as published by the Free Software Foundation.
Packit 2e24a8
 *
Packit 2e24a8
 * This program is distributed in the hope it will be useful, but WITHOUT
Packit 2e24a8
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit 2e24a8
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
Packit 2e24a8
 * for more details.
Packit 2e24a8
 *
Packit 2e24a8
 * You should have received a copy of the GNU Lesser General Public License
Packit 2e24a8
 * along with this program; if not, write to the Free Software Foundation, Inc.,
Packit 2e24a8
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
Packit 2e24a8
 *
Packit 2e24a8
 */
Packit 2e24a8
Packit 2e24a8
#include "utils.h"
Packit 2e24a8
#include "api_lib.h"
Packit 2e24a8
#include "adapt_impl.h"
Packit 2e24a8
Packit 2e24a8
static int sys_read_port_state(const char *, const char *, u_int32_t *);
Packit 2e24a8
static int sys_read_classes(const char *, const char *, u_int32_t *);
Packit 2e24a8
Packit 2e24a8
static struct sa_table rports_table;          /* table of discovered ports */
Packit 2e24a8
Packit 2e24a8
/*
Packit 2e24a8
 * Handle a single remote port from the /sys directory entry.
Packit 2e24a8
 * The return value is 0 unless an error is detected which should stop the
Packit 2e24a8
 * directory read.
Packit 2e24a8
 */
Packit 2e24a8
static int
Packit 2e24a8
sysfs_get_rport(struct dirent *dp, void *arg)
Packit 2e24a8
{
Packit 2e24a8
	struct port_info *rp;
Packit 2e24a8
	HBA_PORTATTRIBUTES *rpa;
Packit 2e24a8
	int rc;
Packit 2e24a8
	u_int32_t hba;
Packit 2e24a8
	u_int32_t port;
Packit 2e24a8
	u_int32_t rp_index;
Packit 2e24a8
	char *rport_dir;
Packit 2e24a8
	char buf[256];
Packit 2e24a8
Packit 2e24a8
	/*
Packit 2e24a8
	 * Parse name into bus number, channel number, and remote port number.
Packit 2e24a8
	 */
Packit 2e24a8
	hba = ~0;
Packit 2e24a8
	port = ~0;
Packit 2e24a8
	rp_index = ~0;
Packit 2e24a8
	rc = sscanf(dp->d_name, SYSFS_RPORT_DIR, &hba, &port, &rp_index);
Packit 2e24a8
	if (rc != 3) {
Packit 2e24a8
		fprintf(stderr,
Packit 2e24a8
			"%s: remote port %s didn't parse."
Packit 2e24a8
			" rc %d h 0x%x p 0x%x rp 0x%x\n", __func__,
Packit 2e24a8
			dp->d_name, rc, hba, port, rp_index);
Packit 2e24a8
		return 0;
Packit 2e24a8
	}
Packit 2e24a8
Packit 2e24a8
	/*
Packit 2e24a8
	 * Allocate a remote port.
Packit 2e24a8
	 */
Packit 2e24a8
	rp = malloc(sizeof(*rp));
Packit 2e24a8
	if (rp == NULL) {
Packit 2e24a8
		fprintf(stderr, "%s: malloc for remote port %s failed,"
Packit 2e24a8
			" errno=0x%x\n", __func__, dp->d_name, errno);
Packit 2e24a8
		return ENOMEM;
Packit 2e24a8
	}
Packit 2e24a8
	memset(rp, 0, sizeof(*rp));
Packit 2e24a8
	rp->ap_kern_hba = hba;
Packit 2e24a8
	rp->ap_index = port;
Packit 2e24a8
	rp->ap_disc_index = rp_index;
Packit 2e24a8
	rpa = &rp->ap_attr;
Packit 2e24a8
Packit 2e24a8
	snprintf(rpa->OSDeviceName, sizeof(rpa->OSDeviceName), "%s/%s",
Packit 2e24a8
		SYSFS_RPORT_ROOT, dp->d_name);
Packit 2e24a8
	rport_dir = rpa->OSDeviceName;
Packit 2e24a8
	rc = 0;
Packit 2e24a8
	rc |= sys_read_wwn(rport_dir, "node_name", &rpa->NodeWWN);
Packit 2e24a8
	rc |= sys_read_wwn(rport_dir, "port_name", &rpa->PortWWN);
Packit 2e24a8
	rc |= sa_sys_read_u32(rport_dir, "port_id", &rpa->PortFcId);
Packit 2e24a8
	rc |= sa_sys_read_u32(rport_dir, "scsi_target_id", &rp->ap_scsi_target);
Packit 2e24a8
	sa_sys_read_line(rport_dir, "maxframe_size", buf, sizeof(buf));
Packit 2e24a8
	sscanf(buf, "%d", &rpa->PortMaxFrameSize);
Packit 2e24a8
	rc |= sys_read_port_state(rport_dir, "port_state", &rpa->PortState);
Packit 2e24a8
	rc |= sys_read_classes(rport_dir, "supported_classes",
Packit 2e24a8
				   &rpa->PortSupportedClassofService);
Packit 2e24a8
	if (rc != 0 || sa_table_append(&rports_table, rp) < 0) {
Packit 2e24a8
		if (rc != 0)
Packit 2e24a8
			fprintf(stderr,
Packit 2e24a8
				"%s: errors (%x) from /sys reads in %s\n",
Packit 2e24a8
				__func__, rc, dp->d_name);
Packit 2e24a8
		else
Packit 2e24a8
			fprintf(stderr,
Packit 2e24a8
				"%s: sa_table_append error on rport %s\n",
Packit 2e24a8
				__func__, dp->d_name);
Packit 2e24a8
		free(rp);
Packit 2e24a8
	}
Packit 2e24a8
	return 0;
Packit 2e24a8
}
Packit 2e24a8
Packit 2e24a8
/*
Packit 2e24a8
 * Get remote port information from /sys.
Packit 2e24a8
 */
Packit 2e24a8
static void
Packit 2e24a8
sysfs_find_rports(void)
Packit 2e24a8
{
Packit 2e24a8
	sa_dir_read(SYSFS_RPORT_ROOT, sysfs_get_rport, NULL);
Packit 2e24a8
}
Packit 2e24a8
Packit 2e24a8
/*
Packit 2e24a8
 * Read port state as formatted by scsi_transport_fc.c in the linux kernel.
Packit 2e24a8
 */
Packit 2e24a8
static int
Packit 2e24a8
sys_read_port_state(const char *dir, const char *file, u_int32_t *statep)
Packit 2e24a8
{
Packit 2e24a8
	char buf[256];
Packit 2e24a8
	int rc;
Packit 2e24a8
Packit 2e24a8
	rc = sa_sys_read_line(dir, file, buf, sizeof(buf));
Packit 2e24a8
	if (rc == 0) {
Packit 2e24a8
		rc = sa_enum_encode(port_states_table, buf, statep);
Packit 2e24a8
		if (rc != 0)
Packit 2e24a8
			fprintf(stderr,
Packit 2e24a8
				"%s: parse error. file %s/%s line '%s'\n",
Packit 2e24a8
				__func__, dir, file, buf);
Packit 2e24a8
	}
Packit 2e24a8
	return rc;
Packit 2e24a8
}
Packit 2e24a8
Packit 2e24a8
/*
Packit 2e24a8
 * Read class list as formatted by scsi_transport_fc.c in the linux kernel.
Packit 2e24a8
 * Format is expected to be "Class 3[, Class 4]..."
Packit 2e24a8
 * Actually accepts "[Class ]3[,[ ][Class ]4]..." (i.e., "Class" and spaces
Packit 2e24a8
 * are optional).
Packit 2e24a8
 */
Packit 2e24a8
static int
Packit 2e24a8
sys_read_classes(const char *dir, const char *file, u_int32_t *classp)
Packit 2e24a8
{
Packit 2e24a8
	char buf[256];
Packit 2e24a8
	int rc;
Packit 2e24a8
	u_int32_t val;
Packit 2e24a8
	char *cp;
Packit 2e24a8
	char *ep;
Packit 2e24a8
Packit 2e24a8
	*classp = 0;
Packit 2e24a8
	rc = sa_sys_read_line(dir, file, buf, sizeof(buf));
Packit 2e24a8
	if (rc == 0 && strstr(buf, "unspecified") == NULL) {
Packit 2e24a8
		for (cp = buf; *cp != '\0'; cp = ep) {
Packit 2e24a8
			if (strncmp(cp, "Class ", 6) == 0)
Packit 2e24a8
				cp += 6;
Packit 2e24a8
			val = strtoul(cp, &ep, 10);
Packit 2e24a8
			*classp |= 1 << val;
Packit 2e24a8
			if (*ep == '\0')
Packit 2e24a8
				break;
Packit 2e24a8
			if (*ep == ',') {
Packit 2e24a8
				ep++;
Packit 2e24a8
				if (*ep == ' ')
Packit 2e24a8
					ep++;
Packit 2e24a8
			} else {
Packit 2e24a8
				fprintf(stderr, "%s: parse error. file %s/%s "
Packit 2e24a8
				       "line '%s' ep '%c'\n", __func__,
Packit 2e24a8
					dir, file, buf, *ep);
Packit 2e24a8
				rc = -1;
Packit 2e24a8
				break;
Packit 2e24a8
			}
Packit 2e24a8
		}
Packit 2e24a8
	}
Packit 2e24a8
	return rc;
Packit 2e24a8
}
Packit 2e24a8
Packit 2e24a8
/*
Packit 2e24a8
 * Get all discovered ports for a particular port using /sys.
Packit 2e24a8
 */
Packit 2e24a8
void
Packit 2e24a8
get_rport_info(struct port_info *pp)
Packit 2e24a8
{
Packit 2e24a8
	struct port_info *rp;
Packit 2e24a8
	int rp_count = 0;
Packit 2e24a8
	int ri;
Packit 2e24a8
Packit 2e24a8
	if (rports_table.st_size == 0)
Packit 2e24a8
		sysfs_find_rports();
Packit 2e24a8
Packit 2e24a8
	for (ri = 0; ri < rports_table.st_size; ri++) {
Packit 2e24a8
		rp = sa_table_lookup(&rports_table, ri);
Packit 2e24a8
		if (rp != NULL) {
Packit 2e24a8
			if (rp->ap_kern_hba == pp->ap_kern_hba &&
Packit 2e24a8
			    rp->ap_index == pp->ap_index &&
Packit 2e24a8
			    rp->ap_adapt == NULL) {
Packit 2e24a8
				rp->ap_adapt = pp->ap_adapt;
Packit 2e24a8
				if (sa_table_lookup(&pp->ap_rports,
Packit 2e24a8
						    rp->ap_disc_index)) {
Packit 2e24a8
					fprintf(stderr,
Packit 2e24a8
						"%s: discovered port exists. "
Packit 2e24a8
					       "hba %x port %x rport %x\n",
Packit 2e24a8
					       __func__, pp->ap_kern_hba,
Packit 2e24a8
					       pp->ap_index, rp->ap_disc_index);
Packit 2e24a8
				}
Packit 2e24a8
				sa_table_insert(&pp->ap_rports,
Packit 2e24a8
						rp->ap_disc_index, rp);
Packit 2e24a8
			}
Packit 2e24a8
			rp_count++;
Packit 2e24a8
		}
Packit 2e24a8
	}
Packit 2e24a8
}
Packit 2e24a8