diff options
-rw-r--r-- | sys/cam/ctl/ctl.c | 46 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_ha.c | 35 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_ha.h | 1 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_io.h | 24 |
4 files changed, 99 insertions, 7 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c index 3dee0aa..c172afb 100644 --- a/sys/cam/ctl/ctl.c +++ b/sys/cam/ctl/ctl.c @@ -717,8 +717,20 @@ ctl_isc_ha_link_up(struct ctl_softc *softc) { struct ctl_port *port; struct ctl_lun *lun; + union ctl_ha_msg msg; int i; + /* Announce this node parameters to peer for validation. */ + msg.login.msg_type = CTL_MSG_LOGIN; + msg.login.version = CTL_HA_VERSION; + msg.login.ha_mode = softc->ha_mode; + msg.login.ha_id = softc->ha_id; + msg.login.max_luns = CTL_MAX_LUNS; + msg.login.max_ports = CTL_MAX_PORTS; + msg.login.max_init_per_port = CTL_MAX_INIT_PER_PORT; + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg.login, sizeof(msg.login), + M_WAITOK); + STAILQ_FOREACH(port, &softc->port_list, links) { ctl_isc_announce_port(port); for (i = 0; i < CTL_MAX_INIT_PER_PORT; i++) { @@ -1001,6 +1013,36 @@ ctl_isc_iid_sync(struct ctl_softc *softc, union ctl_ha_msg *msg, int len) port->wwpn_iid[iid].name = NULL; } +static void +ctl_isc_login(struct ctl_softc *softc, union ctl_ha_msg *msg, int len) +{ + + if (msg->login.version != CTL_HA_VERSION) { + printf("CTL HA peers have different versions %d != %d\n", + msg->login.version, CTL_HA_VERSION); + ctl_ha_msg_abort(CTL_HA_CHAN_CTL); + return; + } + if (msg->login.ha_mode != softc->ha_mode) { + printf("CTL HA peers have different ha_mode %d != %d\n", + msg->login.ha_mode, softc->ha_mode); + ctl_ha_msg_abort(CTL_HA_CHAN_CTL); + return; + } + if (msg->login.ha_id == softc->ha_id) { + printf("CTL HA peers have same ha_id %d\n", msg->login.ha_id); + ctl_ha_msg_abort(CTL_HA_CHAN_CTL); + return; + } + if (msg->login.max_luns != CTL_MAX_LUNS || + msg->login.max_ports != CTL_MAX_PORTS || + msg->login.max_init_per_port != CTL_MAX_INIT_PER_PORT) { + printf("CTL HA peers have different limits\n"); + ctl_ha_msg_abort(CTL_HA_CHAN_CTL); + return; + } +} + /* * ISC (Inter Shelf Communication) event handler. Events from the HA * subsystem come in here. @@ -1277,9 +1319,13 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) case CTL_MSG_IID_SYNC: ctl_isc_iid_sync(softc, msg, param); break; + case CTL_MSG_LOGIN: + ctl_isc_login(softc, msg, param); + break; default: printf("Received HA message of unknown type %d\n", msg->hdr.msg_type); + ctl_ha_msg_abort(CTL_HA_CHAN_CTL); break; } if (msg != &msgbuf) diff --git a/sys/cam/ctl/ctl_ha.c b/sys/cam/ctl/ctl_ha.c index 13cb2e1..03401ae 100644 --- a/sys/cam/ctl/ctl_ha.c +++ b/sys/cam/ctl/ctl_ha.c @@ -283,8 +283,9 @@ ctl_ha_rx_thread(void *arg) else next = sizeof(wire_hdr); SOCKBUF_LOCK(&so->so_rcv); - while (sbavail(&so->so_rcv) < next) { - if (softc->ha_connected == 0 || so->so_error || + while (sbavail(&so->so_rcv) < next || softc->ha_disconnect) { + if (softc->ha_connected == 0 || softc->ha_disconnect || + so->so_error || (so->so_rcv.sb_state & SBS_CANTRCVMORE)) { goto errout; } @@ -541,6 +542,18 @@ ctl_ha_listen(struct ha_softc *softc) printf("%s: REUSEADDR setting failed %d\n", __func__, error); } + bzero(&opt, sizeof(struct sockopt)); + opt.sopt_dir = SOPT_SET; + opt.sopt_level = SOL_SOCKET; + opt.sopt_name = SO_REUSEPORT; + opt.sopt_val = &val; + opt.sopt_valsize = sizeof(val); + val = 1; + error = sosetopt(softc->ha_lso, &opt); + if (error) { + printf("%s: REUSEPORT setting failed %d\n", + __func__, error); + } SOCKBUF_LOCK(&softc->ha_lso->so_rcv); soupcall_set(softc->ha_lso, SO_RCV, ctl_ha_lupcall, softc); SOCKBUF_UNLOCK(&softc->ha_lso->so_rcv); @@ -572,7 +585,8 @@ ctl_ha_conn_thread(void *arg) while (1) { if (softc->ha_disconnect || softc->ha_shutdown) { ctl_ha_close(softc); - ctl_ha_lclose(softc); + if (softc->ha_disconnect == 2 || softc->ha_shutdown) + ctl_ha_lclose(softc); softc->ha_disconnect = 0; if (softc->ha_shutdown) break; @@ -666,7 +680,7 @@ ctl_ha_peer_sysctl(SYSCTL_HANDLER_ARGS) sa->sin_addr.s_addr = htonl((b1 << 24) + (b2 << 16) + (b3 << 8) + b4); } - softc->ha_disconnect = 1; + softc->ha_disconnect = 2; softc->ha_wakeup = 1; mtx_unlock(&softc->ha_lock); wakeup(&softc->ha_wakeup); @@ -811,6 +825,19 @@ ctl_ha_msg_send(ctl_ha_channel channel, const void *addr, size_t len, return (ctl_ha_msg_send2(channel, addr, len, NULL, 0, wait)); } +ctl_ha_status +ctl_ha_msg_abort(ctl_ha_channel channel) +{ + struct ha_softc *softc = &ha_softc; + + mtx_lock(&softc->ha_lock); + softc->ha_disconnect = 1; + softc->ha_wakeup = 1; + mtx_unlock(&softc->ha_lock); + wakeup(&softc->ha_wakeup); + return (CTL_HA_STATUS_SUCCESS); +} + /* * Allocate a data transfer request structure. */ diff --git a/sys/cam/ctl/ctl_ha.h b/sys/cam/ctl/ctl_ha.h index 0d2c011..f38f640 100644 --- a/sys/cam/ctl/ctl_ha.h +++ b/sys/cam/ctl/ctl_ha.h @@ -125,6 +125,7 @@ ctl_ha_status ctl_ha_msg_send(ctl_ha_channel channel, const void *addr, size_t len, int wait); ctl_ha_status ctl_ha_msg_send2(ctl_ha_channel channel, const void *addr, size_t len, const void *addr2, size_t len2, int wait); +ctl_ha_status ctl_ha_msg_abort(ctl_ha_channel channel); ctl_ha_status ctl_ha_msg_deregister(ctl_ha_channel channel); struct ctl_ha_dt_req * ctl_dt_req_alloc(void); diff --git a/sys/cam/ctl/ctl_io.h b/sys/cam/ctl/ctl_io.h index 805a4ce..a9ed1d0 100644 --- a/sys/cam/ctl/ctl_io.h +++ b/sys/cam/ctl/ctl_io.h @@ -197,6 +197,7 @@ typedef enum { CTL_MSG_PORT_SYNC, /* Information about port. */ CTL_MSG_LUN_SYNC, /* Information about LUN. */ CTL_MSG_IID_SYNC, /* Information about initiator. */ + CTL_MSG_LOGIN, /* Information about HA peer. */ CTL_MSG_FAILOVER /* Fake, never sent though the wire */ } ctl_msg_type; @@ -358,6 +359,25 @@ struct ctl_taskio { uint8_t task_resp[3];/* Response information */ }; + +/* + * HA link messages. + */ +#define CTL_HA_VERSION 1 + +/* + * Used for CTL_MSG_LOGIN. + */ +struct ctl_ha_msg_login { + ctl_msg_type msg_type; + int version; + int ha_mode; + int ha_id; + int max_luns; + int max_ports; + int max_init_per_port; +}; + typedef enum { CTL_PR_REG_KEY, CTL_PR_UNREG_KEY, @@ -523,16 +543,14 @@ union ctl_ha_msg { struct ctl_ha_msg_port port; struct ctl_ha_msg_lun lun; struct ctl_ha_msg_iid iid; + struct ctl_ha_msg_login login; }; - struct ctl_prio { struct ctl_io_hdr io_hdr; struct ctl_ha_msg_pr pr_msg; }; - - union ctl_io { struct ctl_io_hdr io_hdr; /* common to all I/O types */ struct ctl_scsiio scsiio; /* Normal SCSI commands */ |