summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2015-10-05 10:37:20 +0000
committermav <mav@FreeBSD.org>2015-10-05 10:37:20 +0000
commitb89b02cbef6884e948f9135c52708e64007070e9 (patch)
tree754475e35bc674635cd13802fc22edfe97e6c0c3
parent2da4219a54809b45e73b23decdffb6a381677fcd (diff)
downloadFreeBSD-src-b89b02cbef6884e948f9135c52708e64007070e9.zip
FreeBSD-src-b89b02cbef6884e948f9135c52708e64007070e9.tar.gz
MFC r287940: Replicate initiators WWPNs and names between HA peers.
-rw-r--r--sys/cam/ctl/ctl.c78
-rw-r--r--sys/cam/ctl/ctl.h1
-rw-r--r--sys/cam/ctl/ctl_io.h13
3 files changed, 91 insertions, 1 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index 8f1ef5f..47401d6 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -656,14 +656,56 @@ ctl_isc_announce_port(struct ctl_port *port)
free(msg, M_CTL);
}
+void
+ctl_isc_announce_iid(struct ctl_port *port, int iid)
+{
+ struct ctl_softc *softc = control_softc;
+ union ctl_ha_msg *msg;
+ int i, l;
+
+ if (port->targ_port < softc->port_min ||
+ port->targ_port >= softc->port_max ||
+ softc->ha_link != CTL_HA_LINK_ONLINE)
+ return;
+ mtx_lock(&softc->ctl_lock);
+ i = sizeof(msg->iid);
+ l = 0;
+ if (port->wwpn_iid[iid].name)
+ l = strlen(port->wwpn_iid[iid].name) + 1;
+ i += l;
+ msg = malloc(i, M_CTL, M_NOWAIT);
+ if (msg == NULL) {
+ mtx_unlock(&softc->ctl_lock);
+ return;
+ }
+ bzero(&msg->iid, sizeof(msg->iid));
+ msg->hdr.msg_type = CTL_MSG_IID_SYNC;
+ msg->hdr.nexus.targ_port = port->targ_port;
+ msg->hdr.nexus.initid = iid;
+ msg->iid.in_use = port->wwpn_iid[iid].in_use;
+ msg->iid.name_len = l;
+ msg->iid.wwpn = port->wwpn_iid[iid].wwpn;
+ if (port->wwpn_iid[iid].name)
+ strlcpy(msg->iid.data, port->wwpn_iid[iid].name, l);
+ mtx_unlock(&softc->ctl_lock);
+ ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg->iid, i, M_NOWAIT);
+ free(msg, M_CTL);
+}
+
static void
ctl_isc_ha_link_up(struct ctl_softc *softc)
{
struct ctl_port *port;
struct ctl_lun *lun;
+ int i;
- STAILQ_FOREACH(port, &softc->port_list, links)
+ STAILQ_FOREACH(port, &softc->port_list, links) {
ctl_isc_announce_port(port);
+ for (i = 0; i < CTL_MAX_INIT_PER_PORT; i++) {
+ if (port->wwpn_iid[i].in_use)
+ ctl_isc_announce_iid(port, i);
+ }
+ }
STAILQ_FOREACH(lun, &softc->lun_list, links)
ctl_isc_announce_lun(lun);
}
@@ -674,6 +716,7 @@ ctl_isc_ha_link_down(struct ctl_softc *softc)
struct ctl_port *port;
struct ctl_lun *lun;
union ctl_io *io;
+ int i;
mtx_lock(&softc->ctl_lock);
STAILQ_FOREACH(lun, &softc->lun_list, links) {
@@ -698,6 +741,11 @@ ctl_isc_ha_link_down(struct ctl_softc *softc)
port->targ_port < softc->port_max)
continue;
port->status &= ~CTL_PORT_STATUS_ONLINE;
+ for (i = 0; i < CTL_MAX_INIT_PER_PORT; i++) {
+ port->wwpn_iid[i].in_use = 0;
+ free(port->wwpn_iid[i].name, M_CTL);
+ port->wwpn_iid[i].name = NULL;
+ }
}
mtx_unlock(&softc->ctl_lock);
}
@@ -910,6 +958,29 @@ ctl_isc_port_sync(struct ctl_softc *softc, union ctl_ha_msg *msg, int len)
mtx_unlock(&softc->ctl_lock);
}
+static void
+ctl_isc_iid_sync(struct ctl_softc *softc, union ctl_ha_msg *msg, int len)
+{
+ struct ctl_port *port;
+ int iid;
+
+ port = softc->ctl_ports[msg->hdr.nexus.targ_port];
+ if (port == NULL) {
+ printf("%s: Received IID for unknown port %d\n",
+ __func__, msg->hdr.nexus.targ_port);
+ return;
+ }
+ iid = msg->hdr.nexus.initid;
+ port->wwpn_iid[iid].in_use = msg->iid.in_use;
+ port->wwpn_iid[iid].wwpn = msg->iid.wwpn;
+ free(port->wwpn_iid[iid].name, M_CTL);
+ if (msg->iid.name_len) {
+ port->wwpn_iid[iid].name = strndup(&msg->iid.data[0],
+ msg->iid.name_len, M_CTL);
+ } else
+ port->wwpn_iid[iid].name = NULL;
+}
+
/*
* ISC (Inter Shelf Communication) event handler. Events from the HA
* subsystem come in here.
@@ -1185,6 +1256,9 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param)
case CTL_MSG_LUN_SYNC:
ctl_isc_lun_sync(softc, msg, param);
break;
+ case CTL_MSG_IID_SYNC:
+ ctl_isc_iid_sync(softc, msg, param);
+ break;
default:
printf("Received HA message of unknown type %d\n",
msg->hdr.msg_type);
@@ -1599,6 +1673,7 @@ ctl_remove_initiator(struct ctl_port *port, int iid)
port->wwpn_iid[iid].in_use--;
port->wwpn_iid[iid].last_use = time_uptime;
mtx_unlock(&softc->ctl_lock);
+ ctl_isc_announce_iid(port, iid);
return (0);
}
@@ -1714,6 +1789,7 @@ take:
port->wwpn_iid[iid].wwpn = wwpn;
port->wwpn_iid[iid].in_use++;
mtx_unlock(&softc->ctl_lock);
+ ctl_isc_announce_iid(port, iid);
return (iid);
}
diff --git a/sys/cam/ctl/ctl.h b/sys/cam/ctl/ctl.h
index d10bdf6..5d8a182 100644
--- a/sys/cam/ctl/ctl.h
+++ b/sys/cam/ctl/ctl.h
@@ -191,6 +191,7 @@ void ctl_clr_ua_allluns(struct ctl_softc *ctl_softc, uint32_t initidx,
void ctl_isc_announce_lun(struct ctl_lun *lun);
void ctl_isc_announce_port(struct ctl_port *port);
+void ctl_isc_announce_iid(struct ctl_port *port, int iid);
/*
* KPI to manipulate LUN/port options
diff --git a/sys/cam/ctl/ctl_io.h b/sys/cam/ctl/ctl_io.h
index 86aebc9..2fb8900 100644
--- a/sys/cam/ctl/ctl_io.h
+++ b/sys/cam/ctl/ctl_io.h
@@ -197,6 +197,7 @@ typedef enum {
CTL_MSG_UA, /* Set/clear UA on secondary. */
CTL_MSG_PORT_SYNC, /* Information about port. */
CTL_MSG_LUN_SYNC, /* Information about LUN. */
+ CTL_MSG_IID_SYNC, /* Information about initiator. */
CTL_MSG_FAILOVER /* Fake, never sent though the wire */
} ctl_msg_type;
@@ -502,6 +503,17 @@ struct ctl_ha_msg_lun_pr_key {
uint64_t pr_key;
};
+/*
+ * Used for CTL_MSG_IID_SYNC.
+ */
+struct ctl_ha_msg_iid {
+ struct ctl_ha_msg_hdr hdr;
+ int in_use;
+ int name_len;
+ uint64_t wwpn;
+ uint8_t data[];
+};
+
union ctl_ha_msg {
struct ctl_ha_msg_hdr hdr;
struct ctl_ha_msg_task task;
@@ -511,6 +523,7 @@ union ctl_ha_msg {
struct ctl_ha_msg_ua ua;
struct ctl_ha_msg_port port;
struct ctl_ha_msg_lun lun;
+ struct ctl_ha_msg_iid iid;
};
OpenPOWER on IntegriCloud