When the firmware tells us a loop id is already in use, add the device
authorjmatthew <jmatthew@openbsd.org>
Wed, 21 May 2014 22:59:26 +0000 (22:59 +0000)
committerjmatthew <jmatthew@openbsd.org>
Wed, 21 May 2014 22:59:26 +0000 (22:59 +0000)
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.

sys/dev/pci/qle.c

index 8ee6f77..3ab2e5f 100644 (file)
@@ -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",