xref: /illumos-gate/usr/src/lib/sun_fc/common/HBA.cc (revision f3aaec0a)
1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
221770502eSYu Renia Miao  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce44SJohn Forte  * Use is subject to license terms.
24fcf3ce44SJohn Forte  */
25fcf3ce44SJohn Forte 
26fcf3ce44SJohn Forte 
27fcf3ce44SJohn Forte 
28fcf3ce44SJohn Forte #include "HBA.h"
29fcf3ce44SJohn Forte #include "Exceptions.h"
30fcf3ce44SJohn Forte #include "Trace.h"
31fcf3ce44SJohn Forte #include <iostream>
32fcf3ce44SJohn Forte #include <iomanip>
33fcf3ce44SJohn Forte #include <sys/types.h>
34fcf3ce44SJohn Forte #include <sys/stat.h>
35fcf3ce44SJohn Forte #include <time.h>
36fcf3ce44SJohn Forte #include <fcntl.h>
37fcf3ce44SJohn Forte #include <unistd.h>
38fcf3ce44SJohn Forte #include <stropts.h>
39fcf3ce44SJohn Forte #include <errno.h>
40*f3aaec0aSRichard Lowe #include <climits>
41*f3aaec0aSRichard Lowe #include <cstring>
42fcf3ce44SJohn Forte 
43fcf3ce44SJohn Forte #define	    NSECS_PER_SEC	1000000000l
44fcf3ce44SJohn Forte #define	    BUSY_SLEEP		NSECS_PER_SEC/10 /* 1/10 second */
45fcf3ce44SJohn Forte #define	    BUSY_RETRY_TIMER	3000000000UL /* Retry for 3 seconds */
46fcf3ce44SJohn Forte 
47fcf3ce44SJohn Forte using namespace std;
48fcf3ce44SJohn Forte 
49fcf3ce44SJohn Forte /**
50fcf3ce44SJohn Forte  * Max number of Adatper ports per HBA that VSL supports.
51fcf3ce44SJohn Forte  *
52fcf3ce44SJohn Forte  */
53fcf3ce44SJohn Forte const uint8_t HBA::HBA_PORT_MAX = UCHAR_MAX;
54fcf3ce44SJohn Forte 
55fcf3ce44SJohn Forte /**
56fcf3ce44SJohn Forte  * @memo	    Add a new port to this HBA
57fcf3ce44SJohn Forte  * @precondition    Port must be a valid port on this HBA
58fcf3ce44SJohn Forte  * @postcondition   Port will be exposed as one of the ports on this HBA
59fcf3ce44SJohn Forte  * @exception	    Throws InternalError when the HBA port count exceeds
60fcf3ce44SJohn Forte  *		    max number of ports and throws any underlying exception
61fcf3ce44SJohn Forte  * @param	    port The Port to add to this HBA
62fcf3ce44SJohn Forte  *
63fcf3ce44SJohn Forte  * @doc		    When discovering HBAs and their ports, use this
64fcf3ce44SJohn Forte  *		    routine to add a port to its existing HBA instance.
65fcf3ce44SJohn Forte  */
addPort(HBAPort * port)66fcf3ce44SJohn Forte void HBA::addPort(HBAPort* port) {
67fcf3ce44SJohn Forte 	Trace log("HBA::addPort");
68fcf3ce44SJohn Forte 	lock();
69fcf3ce44SJohn Forte 	// support hba with up to UCHAR_MAX number of ports.
70fcf3ce44SJohn Forte 	if (portsByIndex.size() + 1 > HBA_PORT_MAX) {
71fcf3ce44SJohn Forte 	    unlock();
72fcf3ce44SJohn Forte 	    throw InternalError("HBA Port count exceeds max number of ports");
73fcf3ce44SJohn Forte 	}
74fcf3ce44SJohn Forte 
75fcf3ce44SJohn Forte 	try {
76fcf3ce44SJohn Forte 	    portsByWWN[port->getPortWWN()] = port;
77fcf3ce44SJohn Forte 	    portsByIndex.insert(portsByIndex.end(), port);
78fcf3ce44SJohn Forte 	    unlock();
79fcf3ce44SJohn Forte 	} catch (...) {
80fcf3ce44SJohn Forte 	    unlock();
81fcf3ce44SJohn Forte 	    throw;
82fcf3ce44SJohn Forte 	}
83fcf3ce44SJohn Forte }
84fcf3ce44SJohn Forte 
85fcf3ce44SJohn Forte /**
86fcf3ce44SJohn Forte  * @memo	    Return number of ports to this HBA
87fcf3ce44SJohn Forte  * @exception	    No exception for this method.
88fcf3ce44SJohn Forte  *
89fcf3ce44SJohn Forte  * @doc		    Returns the number of ports on this HBA. The max
90fcf3ce44SJohn Forte  *		    number of ports that VSL support is up to max uint8_t
91fcf3ce44SJohn Forte  *		    size.
92fcf3ce44SJohn Forte  */
getNumberOfPorts()93fcf3ce44SJohn Forte uint8_t HBA::getNumberOfPorts() {
94fcf3ce44SJohn Forte 	Trace log("HBA::getNumberOfPorts");
95fcf3ce44SJohn Forte 	return (uint8_t)portsByIndex.size();
96fcf3ce44SJohn Forte }
97fcf3ce44SJohn Forte 
98fcf3ce44SJohn Forte /**
99fcf3ce44SJohn Forte  * @memo	    Retrieve an HBA port based on a Port WWN
100fcf3ce44SJohn Forte  * @exception	    IllegalWWNException Thrown if WWN does not match any
101fcf3ce44SJohn Forte  *		    known HBA port.
102fcf3ce44SJohn Forte  * @return	    HBAPort* to the port with a matching Port WWN
103fcf3ce44SJohn Forte  * @param	    wwn The wwn of the desired HBA port
104fcf3ce44SJohn Forte  *
105fcf3ce44SJohn Forte  * @doc		    Fetch an HBA port based on WWN.  If the port is not
106fcf3ce44SJohn Forte  *		    found, an exception will be thrown.  NULL will never
107fcf3ce44SJohn Forte  *		    be returned.
108fcf3ce44SJohn Forte  */
getPort(uint64_t wwn)109fcf3ce44SJohn Forte HBAPort* HBA::getPort(uint64_t wwn) {
110fcf3ce44SJohn Forte 	Trace log("HBA::getPort");
111fcf3ce44SJohn Forte 	HBAPort *port = NULL;
112fcf3ce44SJohn Forte 	lock();
113fcf3ce44SJohn Forte 
114fcf3ce44SJohn Forte 	log.debug("getPort(wwn): WWN %016llx", wwn);
115fcf3ce44SJohn Forte 
116fcf3ce44SJohn Forte 	try {
117fcf3ce44SJohn Forte 	    // Make sure it is in the map
118fcf3ce44SJohn Forte 	    if (portsByWWN.find(wwn) == portsByWWN.end()) {
119fcf3ce44SJohn Forte 		throw IllegalWWNException();
120fcf3ce44SJohn Forte 	    }
121fcf3ce44SJohn Forte 	    port = portsByWWN[wwn];
122fcf3ce44SJohn Forte 	    unlock();
123fcf3ce44SJohn Forte 	    return (port);
124fcf3ce44SJohn Forte 	} catch (...) {
125fcf3ce44SJohn Forte 	    unlock();
126fcf3ce44SJohn Forte 	    throw;
127fcf3ce44SJohn Forte 	}
128fcf3ce44SJohn Forte }
129fcf3ce44SJohn Forte 
130fcf3ce44SJohn Forte /**
131fcf3ce44SJohn Forte  * Iterator for WWN to HBAPort map type
132fcf3ce44SJohn Forte  */
133fcf3ce44SJohn Forte typedef map<uint64_t, HBAPort *>::const_iterator CI;
134fcf3ce44SJohn Forte 
135fcf3ce44SJohn Forte /**
136fcf3ce44SJohn Forte  * @memo	    Return true if this HBA contains the stated WWN
137fcf3ce44SJohn Forte  *		    (node or port)
138fcf3ce44SJohn Forte  * @exception	    ... underlying exceptions will be thrown
139fcf3ce44SJohn Forte  * @return	    TRUE if the wwn is found
140fcf3ce44SJohn Forte  * @return	    FALSE if the wwn is not found
141fcf3ce44SJohn Forte  * @param	    wwn The wwn to look for
142fcf3ce44SJohn Forte  *
143fcf3ce44SJohn Forte  */
containsWWN(uint64_t wwn)144fcf3ce44SJohn Forte bool HBA::containsWWN(uint64_t wwn) {
145fcf3ce44SJohn Forte 	Trace log("HBA::containsWWN");
146fcf3ce44SJohn Forte 	lock();
147fcf3ce44SJohn Forte 
148fcf3ce44SJohn Forte 	try {
149fcf3ce44SJohn Forte 	    for (CI port = portsByWWN.begin(); port != portsByWWN.end();
150fcf3ce44SJohn Forte 		    port++) {
151fcf3ce44SJohn Forte 		if (port->second->getPortWWN() == wwn) {
152fcf3ce44SJohn Forte 		    unlock();
153fcf3ce44SJohn Forte 		    return (true);
154fcf3ce44SJohn Forte 		}
155fcf3ce44SJohn Forte 		if (port->second->getNodeWWN() == wwn) {
156fcf3ce44SJohn Forte 		    unlock();
157fcf3ce44SJohn Forte 		    return (true);
158fcf3ce44SJohn Forte 		}
159fcf3ce44SJohn Forte 	    }
160fcf3ce44SJohn Forte 	    unlock();
161fcf3ce44SJohn Forte 	    return (false);
162fcf3ce44SJohn Forte 	} catch (...) {
163fcf3ce44SJohn Forte 	    unlock();
164fcf3ce44SJohn Forte 	    throw;
165fcf3ce44SJohn Forte 	}
166fcf3ce44SJohn Forte }
167fcf3ce44SJohn Forte 
168fcf3ce44SJohn Forte /**
169fcf3ce44SJohn Forte  * @memo	    Fetch the port based on index.
170fcf3ce44SJohn Forte  * @exception	    IllegalIndexException Thrown if the index is not valid
171fcf3ce44SJohn Forte  * @return	    HBAPort* the port matching the index
172fcf3ce44SJohn Forte  * @param	    index - the zero based index of the port to retrieve
173fcf3ce44SJohn Forte  *
174fcf3ce44SJohn Forte  */
getPortByIndex(int index)175fcf3ce44SJohn Forte HBAPort* HBA::getPortByIndex(int index) {
176fcf3ce44SJohn Forte 	Trace log("HBA::getPortByIndex");
177fcf3ce44SJohn Forte 	lock();
178fcf3ce44SJohn Forte 	try {
179fcf3ce44SJohn Forte 	    log.debug("Port index size %d index %d ", portsByIndex.size(),
180fcf3ce44SJohn Forte 		    index);
181fcf3ce44SJohn Forte 
182fcf3ce44SJohn Forte 	    if (index >= portsByIndex.size() || index < 0) {
183fcf3ce44SJohn Forte 		throw IllegalIndexException();
184fcf3ce44SJohn Forte 	    }
185fcf3ce44SJohn Forte 
186fcf3ce44SJohn Forte 	    HBAPort *tmp = portsByIndex[index];
187fcf3ce44SJohn Forte 	    unlock();
188fcf3ce44SJohn Forte 	    return (tmp);
189fcf3ce44SJohn Forte 	} catch (...) {
190fcf3ce44SJohn Forte 	    unlock();
191fcf3ce44SJohn Forte 	    throw;
192fcf3ce44SJohn Forte 	}
193fcf3ce44SJohn Forte }
194fcf3ce44SJohn Forte 
195fcf3ce44SJohn Forte /**
196fcf3ce44SJohn Forte  * @memo	    Compare two HBAs for equality
197fcf3ce44SJohn Forte  * @precondition    Both HBAs should be fully discovered (all ports added)
198fcf3ce44SJohn Forte  * @exception	    ... underlying exceptions will be thrown
199fcf3ce44SJohn Forte  * @return	    TRUE The two HBA instances represent the same HBA
200fcf3ce44SJohn Forte  * @return	    FALSE The two HBA instances are different
201fcf3ce44SJohn Forte  *
202fcf3ce44SJohn Forte  * @doc		    This routine will compare each port within both
203fcf3ce44SJohn Forte  *		    HBAs and verify they are the same.  The ports must
204fcf3ce44SJohn Forte  *		    have been added in the same order.
205fcf3ce44SJohn Forte  */
operator ==(HBA & comp)206fcf3ce44SJohn Forte bool HBA::operator==(HBA &comp) {
207fcf3ce44SJohn Forte 	Trace log("HBA::operator==");
208fcf3ce44SJohn Forte 	lock();
209fcf3ce44SJohn Forte 
210fcf3ce44SJohn Forte 	try {
211fcf3ce44SJohn Forte 	    bool ret = false;
212fcf3ce44SJohn Forte 	    if (portsByIndex.size() == comp.portsByIndex.size()) {
213fcf3ce44SJohn Forte 		if (portsByIndex.size() > 0) {
214fcf3ce44SJohn Forte 		    ret = (*portsByIndex[0] == *comp.portsByIndex[0]);
215fcf3ce44SJohn Forte 		}
216fcf3ce44SJohn Forte 	    }
217fcf3ce44SJohn Forte 	    unlock();
218fcf3ce44SJohn Forte 	    return (ret);
219fcf3ce44SJohn Forte 	} catch (...) {
220fcf3ce44SJohn Forte 	    unlock();
221fcf3ce44SJohn Forte 	    throw;
222fcf3ce44SJohn Forte 	}
223fcf3ce44SJohn Forte }
224fcf3ce44SJohn Forte 
225fcf3ce44SJohn Forte /**
226fcf3ce44SJohn Forte  * @memo	    Set the RNID data for all the ports in this HBA
227fcf3ce44SJohn Forte  * @precondition    All ports must be added
228fcf3ce44SJohn Forte  * @postcondition   Each port will have the same RNID value set
229fcf3ce44SJohn Forte  * @exception	    ... underlying exceptions will be thrown.  Partial failure
230fcf3ce44SJohn Forte  *		    is possible and will not be cleaned up.
231fcf3ce44SJohn Forte  * @param	    info The RNID information to program for each HBA port
232fcf3ce44SJohn Forte  * @see		    HBAPort::setRNID
233fcf3ce44SJohn Forte  *
234fcf3ce44SJohn Forte  */
setRNID(HBA_MGMTINFO info)235fcf3ce44SJohn Forte void HBA::setRNID(HBA_MGMTINFO info) {
236fcf3ce44SJohn Forte 	Trace log("HBA::setRNID");
237fcf3ce44SJohn Forte 	lock();
238fcf3ce44SJohn Forte 
239fcf3ce44SJohn Forte 	try {
240fcf3ce44SJohn Forte 	    for (CI port = portsByWWN.begin(); port != portsByWWN.end();
241fcf3ce44SJohn Forte 		    port++) {
242fcf3ce44SJohn Forte 		port->second->setRNID(info);
243fcf3ce44SJohn Forte 	    }
244fcf3ce44SJohn Forte 	    unlock();
245fcf3ce44SJohn Forte 	} catch (...) {
246fcf3ce44SJohn Forte 	    unlock();
247fcf3ce44SJohn Forte 	    throw;
248fcf3ce44SJohn Forte 	}
249fcf3ce44SJohn Forte }
250fcf3ce44SJohn Forte 
251fcf3ce44SJohn Forte /**
252fcf3ce44SJohn Forte  * @memo	    Verify that this HBA is present on the system
253fcf3ce44SJohn Forte  * @exception	    UnavailableException Thrown when HBA not present
254fcf3ce44SJohn Forte  * @see		    HBAPort::validatePresent
255fcf3ce44SJohn Forte  *
256fcf3ce44SJohn Forte  * @doc		    This routine is used to verify that a given HBA
257fcf3ce44SJohn Forte  *		    has not been removed through dynamic reconfiguration.
258fcf3ce44SJohn Forte  *		    If the HBA is present, the routine will return.
259fcf3ce44SJohn Forte  *		    If the HBA is not present (if any port is not present)
260fcf3ce44SJohn Forte  *		    an exception will be thrown
261fcf3ce44SJohn Forte  */
validatePresent()262fcf3ce44SJohn Forte void HBA::validatePresent() {
263fcf3ce44SJohn Forte 	Trace log("HBA::validatePresent");
264fcf3ce44SJohn Forte 	lock();
265fcf3ce44SJohn Forte 	try {
266fcf3ce44SJohn Forte 	    for (CI port = portsByWWN.begin(); port != portsByWWN.end();
267fcf3ce44SJohn Forte 		    port++) {
268fcf3ce44SJohn Forte 		port->second->validatePresent();
269fcf3ce44SJohn Forte 	    }
270fcf3ce44SJohn Forte 	    unlock();
271fcf3ce44SJohn Forte 	} catch (...) {
272fcf3ce44SJohn Forte 	    unlock();
273fcf3ce44SJohn Forte 	    throw;
274fcf3ce44SJohn Forte 	}
275fcf3ce44SJohn Forte }
276fcf3ce44SJohn Forte 
277fcf3ce44SJohn Forte /**
278fcf3ce44SJohn Forte  * Opens a file, throwing exceptions on error.
279fcf3ce44SJohn Forte  */
_open(std::string path,int flag)280fcf3ce44SJohn Forte int HBA::_open(std::string path, int flag) {
281fcf3ce44SJohn Forte 	Trace log("HBA::open");
282fcf3ce44SJohn Forte 	int fd;
283fcf3ce44SJohn Forte 	errno = 0;
284fcf3ce44SJohn Forte 	if ((fd = open(path.c_str(), flag)) < 0) {
285fcf3ce44SJohn Forte 	    log.debug("Unable to open \"%s\" - reason (%d) %s",
286fcf3ce44SJohn Forte 		path.c_str(), errno, strerror(errno));
287fcf3ce44SJohn Forte 	    if (errno == EBUSY) {
288fcf3ce44SJohn Forte 		throw BusyException();
289fcf3ce44SJohn Forte 	    } else if (errno == EAGAIN) {
290fcf3ce44SJohn Forte 		throw TryAgainException();
291fcf3ce44SJohn Forte 	    } else if (errno == ENOTSUP) {
292fcf3ce44SJohn Forte 		throw NotSupportedException();
293fcf3ce44SJohn Forte 	    } else if (errno == ENOENT) {
294fcf3ce44SJohn Forte 		throw UnavailableException();
295fcf3ce44SJohn Forte 	    } else {
296fcf3ce44SJohn Forte 		string msg = "Unable to open ";
297fcf3ce44SJohn Forte 		msg += path;
298fcf3ce44SJohn Forte 		throw IOError(msg);
299fcf3ce44SJohn Forte 	    }
300fcf3ce44SJohn Forte 	}
301fcf3ce44SJohn Forte 	return (fd);
302fcf3ce44SJohn Forte }
303fcf3ce44SJohn Forte 
304fcf3ce44SJohn Forte /**
305fcf3ce44SJohn Forte  * Issues IOCTL, throwing exceptions on error.
306fcf3ce44SJohn Forte  * Note, if the IOCTL succeeds, but some IOCTL specific
307fcf3ce44SJohn Forte  * error is recorded in the response, this routine
308fcf3ce44SJohn Forte  * will not throw an exception.
309fcf3ce44SJohn Forte  */
_ioctl(int fd,int type,uchar_t * arg)310fcf3ce44SJohn Forte void HBA::_ioctl(int fd, int type, uchar_t *arg) {
311fcf3ce44SJohn Forte 	Trace log("HBA::ioctl");
312fcf3ce44SJohn Forte 	hrtime_t	    cur;
313fcf3ce44SJohn Forte 	int		    saved_errno = 0;
314fcf3ce44SJohn Forte 	struct timespec	    ts;
315fcf3ce44SJohn Forte 
316fcf3ce44SJohn Forte 	hrtime_t start = gethrtime();
317fcf3ce44SJohn Forte 	hrtime_t end = start + BUSY_RETRY_TIMER;
318fcf3ce44SJohn Forte 	ts.tv_sec = 0;
319fcf3ce44SJohn Forte 	ts.tv_nsec = BUSY_SLEEP;
320fcf3ce44SJohn Forte 	for (cur = start; cur < end; cur = gethrtime()) {
3211770502eSYu Renia Miao 		errno = 0;
322fcf3ce44SJohn Forte 		if (ioctl(fd, type, arg) != 0) {
323fcf3ce44SJohn Forte 			if (errno == EAGAIN) {
324fcf3ce44SJohn Forte 				saved_errno = errno;
325fcf3ce44SJohn Forte 				nanosleep(&ts, NULL);
326fcf3ce44SJohn Forte 				continue;
327fcf3ce44SJohn Forte 			} else if (errno == EBUSY) {
328fcf3ce44SJohn Forte 				saved_errno = errno;
329fcf3ce44SJohn Forte 				nanosleep(&ts, NULL);
330fcf3ce44SJohn Forte 				continue;
331fcf3ce44SJohn Forte 			} else if (errno == ENOTSUP) {
332fcf3ce44SJohn Forte 				throw NotSupportedException();
333fcf3ce44SJohn Forte 			} else if (errno == ENOENT) {
334fcf3ce44SJohn Forte 				throw UnavailableException();
335fcf3ce44SJohn Forte 			} else {
336fcf3ce44SJohn Forte 				throw IOError("IOCTL failed");
337fcf3ce44SJohn Forte 			}
338fcf3ce44SJohn Forte 		} else {
339fcf3ce44SJohn Forte 			break;
340fcf3ce44SJohn Forte 		}
341fcf3ce44SJohn Forte 	}
342fcf3ce44SJohn Forte 	if (cur >= end) {
343fcf3ce44SJohn Forte 		if (saved_errno == EAGAIN) {
344fcf3ce44SJohn Forte 			throw TryAgainException();
345fcf3ce44SJohn Forte 		} else if (saved_errno == EBUSY) {
346fcf3ce44SJohn Forte 			throw BusyException();
347fcf3ce44SJohn Forte 		} else {
348fcf3ce44SJohn Forte 			throw IOError("IOCTL failed");
349fcf3ce44SJohn Forte 		}
350fcf3ce44SJohn Forte 	}
351fcf3ce44SJohn Forte }
352fcf3ce44SJohn Forte 
~HBA()353fcf3ce44SJohn Forte HBA::~HBA() {
354fcf3ce44SJohn Forte 	Trace log("HBA::~HBA");
355fcf3ce44SJohn Forte 	for (int i = 0; i < getNumberOfPorts(); i++) {
356fcf3ce44SJohn Forte 	    delete (getPortByIndex(i));
357fcf3ce44SJohn Forte 	}
358fcf3ce44SJohn Forte }
359fcf3ce44SJohn Forte 
360