diff -Naur drbd-utils-8.9.9.orig/scripts/drbd.ocf drbd-utils-8.9.9/scripts/drbd.ocf
--- drbd-utils-8.9.9.orig/scripts/drbd.ocf	2016-10-26 10:55:38.214292469 +0800
+++ drbd-utils-8.9.9/scripts/drbd.ocf	2016-10-26 11:02:30.160887975 +0800
@@ -329,6 +329,23 @@
 	do_cmd ${HA_SBIN_DIR}/crm_master -l reboot -D
 }
 
+_peer_node_process() {
+	# _since drbd9 support multiple connections
+	: ${_peer_node_id:=0}
+	DRBD_PER_NAME[$_peer_node_id]=$_conn_name
+	DRBD_PER_ID[$_peer_node_id]=$_peer_node_id
+	DRBD_PER_CSTATE[$_peer_node_id]=$_cstate
+	DRBD_PER_ROLE_REMOTE[$_peer_node_id]=${_peer:-Unknown}
+	DRBD_PER_DSTATE_REMOTE[$_peer_node_id]=${_pdsk:-DUnknown}
+
+	: == DEBUG == _peer_node_id                         == ${_peer_node_id} ==
+	: == DEBUG == DRBD_PER_NAME[_peer_node_id]          == ${DRBD_PER_NAME[${_peer_node_id}]} ==
+	: == DEBUG == DRBD_PER_ID[_peer_node_id]            == ${DRBD_PER_ID[${_peer_node_id}]} ==
+	: == DEBUG == DRBD_PER_CSTATE[_peer_node_id]        == ${DRBD_PER_CSTATE[${_peer_node_id}]} ==
+	: == DEBUG == DRBD_PER_ROLE_REMOTE[_peer_node_id]   == ${DRBD_PER_ROLE_REMOTE[${_peer_node_id}]} ==
+	: == DEBUG == DRBD_PER_DSTATE_REMOTE[_peer_node_id] == ${DRBD_PER_DSTATE_REMOTE[${_peer_node_id}]} ==
+}
+
 _sh_status_process() {
 	# _volume not present should not happen,
 	# but may help make this agent work even if it talks to drbd 8.3.
@@ -336,11 +353,36 @@
 	# not-yet-created volumes are reported as -1
 	(( _volume >= 0 )) || _volume=$[1 << 16]
 	DRBD_ROLE_LOCAL[$_volume]=${_role:-Unconfigured}
-	DRBD_ROLE_REMOTE[$_volume]=${_peer:-Unknown}
-	DRBD_CSTATE[$_volume]=$_cstate
 	DRBD_DSTATE_LOCAL[$_volume]=${_disk:-Unconfigured}
-	DRBD_DSTATE_REMOTE[$_volume]=${_pdsk:-DUnknown}
+
+	if $DRBD_VERSION_9 ; then
+		#Get from _peer_node_process
+		DRBD_NAME[$_volume]=${DRBD_PER_NAME[@]}
+		DRBD_ID[$_volume]=${DRBD_PER_ID[@]}
+		DRBD_VOLUME[$_volume]=${_volume}
+		DRBD_CSTATE[$_volume]=${DRBD_PER_CSTATE[@]}
+		DRBD_ROLE_REMOTE[$_volume]=${DRBD_PER_ROLE_REMOTE[@]}
+		DRBD_DSTATE_REMOTE[$_volume]=${DRBD_PER_DSTATE_REMOTE[@]}
+
+		DRBD_PER_NAME=()
+		DRBD_PER_ID=()
+		DRBD_PER_CSTATE=()
+		DRBD_PER_ROLE_REMOTE=()
+		DRBD_PER_DSTATE_REMOTE=()
+
+		: == DEBUG == _volume            == ${_volume} ==
+		: == DEBUG == DRBD_ROLE_LOCAL    == ${DRBD_ROLE_LOCAL[${_volume}]} ==
+		: == DEBUG == DRBD_DSTATE_LOCAL  == ${DRBD_DSTATE_LOCAL[${_volume}]} ==
+		: == DEBUG == DRBD_CSTATE        == ${DRBD_CSTATE[${_volume}]} ==
+		: == DEBUG == DRBD_ROLE_REMOTE   == ${DRBD_ROLE_REMOTE[${_volume}]} ==
+		: == DEBUG == DRBD_DSTATE_REMOTE == ${DRBD_DSTATE_REMOTE[${_volume}]} ==
+	else
+		DRBD_CSTATE[$_volume]=$_cstate
+		DRBD_ROLE_REMOTE[$_volume]=${_peer:-Unknown}
+		DRBD_DSTATE_REMOTE[$_volume]=${_pdsk:-DUnknown}
+	fi
 }
