|
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 |
|