OpenSolaris_b135/lib/sun_fc/common/HandlePort.cc

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */



#include "HandlePort.h"
#include "Exceptions.h"
#include "Trace.h"
#include <iostream>
#include <iomanip>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stropts.h>


using namespace std;

/**
 * @memo	    Construct a new HandlePort for state tracking
 * @precondition    Handle must be open
 * @param	    myHandle The open handle for this HBA
 * @param	    myHBA The HBA for this port
 * @param	    myPort The HBA Port to open
 */
HandlePort::HandlePort(Handle *myHandle, HBA *myHBA, HBAPort *myPort) :
	handle(myHandle), hba(myHBA), port(myPort), active(false) {
	Trace log("HandlePort::HandlePort");
}

/**
 * @memo	    Reset the state tracking values for stale index detection
 * @postcondition   The first subsequent call to any index based routine
 *		    will always succed. 
 */
void HandlePort::refresh() {
	Trace log("HandlePort::refresh");
	lock();
	active = false;
	unlock();
}

/**
 * @memo	    Validate the current state of the handle port
 * @exception	    StaleDataException Thrown if the state has changed
 * @param	    newState The new state of the port
 * 
 * @doc		    After opening a port or refreshing, no state is tracked.
 *		    The first time validate is called, the state is recorded.
 *		    Subsequent calls will verify that the state is the same.
 *		    If the state has changed, the exception will be thrown.
 */
void HandlePort::validate(uint64_t newState) {
	Trace log("HandlePort::validate");
	log.debug("Port %016llx state %016llx", port->getPortWWN(), newState);
	lock();
	if (active) {
	    if (lastState != newState) {
		unlock();
		throw StaleDataException();
	    }
	} else {
	    active = true;
	    lastState = newState;
	}
	unlock();
}

/**
 * @memo	    Verify this port has the stated port wwn
 * @return	    TRUE if the argument matches this port
 * @return	    FALSE if the argument does not match this port
 * @param	    portWWN The Port WWN to compare against this port
 */
bool HandlePort::match(uint64_t portWWN) {
	Trace log("HandlePort::match(wwn)");
	bool ret = false;
	ret = (portWWN == port->getPortWWN());
	return (ret);
}

/**
 * @memo	    Verify this port is the stated index
 * @return	    TRUE if the argument matches this port
 * @return	    FALSE if the argument does not match this port
 * @param	    index The index value to compare against this port
 */
bool HandlePort::match(int index) {
	Trace log("HandlePort::match(index)");
	return (*port == *(hba->getPortByIndex(index)));
}

/**
 * @memo	    Get attributes from a discovered port.
 * @exception	    ... underlying exceptions will be thrown
 * @return	    The discovered port attributes
 * @param	    wwn The node or port wwn of the discovered port
 * 
 * @doc		    This routine will not perform any state validation
 */
HBA_PORTATTRIBUTES HandlePort::getDiscoveredAttributes(uint64_t wwn) {
	Trace log("HandlePort::getDiscoveredAttributes(wwn)");
	uint64_t newState;
	HBA_PORTATTRIBUTES attributes = port->getDiscoveredAttributes(
		wwn, newState);
	// We don't validate when a WWN was used
	return (attributes);
}

/**
 * @memo	    Get attributes from this port.
 * @exception	    ... underlying exceptions will be thrown
 * @return	    The port attributes
 * @see		    HandlePort::validate
 * 
 * @doc		    This routine will perform state validation
 */
HBA_PORTATTRIBUTES HandlePort::getPortAttributes() {
	Trace log("HandlePort::getPortAttributes");
	uint64_t newState;
	HBA_PORTATTRIBUTES attributes = port->getPortAttributes(newState);
	validate(newState);
	return (attributes);
}

/**
 * @memo	    Get attributes from a discovered port.
 * @exception	    ... underlying exceptions will be thrown
 * @return	    The discovered port attributes
 * @param	    discoveredport The index of the discovered port
 * @see		    HandlePort::validate
 * 
 * @doc		    This routine will perform state validation
 */
HBA_PORTATTRIBUTES
HandlePort::getDiscoveredAttributes(HBA_UINT32 discoveredport) {
	Trace log("HandlePort::getDiscoveredAttributes(index)");
	uint64_t newState;
	HBA_PORTATTRIBUTES attributes = port->getDiscoveredAttributes(
		discoveredport, newState);
	validate(newState);
	return (attributes);
}

HBA_PORTNPIVATTRIBUTES HandlePort::getPortNPIVAttributes() {
	Trace log("HandlePort::getPortNPIVAttributes");
	uint64_t newState;
	HBA_PORTNPIVATTRIBUTES attributes = port->getPortNPIVAttributes(newState);
	validate(newState);
	return (attributes);
}

uint32_t HandlePort::deleteNPIVPort(uint64_t vportwwn) {
	Trace log("HandlePort::deleteNPIVPort");
	uint32_t ret = port->deleteNPIVPort(vportwwn);

	return (ret);
}

uint32_t HandlePort::createNPIVPort(uint64_t vnodewwn,
    uint64_t vportwwn, uint32_t vindex) {
	Trace log("HandlePort::createNPIVPort");
	uint32_t vportindex;

	vportindex = port->createNPIVPort(vnodewwn, vportwwn, vindex);
	return (vportindex);
}

HandleNPIVPort* HandlePort::getHandleNPIVPortByIndex(int index) {
	Trace log("HandlePort::getHandleNPIVPortByIndex(int index)");

	HBANPIVPort* vport = port->getPortByIndex(index);
	return (getHandleNPIVPort(vport->getPortWWN()));
}

HandleNPIVPort* HandlePort::getHandleNPIVPort(uint64_t wwn) {
	Trace log("HandlePort::getHandleNPIVPort");
	lock();
	try {
		// Check to see if the wwn is in the map
		if (npivportHandles.find(wwn) == npivportHandles.end()) {
			// Not found, add a new one
			HBANPIVPort* vport = port->getPort(wwn);
			npivportHandles[wwn] = new HandleNPIVPort(handle, this, hba, port, vport);
		}
		HandleNPIVPort *npivportHandle = npivportHandles[wwn];
		unlock();
		return (npivportHandle);
	} catch (...) {
		unlock();
		throw;
	}
}