+
 drbd_set_status_variables() {
 	# drbdsetup sh-status prints these values to stdout,
 	# and then prints _sh_status_process.
@@ -353,6 +395,15 @@
 	local _resynced_percent
 	local out
 
+	if $DRBD_VERSION_9 ; then
+		local _peer_node_id _conn_name
+		DRBD_PER_NAME=()
+		DRBD_PER_ID=()
+		DRBD_PER_CSTATE=()
+		DRBD_PER_ROLE_REMOTE=()
+		DRBD_PER_DSTATE_REMOTE=()
+	fi
+
 	DRBD_ROLE_LOCAL=()
 	DRBD_ROLE_REMOTE=()
 	DRBD_CSTATE=()
@@ -370,16 +421,20 @@
 	# if there was no output at all, or a weird output
 	# make sure the status arrays won't be empty.
 	[[ ${#DRBD_ROLE_LOCAL[@]}    != 0 ]] || DRBD_ROLE_LOCAL=(Unconfigured)
-	[[ ${#DRBD_ROLE_REMOTE[@]}   != 0 ]] || DRBD_ROLE_REMOTE=(Unknown)
-	[[ ${#DRBD_CSTATE[@]}        != 0 ]] || DRBD_CSTATE=(Unconfigured)
 	[[ ${#DRBD_DSTATE_LOCAL[@]}  != 0 ]] || DRBD_DSTATE_LOCAL=(Unconfigured)
+	[[ ${#DRBD_CSTATE[@]}        != 0 ]] || DRBD_CSTATE=(Unconfigured)
+	[[ ${#DRBD_ROLE_REMOTE[@]}   != 0 ]] || DRBD_ROLE_REMOTE=(Unknown)
 	[[ ${#DRBD_DSTATE_REMOTE[@]} != 0 ]] || DRBD_DSTATE_REMOTE=(DUnknown)
 
-
+	if $DRBD_VERSION_9 ; then
+		: == DEBUG == DRBD_NAME    == ${DRBD_NAME[@]} ==
+		: == DEBUG == DRBD_ID    == ${DRBD_ID[@]} ==
+		: == DEBUG == DRBD_VOLUME    == ${DRBD_VOLUME[@]} ==
+	fi
 	: == DEBUG == DRBD_ROLE_LOCAL    == "${DRBD_ROLE_LOCAL[@]}" ==
-	: == DEBUG == DRBD_ROLE_REMOTE   == "${DRBD_ROLE_REMOTE[@]}" ==
-	: == DEBUG == DRBD_CSTATE        == "${DRBD_CSTATE[@]}" ==
 	: == DEBUG == DRBD_DSTATE_LOCAL  == "${DRBD_DSTATE_LOCAL[@]}" ==
+	: == DEBUG == DRBD_CSTATE        == "${DRBD_CSTATE[@]}" ==
+	: == DEBUG == DRBD_ROLE_REMOTE   == "${DRBD_ROLE_REMOTE[@]}" ==
 	: == DEBUG == DRBD_DSTATE_REMOTE == "${DRBD_DSTATE_REMOTE[@]}" ==
 }
 
@@ -415,6 +470,9 @@
 	ocf_is_true $OCF_RESKEY_stop_outdates_secondary || return 1
 
 	local host stop_uname
+	if $DRBD_VERSION_9 ; then
+		local master temp_nmber outdate_self
+	fi
 	# We ignore $OCF_RESKEY_CRM_meta_notify_promote_uname here
 	# because: if demote and promote for a _stacked_ resource
 	# (or a "floating" one, where DRBD sits on top of some SAN)
@@ -438,6 +496,29 @@
 		return 1
 	done
 
+	if $DRBD_VERSION_9 ; then
+		temp_name=($DRBD_NAME[@])
+		temp_dstate=($DRBD_DSTATE_REMOTE[@])
+		temp_number=${#temp_name[@]}
+		outdate_self=false
+
+		for master in $OCF_RESKEY_CRM_meta_notify_master_uname; do
+			for i in `seq 0 $((temp_number-1))`; do
+				if [[ ${temp_name[$i]} == "$master" ]] &&
+				  [[ ${temp_dstate[$i]} == "DUnknown" ]]; then
+					outdate_self=true
+					break
+				fi
+			done
+			temp_number=${#temp_name[@]}
+		done
+
+		if ! $outdate_self; then
+			#The disconnecting node is not in Primary
+			return 1
+		fi
+    fi
+
 	# e.g. post/promote of some other peer.
 	# Should not happen, fencing constraints should take care of that.
 	# But in case it does, scream out loud.
@@ -1020,6 +1101,7 @@
 	DRBDADM="drbdadm"
 	DRBDSETUP="drbdsetup"
 	DRBD_HAS_MULTI_VOLUME=false
+	DRBD_VERSION_9=false
 
 	# these will _exit_ if they don't find the binaries
 	check_binary $DRBDADM
@@ -1046,15 +1128,25 @@
 		DRBD_HAS_MULTI_VOLUME=true
 	fi
 	if (( $DRBD_KERNEL_VERSION_CODE >= 0x090000 )) ; then
-		ocf_log err "This resource agent does (still) only support DRBD version 8.x"
-		exit $OCF_ERR_INSTALLED
+		DRBD_HAS_MULTI_VOLUME=true
+		DRBD_VERSION_9=true
 	fi
 	check_crm_feature_set
 
 	# Check clone and M/S options.
-	meta_expect clone-max -le 2
+	# Drbd9 support more than two nodes
+	if ! $DRBD_VERSION_9 ; then
+		meta_expect clone-max -le 2
+	fi
+
+	if [ ${OCF_RESKEY_CRM_meta_clone_max} -gt 2 ]
+	then
+		ocf_log warn "SUSE only supports two nodes, although it is technically feasible to use more than two."
+	fi
+
 	meta_expect clone-node-max = 1
 	meta_expect master-node-max = 1
+	# With current DRBD-9.0 version more than two primaries at the same time is not support.
 	meta_expect master-max -le 2
 
 	# Rather than returning $OCF_ERR_CONFIGURED, we sometimes return
@@ -1108,7 +1200,12 @@
 	# DRBD_DEVICES will be a shell array!
 	# FIXME we should double check that we explicitly restrict the set of
 	# valid characters in device names...
-	if DRBD_DEVICES=($($DRBDADM --stacked sh-dev $DRBD_RESOURCE 2>/dev/null)); then
+	# In DRBD9, no matter stacked or not "$DRBDADM --stacked sh-dev $DRBD_RESOURCE" will return true
+	if $DRBD_VERSION_9 && ! $($DRBDADM --stacked sh-dev $DRBD_RESOURCE 2>&1|
+		grep "not available in stacked" >/dev/null); then
+		DRBD_DEVICES=($($DRBDADM --stacked sh-dev $DRBD_RESOURCE 2>/dev/null))
+		DRBDADM="$DRBDADM -S"
+	elif ! $DRBD_VERSION_9 && DRBD_DEVICES=($($DRBDADM --stacked sh-dev $DRBD_RESOURCE 2>/dev/null)); then
 		# apparently a "stacked" resource. Remember for future DRBDADM calls.
 		DRBDADM="$DRBDADM -S"
 	elif DRBD_DEVICES=($($DRBDADM sh-dev $DRBD_RESOURCE 2>/dev/null)); then
diff -Naur drbd-utils-8.9.9.orig/user/v9/drbdsetup.c drbd-utils-8.9.9/user/v9/drbdsetup.c
--- drbd-utils-8.9.9.orig/user/v9/drbdsetup.c	2016-10-26 10:55:38.210292487 +0800
+++ drbd-utils-8.9.9/user/v9/drbdsetup.c	2016-10-26 10:58:09.041778235 +0800
@@ -255,6 +255,7 @@
 static int show_cmd(struct drbd_cmd *cm, int argc, char **argv);
 static int status_cmd(struct drbd_cmd *cm, int argc, char **argv);
 static int role_cmd(struct drbd_cmd *cm, int argc, char **argv);
+static int sh_status_9compat_cmd(struct drbd_cmd *cm, int argc, char **argv);
 static int cstate_cmd(struct drbd_cmd *cm, int argc, char **argv);
 static int dstate_cmd(struct drbd_cmd *cm, int argc, char **argv);
 static int check_resize_cmd(struct drbd_cmd *cm, int argc, char **argv);
@@ -483,6 +484,9 @@
 	{"role", CTX_RESOURCE, 0, NO_PAYLOAD, role_cmd,
 	 .lockless = true,
 	 .summary = "Show the current role of a resource." },
+	{"sh-status", CTX_RESOURCE | CTX_ALL, 0, 0, sh_status_9compat_cmd,
+	 .lockless = true,
+	 .summary = "Show all status of resource." },
 	{"cstate", CTX_PEER_NODE, 0, NO_PAYLOAD, cstate_cmd,
 	 .lockless = true,
 	 .summary = "Show the current state of a connection." },
@@ -2786,6 +2790,87 @@
 	return 0;
 }
 
+
+static int sh_status_9compat_cmd(struct drbd_cmd *cm, int argc, char **argv)
+{
+
+	struct resources_list *resources_list, *resource;
+	char *old_objname = objname;
+
+	resources_list = sort_resources(list_resources());
+
+	for (resource = resources_list; resource; resource = resource->next) {
+		struct devices_list *devices, *device;
+		struct connections_list *connections, *connection;
+		struct peer_devices_list *peer_devices = NULL, *peer_device;
+		struct nlattr *nla;
+
+		if (strcmp(old_objname, "all") && strcmp(old_objname, resource->name))
+			continue;
+
+		objname = resource->name;
+		printI("_res_name=%s\n", objname);
+
+		nla = nla_find_nested(resource->res_opts, __nla_type(T_node_id));
+		if (nla)
+			printI("_node_id=%d\n\n", *(uint32_t *)nla_data(nla));
+		else
+			printI("_node_id=\n\n");
+
+		devices = list_devices(resource->name);
+		connections = sort_connections(list_connections(resource->name));
+		if (devices && connections)
+			peer_devices = list_peer_devices(resource->name);
+
+		link_peer_devices_to_devices(peer_devices, devices);
+
+		for (device = devices; device; device = device->next) {
+			++indent;
+			printI("_minor=%d\n", device->minor);
+			printI("_volume=%d\n", device->ctx.ctx_volume);
+			//refer to v84
+			//printI("_known=%s\n", xxx);
+			printI("_role=%s\n", drbd_role_str(resource->info.res_role));
+			printI("_disk=%s\n\n", drbd_disk_str(device->info.dev_disk_state));
+
+			for (connection = connections; connection; connection = connection->next) {
+				++indent;
+				for (peer_device = peer_devices; peer_device; peer_device = peer_device->next) {
+					if (connection->ctx.ctx_peer_node_id != peer_device->ctx.ctx_peer_node_id
+						|| device->ctx.ctx_volume != peer_device->ctx.ctx_volume)
+						continue;
+					printI("_conn_name=%s\n", connection->ctx.ctx_conn_name);
+					printI("_peer_node_id=%d\n", connection->ctx.ctx_peer_node_id);
+					printI("_cstate=%s\n", drbd_conn_str(connection->info.conn_connection_state));
+					if (connection->info.conn_connection_state == C_CONNECTED) {
+						printI("_peer=%s\n", drbd_role_str(connection->info.conn_role));
+						printI("_pdsk=%s\n\n", drbd_disk_str(peer_device->info.peer_disk_state));
+					} else {
+						printI("_peer=\n");
+						printI("_pdsk=\n");
+					}
+					wrap_printf(0, "_peer_node_process\n\n");
+				}
+				//Dummy
+				//printI("_flags_susp==%s\n", xxx);
+				//...
+				--indent;
+			}
+
+			wrap_printf(0, "_sh_status_process\n\n");
+			--indent;
+		}
+
+		free_connections(connections);
+		free_devices(devices);
+		free_peer_devices(peer_devices);
+	}
+
+	free(resources_list);
+	objname = old_objname;
+	return 0;
+}
+
 static int cstate_cmd(struct drbd_cmd *cm, int argc, char **argv)
 {
 	struct connections_list *connections, *connection;
