#include "HBAPort.h"
#include "Exceptions.h"
#include "Trace.h"
#include <iostream>
#include <iomanip>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/mkdev.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stropts.h>
#include <dirent.h>
#include <libdevinfo.h>
using namespace std;
const int HBAPort::RNID_GENERAL_TOPOLOGY_DATA_FORMAT = 0xDF;
const uint8_t HBAPort::HBA_NPIV_PORT_MAX = UCHAR_MAX;
HBAPort::HBAPort() {
}
bool HBAPort::operator==(HBAPort &comp) {
return (this->getPortWWN() == comp.getPortWWN() &&
this->getNodeWWN() == comp.getNodeWWN() &&
this->getPath() == comp.getPath());
}
void HBAPort::validatePresent() {
Trace log("HBAPort::validatePresent");
string path = getPath();
struct stat sbuf;
if (stat(path.c_str(), &sbuf) == -1) {
if (errno == ENOENT) {
throw UnavailableException();
} else {
log.debug("Unable to stat %s: %s", path.c_str(),
strerror(errno));
throw InternalError();
}
}
}
typedef struct walk_devlink {
char *path;
size_t len;
char **linkpp;
} walk_devlink_t;
extern "C" int
get_devlink(di_devlink_t devlink, void *arg) {
Trace log("get_devlink");
walk_devlink_t *warg = (walk_devlink_t *)arg;
if (warg->path) {
char *content = (char *)di_devlink_content(devlink);
char *start = strstr(content, "/devices");
if (start == NULL ||
strncmp(start, warg->path, warg->len) != 0 ||
start[warg->len] != ':')
return (DI_WALK_CONTINUE);
}
*(warg->linkpp) = strdup(di_devlink_path(devlink));
return (DI_WALK_TERMINATE);
}
void HBAPort::convertToShortNames(PHBA_FCPTARGETMAPPINGV2 mappings) {
Trace log("HBAPort::convertToShortNames");
di_devlink_handle_t hdl;
walk_devlink_t warg;
char *minor_path, *devlinkp;
if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
log.internalError("di_devlink_init failed. Errno:%d", errno);
return;
}
for (int j = 0; j < mappings->NumberOfEntries; j++) {
if (strchr(mappings->entry[j].ScsiId.OSDeviceName, ':')) {
minor_path = mappings->entry[j].ScsiId.OSDeviceName;
if (strstr(minor_path, "/devices") != NULL) {
minor_path = mappings->entry[j].ScsiId.OSDeviceName +
strlen("/devices");
} else {
minor_path = mappings->entry[j].ScsiId.OSDeviceName;
}
warg.path = NULL;
} else {
minor_path = NULL;
if (strstr(mappings->entry[j].ScsiId.OSDeviceName,
"/devices") != NULL) {
warg.len = strlen (mappings->entry[j].ScsiId.OSDeviceName) -
strlen ("/devices");
warg.path = mappings->entry[j].ScsiId.OSDeviceName +
strlen ("/devices");
} else {
warg.len = strlen(mappings->entry[j].ScsiId.OSDeviceName);
warg.path = mappings->entry[j].ScsiId.OSDeviceName;
}
}
devlinkp = NULL;
warg.linkpp = &devlinkp;
(void) di_devlink_walk(hdl, NULL, minor_path, DI_PRIMARY_LINK,
(void *)&warg, get_devlink);
if (devlinkp != NULL) {
snprintf(mappings->entry[j].ScsiId.OSDeviceName,
sizeof (mappings->entry[j].ScsiId.OSDeviceName),
"%s", devlinkp);
free(devlinkp);
}
}
di_devlink_fini(&hdl);
}
string HBAPort::lookupControllerPath(string path) {
Trace log("lookupControllerPath");
DIR *dp;
char buf[MAXPATHLEN];
char node[MAXPATHLEN];
struct dirent **dirpp, *dirp;
const char dir[] = "/dev/cfg";
ssize_t count;
uchar_t *dir_buf = new uchar_t[sizeof (struct dirent) + MAXPATHLEN];
if ((dp = opendir(dir)) == NULL) {
string tmp = "Unable to open ";
tmp += dir;
tmp += "to find controller number.";
delete[] (dir_buf);
throw IOError(tmp);
}
dirp = (struct dirent *) dir_buf;
dirpp = &dirp;
while ((readdir_r(dp, dirp, dirpp)) == 0 && dirp != NULL) {
if (strcmp(dirp->d_name, ".") == 0 ||
strcmp(dirp->d_name, "..") == 0) {
continue;
}
sprintf(node, "%s/%s", dir, dirp->d_name);
if ((count = readlink(node,buf,sizeof(buf)))) {
buf[count] = '\0';
if (strstr(buf, path.c_str())) {
string cfg_path = dir;
cfg_path += "/";
cfg_path += dirp->d_name;
closedir(dp);
delete[] (dir_buf);
return (cfg_path);
}
}
}
closedir(dp);
delete[] (dir_buf);
throw InternalError("Unable to find controller path");
}
void HBAPort::addPort(HBANPIVPort *port) {
Trace log("HBAPort::addPort");
lock();
if (npivportsByIndex.size() + 1 > HBA_NPIV_PORT_MAX) {
unlock();
throw InternalError("HBA NPIV Port count exceeds max number of ports");
}
try {
npivportsByWWN[port->getPortWWN()] = port;
npivportsByIndex.insert(npivportsByIndex.end(), port);
unlock();
} catch (...) {
unlock();
throw;
}
}
HBANPIVPort* HBAPort::getPort(uint64_t wwn) {
Trace log("HBAPort::getPort");
HBANPIVPort *port = NULL;
lock();
try {
if (npivportsByWWN.find(wwn) == npivportsByWWN.end()) {
throw IllegalWWNException();
}
port = npivportsByWWN[wwn];
unlock();
return (port);
} catch (...) {
unlock();
throw;
}
}
HBANPIVPort* HBAPort::getPortByIndex(int index) {
Trace log("HBAPort::getPortByIndex");
lock();
try {
if (index >= npivportsByIndex.size() || index < 0) {
throw IllegalIndexException();
}
HBANPIVPort *tmp = npivportsByIndex[index];
unlock();
return (tmp);
} catch (...) {
unlock();
throw;
}
}