2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A
2N/A
2N/A#include "HBAPort.h"
2N/A#include "Exceptions.h"
2N/A#include "Trace.h"
2N/A#include <iostream>
2N/A#include <iomanip>
2N/A#include <cerrno>
2N/A#include <cstring>
2N/A#include <sys/types.h>
2N/A#include <sys/mkdev.h>
2N/A#include <sys/stat.h>
2N/A#include <fcntl.h>
2N/A#include <unistd.h>
2N/A#include <stropts.h>
2N/A#include <dirent.h>
2N/A#include <libdevinfo.h>
2N/A
2N/Ausing namespace std;
2N/A
2N/A/**
2N/A * Standard definition for general topology lookup (See T11 FC-FS)
2N/A */
2N/Aconst int HBAPort::RNID_GENERAL_TOPOLOGY_DATA_FORMAT = 0xDF;
2N/Aconst uint8_t HBAPort::HBA_NPIV_PORT_MAX = UCHAR_MAX;
2N/A
2N/A/**
2N/A * @memo Construct a new deafult HBA Port
2N/A */
2N/AHBAPort::HBAPort() {
2N/A}
2N/A
2N/A/**
2N/A * @memo Compare two HBA ports for equality
2N/A * @return TRUE if both ports are the same
2N/A * @return FALSE if the ports are different
2N/A *
2N/A * @doc Comparison is based on Node WWN, Port WWN and path
2N/A */
2N/Abool HBAPort::operator==(HBAPort &comp) {
2N/A return (this->getPortWWN() == comp.getPortWWN() &&
2N/A this->getNodeWWN() == comp.getNodeWWN() &&
2N/A this->getPath() == comp.getPath());
2N/A}
2N/A
2N/A/**
2N/A * @memo Validate that the port is still present in the system
2N/A * @exception UnavailableException if the port is not present
2N/A *
2N/A * @doc If the port is still present on the system, the routine
2N/A * will return normally. If the port is not present
2N/A * an exception will be thrown.
2N/A */
2N/Avoid HBAPort::validatePresent() {
2N/A Trace log("HBAPort::validatePresent");
2N/A string path = getPath();
2N/A struct stat sbuf;
2N/A if (stat(path.c_str(), &sbuf) == -1) {
2N/A if (errno == ENOENT) {
2N/A throw UnavailableException();
2N/A } else {
2N/A log.debug("Unable to stat %s: %s", path.c_str(),
2N/A strerror(errno));
2N/A throw InternalError();
2N/A }
2N/A }
2N/A}
2N/A
2N/A
2N/A/*
2N/A * structure for di_devlink_walk
2N/A */
2N/Atypedef struct walk_devlink {
2N/A char *path;
2N/A size_t len;
2N/A char **linkpp;
2N/A} walk_devlink_t;
2N/A
2N/A/**
2N/A * @memo callback funtion for di_devlink_walk
2N/A * @postcondition Find matching /dev link for the given path argument.
2N/A * @param devlink element and callback function argument.
2N/A *
2N/A * @doc The input path is expected to not have "/devices".
2N/A */
2N/Aextern "C" int
2N/Aget_devlink(di_devlink_t devlink, void *arg) {
2N/A Trace log("get_devlink");
2N/A walk_devlink_t *warg = (walk_devlink_t *)arg;
2N/A
2N/A /*
2N/A * When path is specified, it doesn't have minor
2N/A * name. Therefore, the ../.. prefixes needs to be stripped.
2N/A */
2N/A if (warg->path) {
2N/A // di_devlink_content contains /devices
2N/A char *content = (char *)di_devlink_content(devlink);
2N/A char *start = strstr(content, "/devices");
2N/A
2N/A if (start == NULL ||
2N/A strncmp(start, warg->path, warg->len) != 0 ||
2N/A // make it sure the device path has minor name
2N/A start[warg->len] != ':')
2N/A return (DI_WALK_CONTINUE);
2N/A }
2N/A
2N/A *(warg->linkpp) = strdup(di_devlink_path(devlink));
2N/A return (DI_WALK_TERMINATE);
2N/A}
2N/A
2N/A/**
2N/A * @memo Convert /devices paths to /dev sym-link paths.
2N/A * @postcondition The mapping buffer OSDeviceName paths will be
2N/A * converted to short names.
2N/A * @param mappings The target mappings data to convert to
2N/A * short names
2N/A *
2N/A * @doc If no link
2N/A * is found, the long path is left as is.
2N/A * Note: The NumberOfEntries field MUST not be greater than the size
2N/A * of the array passed in.
2N/A */
2N/Avoid HBAPort::convertToShortNames(PHBA_FCPTARGETMAPPINGV2 mappings) {
2N/A Trace log("HBAPort::convertToShortNames");
2N/A di_devlink_handle_t hdl;
2N/A walk_devlink_t warg;
2N/A char *minor_path, *devlinkp;
2N/A
2N/A if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
2N/A log.internalError("di_devlink_init failed. Errno:%d", errno);
2N/A // no need to check further, just return here.
2N/A return;
2N/A }
2N/A
2N/A for (int j = 0; j < mappings->NumberOfEntries; j++) {
2N/A if (strchr(mappings->entry[j].ScsiId.OSDeviceName, ':')) {
2N/A // search link for minor node
2N/A minor_path = mappings->entry[j].ScsiId.OSDeviceName;
2N/A if (strstr(minor_path, "/devices") != NULL) {
2N/A minor_path = mappings->entry[j].ScsiId.OSDeviceName +
2N/A strlen("/devices");
2N/A } else {
2N/A minor_path = mappings->entry[j].ScsiId.OSDeviceName;
2N/A }
2N/A warg.path = NULL;
2N/A } else {
2N/A minor_path = NULL;
2N/A if (strstr(mappings->entry[j].ScsiId.OSDeviceName,
2N/A "/devices") != NULL) {
2N/A warg.len = strlen (mappings->entry[j].ScsiId.OSDeviceName) -
2N/A strlen ("/devices");
2N/A warg.path = mappings->entry[j].ScsiId.OSDeviceName +
2N/A strlen ("/devices");
2N/A } else {
2N/A warg.len = strlen(mappings->entry[j].ScsiId.OSDeviceName);
2N/A warg.path = mappings->entry[j].ScsiId.OSDeviceName;
2N/A }
2N/A }
2N/A
2N/A devlinkp = NULL;
2N/A warg.linkpp = &devlinkp;
2N/A (void) di_devlink_walk(hdl, NULL, minor_path, DI_PRIMARY_LINK,
2N/A (void *)&warg, get_devlink);
2N/A
2N/A if (devlinkp != NULL) {
2N/A snprintf(mappings->entry[j].ScsiId.OSDeviceName,
2N/A sizeof (mappings->entry[j].ScsiId.OSDeviceName),
2N/A "%s", devlinkp);
2N/A free(devlinkp);
2N/A } // else leave OSDeviceName alone.
2N/A
2N/A }
2N/A
2N/A di_devlink_fini(&hdl);
2N/A
2N/A}
2N/A
2N/A/*
2N/A * Finds controller path for a give device path.
2N/A *
2N/A * Return vale: controller path.
2N/A */
2N/Astring HBAPort::lookupControllerPath(string path) {
2N/A Trace log("lookupControllerPath");
2N/A DIR *dp;
2N/A char buf[MAXPATHLEN];
2N/A char node[MAXPATHLEN];
2N/A struct dirent **dirpp, *dirp;
2N/A const char dir[] = "/dev/cfg";
2N/A ssize_t count;
2N/A uchar_t *dir_buf = new uchar_t[sizeof (struct dirent) + MAXPATHLEN];
2N/A
2N/A if ((dp = opendir(dir)) == NULL) {
2N/A string tmp = "Unable to open ";
2N/A tmp += dir;
2N/A tmp += "to find controller number.";
2N/A delete (dir_buf);
2N/A throw IOError(tmp);
2N/A }
2N/A
2N/A dirp = (struct dirent *) dir_buf;
2N/A dirpp = &dirp;
2N/A while ((readdir_r(dp, dirp, dirpp)) == 0 && dirp != NULL) {
2N/A if (strcmp(dirp->d_name, ".") == 0 ||
2N/A strcmp(dirp->d_name, "..") == 0) {
2N/A continue;
2N/A }
2N/A sprintf(node, "%s/%s", dir, dirp->d_name);
2N/A if ((count = readlink(node,buf,sizeof(buf)))) {
2N/A buf[count] = '\0';
2N/A if (strstr(buf, path.c_str())) {
2N/A string cfg_path = dir;
2N/A cfg_path += "/";
2N/A cfg_path += dirp->d_name;
2N/A closedir(dp);
2N/A delete (dir_buf);
2N/A return (cfg_path);
2N/A }
2N/A }
2N/A }
2N/A
2N/A closedir(dp);
2N/A delete (dir_buf);
2N/A throw InternalError("Unable to find controller path");
2N/A}
2N/A
2N/Avoid HBAPort::addPort(HBANPIVPort *port) {
2N/A Trace log("HBAPort::addPort");
2N/A lock();
2N/A // support hba with up to UCHAR_MAX number of ports.
2N/A if (npivportsByIndex.size() + 1 > HBA_NPIV_PORT_MAX) {
2N/A unlock();
2N/A throw InternalError("HBA NPIV Port count exceeds max number of ports");
2N/A }
2N/A
2N/A try {
2N/A npivportsByWWN[port->getPortWWN()] = port;
2N/A npivportsByIndex.insert(npivportsByIndex.end(), port);
2N/A unlock();
2N/A } catch (...) {
2N/A unlock();
2N/A throw;
2N/A }
2N/A}
2N/A
2N/AHBANPIVPort* HBAPort::getPort(uint64_t wwn) {
2N/A Trace log("HBAPort::getPort");
2N/A HBANPIVPort *port = NULL;
2N/A
2N/A lock();
2N/A try {
2N/A if (npivportsByWWN.find(wwn) == npivportsByWWN.end()) {
2N/A throw IllegalWWNException();
2N/A }
2N/A port = npivportsByWWN[wwn];
2N/A unlock();
2N/A return (port);
2N/A } catch (...) {
2N/A unlock();
2N/A throw;
2N/A }
2N/A}
2N/A
2N/AHBANPIVPort* HBAPort::getPortByIndex(int index) {
2N/A Trace log("HBAPort::getPortByIndex");
2N/A lock();
2N/A try {
2N/A if (index >= npivportsByIndex.size() || index < 0) {
2N/A throw IllegalIndexException();
2N/A }
2N/A HBANPIVPort *tmp = npivportsByIndex[index];
2N/A unlock();
2N/A return (tmp);
2N/A } catch (...) {
2N/A unlock();
2N/A throw;
2N/A }
2N/A}
2N/A