#include "HBA.h"
#include "Exceptions.h"
#include "Trace.h"
#include <iostream>
#include <iomanip>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <stropts.h>
#include <errno.h>
#include <climits>
#include <cstring>
#define NSECS_PER_SEC 1000000000l
#define BUSY_SLEEP NSECS_PER_SEC/10
#define BUSY_RETRY_TIMER 3000000000UL
using namespace std;
const uint8_t HBA::HBA_PORT_MAX = UCHAR_MAX;
void HBA::addPort(HBAPort* port) {
Trace log("HBA::addPort");
lock();
if (portsByIndex.size() + 1 > HBA_PORT_MAX) {
unlock();
throw InternalError("HBA Port count exceeds max number of ports");
}
try {
portsByWWN[port->getPortWWN()] = port;
portsByIndex.insert(portsByIndex.end(), port);
unlock();
} catch (...) {
unlock();
throw;
}
}
uint8_t HBA::getNumberOfPorts() {
Trace log("HBA::getNumberOfPorts");
return (uint8_t)portsByIndex.size();
}
HBAPort* HBA::getPort(uint64_t wwn) {
Trace log("HBA::getPort");
HBAPort *port = NULL;
lock();
log.debug("getPort(wwn): WWN %016llx", wwn);
try {
if (portsByWWN.find(wwn) == portsByWWN.end()) {
throw IllegalWWNException();
}
port = portsByWWN[wwn];
unlock();
return (port);
} catch (...) {
unlock();
throw;
}
}
typedef map<uint64_t, HBAPort *>::const_iterator CI;
bool HBA::containsWWN(uint64_t wwn) {
Trace log("HBA::containsWWN");
lock();
try {
for (CI port = portsByWWN.begin(); port != portsByWWN.end();
port++) {
if (port->second->getPortWWN() == wwn) {
unlock();
return (true);
}
if (port->second->getNodeWWN() == wwn) {
unlock();
return (true);
}
}
unlock();
return (false);
} catch (...) {
unlock();
throw;
}
}
HBAPort* HBA::getPortByIndex(int index) {
Trace log("HBA::getPortByIndex");
lock();
try {
log.debug("Port index size %d index %d ", portsByIndex.size(),
index);
if (index >= portsByIndex.size() || index < 0) {
throw IllegalIndexException();
}
HBAPort *tmp = portsByIndex[index];
unlock();
return (tmp);
} catch (...) {
unlock();
throw;
}
}
bool HBA::operator==(HBA &comp) {
Trace log("HBA::operator==");
lock();
try {
bool ret = false;
if (portsByIndex.size() == comp.portsByIndex.size()) {
if (portsByIndex.size() > 0) {
ret = (*portsByIndex[0] == *comp.portsByIndex[0]);
}
}
unlock();
return (ret);
} catch (...) {
unlock();
throw;
}
}
void HBA::setRNID(HBA_MGMTINFO info) {
Trace log("HBA::setRNID");
lock();
try {
for (CI port = portsByWWN.begin(); port != portsByWWN.end();
port++) {
port->second->setRNID(info);
}
unlock();
} catch (...) {
unlock();
throw;
}
}
void HBA::validatePresent() {
Trace log("HBA::validatePresent");
lock();
try {
for (CI port = portsByWWN.begin(); port != portsByWWN.end();
port++) {
port->second->validatePresent();
}
unlock();
} catch (...) {
unlock();
throw;
}
}
int HBA::_open(std::string path, int flag) {
Trace log("HBA::open");
int fd;
errno = 0;
if ((fd = open(path.c_str(), flag)) < 0) {
log.debug("Unable to open \"%s\" - reason (%d) %s",
path.c_str(), errno, strerror(errno));
if (errno == EBUSY) {
throw BusyException();
} else if (errno == EAGAIN) {
throw TryAgainException();
} else if (errno == ENOTSUP) {
throw NotSupportedException();
} else if (errno == ENOENT) {
throw UnavailableException();
} else {
string msg = "Unable to open ";
msg += path;
throw IOError(msg);
}
}
return (fd);
}
void HBA::_ioctl(int fd, int type, uchar_t *arg) {
Trace log("HBA::ioctl");
hrtime_t cur;
int saved_errno = 0;
struct timespec ts;
hrtime_t start = gethrtime();
hrtime_t end = start + BUSY_RETRY_TIMER;
ts.tv_sec = 0;
ts.tv_nsec = BUSY_SLEEP;
for (cur = start; cur < end; cur = gethrtime()) {
errno = 0;
if (ioctl(fd, type, arg) != 0) {
if (errno == EAGAIN) {
saved_errno = errno;
nanosleep(&ts, NULL);
continue;
} else if (errno == EBUSY) {
saved_errno = errno;
nanosleep(&ts, NULL);
continue;
} else if (errno == ENOTSUP) {
throw NotSupportedException();
} else if (errno == ENOENT) {
throw UnavailableException();
} else {
throw IOError("IOCTL failed");
}
} else {
break;
}
}
if (cur >= end) {
if (saved_errno == EAGAIN) {
throw TryAgainException();
} else if (saved_errno == EBUSY) {
throw BusyException();
} else {
throw IOError("IOCTL failed");
}
}
}
HBA::~HBA() {
Trace log("HBA::~HBA");
for (int i = 0; i < getNumberOfPorts(); i++) {
delete (getPortByIndex(i));
}
}