summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Matthew <jmatthew@cvs.openbsd.org>2014-05-21 22:59:27 +0000
committerJonathan Matthew <jmatthew@cvs.openbsd.org>2014-05-21 22:59:27 +0000
commit70c7cd037261acc773c1770acd81d27e865b951a (patch)
tree5a7ba57926883c60cc7877588ca7a477d8e9fd4b
parent52db3c8cc80b965ca7546cefeb4461a49f4d3bb3 (diff)
When the firmware tells us a loop id is already in use, add the device
there to our port lists, then find the next available loop id and carry on rather than restarting. This way, we're less likely to get stuck looping when the firmware behaves inconsistently. We also don't need to treat domain controller logins specially.
-rw-r--r--sys/dev/pci/qle.c85
1 files changed, 54 insertions, 31 deletions
diff --git a/sys/dev/pci/qle.c b/sys/dev/pci/qle.c
index 8ee6f772656..3ab2e5f6578 100644
--- a/sys/dev/pci/qle.c
+++ b/sys/dev/pci/qle.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: qle.c,v 1.28 2014/04/27 05:23:35 jmatthew Exp $ */
+/* $OpenBSD: qle.c,v 1.29 2014/05/21 22:59:26 jmatthew Exp $ */
/*
* Copyright (c) 2013, 2014 Jonathan Matthew <jmatthew@openbsd.org>
@@ -100,9 +100,6 @@ enum qle_port_disp {
QLE_PORT_DISP_DUP
};
-#define QLE_DOMAIN_CTRL_MASK 0xffff00
-#define QLE_DOMAIN_CTRL 0xfffc00
-
#define QLE_LOCATION_LOOP (1 << 24)
#define QLE_LOCATION_FABRIC (2 << 24)
#define QLE_LOCATION_LOOP_ID(l) (l | QLE_LOCATION_LOOP)
@@ -293,11 +290,11 @@ int qle_get_port_db(struct qle_softc *, u_int16_t,
int qle_get_port_name_list(struct qle_softc *sc, u_int32_t);
int qle_add_loop_port(struct qle_softc *, struct qle_fc_port *);
int qle_add_fabric_port(struct qle_softc *, struct qle_fc_port *);
-int qle_add_domain_ctrl_port(struct qle_softc *, u_int16_t,
+int qle_add_logged_in_port(struct qle_softc *, u_int16_t,
u_int32_t);
int qle_classify_port(struct qle_softc *, u_int32_t, u_int64_t,
u_int64_t, struct qle_fc_port **);
-int qle_get_loop_id(struct qle_softc *sc);
+int qle_get_loop_id(struct qle_softc *sc, int);
void qle_clear_port_lists(struct qle_softc *);
int qle_softreset(struct qle_softc *);
void qle_update_topology(struct qle_softc *);
@@ -765,12 +762,15 @@ qle_classify_port(struct qle_softc *sc, u_int32_t location,
}
int
-qle_get_loop_id(struct qle_softc *sc)
+qle_get_loop_id(struct qle_softc *sc, int start)
{
int i, last;
i = QLE_MIN_HANDLE;
last = QLE_MAX_HANDLE;
+ if (i < start)
+ i = start;
+
for (; i <= last; i++) {
if (sc->sc_targets[i] == NULL)
return (i);
@@ -947,6 +947,7 @@ qle_add_fabric_port(struct qle_softc *sc, struct qle_fc_port *port)
*/
if (port->location == QLE_LOCATION_FABRIC) {
port->node_name = betoh64(pdb->node_name);
+ port->port_name = betoh64(pdb->port_name);
port->portid = (pdb->port_id[0] << 16) |
(pdb->port_id[1] << 8) | pdb->port_id[2];
port->location = QLE_LOCATION_PORT_ID(port->portid);
@@ -964,29 +965,63 @@ qle_add_fabric_port(struct qle_softc *sc, struct qle_fc_port *port)
}
int
-qle_add_domain_ctrl_port(struct qle_softc *sc, u_int16_t loopid,
+qle_add_logged_in_port(struct qle_softc *sc, u_int16_t loopid,
u_int32_t portid)
{
struct qle_fc_port *port;
+ struct qle_get_port_db *pdb;
+ u_int64_t node_name, port_name;
+ int flags, ret;
+
+ ret = qle_get_port_db(sc, loopid, sc->sc_scratch);
+ mtx_enter(&sc->sc_port_mtx);
+ if (ret != 0) {
+ /* put in a fake port to prevent use of this loop id */
+ printf("%s: loop id %d used, but can't see what's using it\n",
+ DEVNAME(sc), loopid);
+ node_name = 0;
+ port_name = 0;
+ flags = 0;
+ } else {
+ pdb = QLE_DMA_KVA(sc->sc_scratch);
+ node_name = betoh64(pdb->node_name);
+ port_name = betoh64(pdb->port_name);
+ flags = 0;
+ if (lemtoh16(&pdb->prli_svc_word3) & QLE_SVC3_TARGET_ROLE)
+ flags |= QLE_PORT_FLAG_IS_TARGET;
+
+ /* see if we've already found this port */
+ TAILQ_FOREACH(port, &sc->sc_ports_found, update) {
+ if ((port->node_name == node_name) &&
+ (port->port_name == port_name) &&
+ (port->portid == portid)) {
+ mtx_leave(&sc->sc_port_mtx);
+ DPRINTF(QLE_D_PORT, "%s: already found port "
+ "%06x\n", DEVNAME(sc), portid);
+ return (0);
+ }
+ }
+ }
port = malloc(sizeof(*port), M_DEVBUF, M_ZERO | M_NOWAIT);
if (port == NULL) {
+ mtx_leave(&sc->sc_port_mtx);
printf("%s: failed to allocate a port structure\n",
DEVNAME(sc));
return (1);
}
port->location = QLE_LOCATION_PORT_ID(portid);
- port->port_name = 0;
- port->node_name = 0;
+ port->port_name = port_name;
+ port->node_name = node_name;
port->loopid = loopid;
port->portid = portid;
+ port->flags = flags;
- mtx_enter(&sc->sc_port_mtx);
TAILQ_INSERT_TAIL(&sc->sc_ports, port, ports);
sc->sc_targets[port->loopid] = port;
mtx_leave(&sc->sc_port_mtx);
- DPRINTF(QLE_D_PORT, "%s: added domain controller port %06x at %d\n",
+ DPRINTF(QLE_D_PORT, "%s: added logged in port %06x at %d\n",
DEVNAME(sc), portid, loopid);
return (0);
}
@@ -1976,14 +2011,14 @@ int
qle_fabric_plogi(struct qle_softc *sc, struct qle_fc_port *port)
{
u_int32_t info;
- int err;
+ int err, loopid;
+ loopid = 0;
retry:
if (port->loopid == 0) {
- int loopid;
mtx_enter(&sc->sc_port_mtx);
- loopid = qle_get_loop_id(sc);
+ loopid = qle_get_loop_id(sc, loopid);
mtx_leave(&sc->sc_port_mtx);
if (loopid == -1) {
printf("%s: ran out of loop ids\n", DEVNAME(sc));
@@ -2009,24 +2044,12 @@ retry:
return (0);
case QLE_PLOGX_ERROR_HANDLE_USED:
- /*
- * domain controller ids (fffcDD, where DD is the domain id)
- * get special treatment here because we can't find out about
- * them any other way. otherwise, we restart the update
- * process to add the port at this handle normally.
- */
- if ((info & QLE_DOMAIN_CTRL_MASK) == QLE_DOMAIN_CTRL) {
- if (qle_add_domain_ctrl_port(sc, port->loopid, info)) {
- return (1);
- }
- port->loopid = 0;
- goto retry;
+ if (qle_add_logged_in_port(sc, loopid, info)) {
+ return (1);
}
- DPRINTF(QLE_D_PORT, "%s: handle %d used for port %06x\n",
- DEVNAME(sc), loopid, info);
- qle_update_start(sc, QLE_UPDATE_TASK_GET_PORT_LIST);
port->loopid = 0;
- return (1);
+ loopid++;
+ goto retry;
default:
DPRINTF(QLE_D_PORT, "%s: error %x logging in to port %06x\n",