[SCSI] iscsi cls: sysfs group is_visible callout for conn attrs

The iscsi class currently does not support writable sysfs
attrs for LLD sysfs settings. This patch converts the
iscsi class and drivers to use the attribute container
sysfs group and the sysfs group's is_visible callout
to be able to support readable or writable sysfs attrs.

Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 3cad106..87b7ae1 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -733,3 +733,28 @@
 	beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
 	iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
 }
+
+mode_t be2iscsi_attr_is_visible(int param_type, int param)
+{
+	switch (param_type) {
+	case ISCSI_PARAM:
+		switch (param) {
+		case ISCSI_PARAM_MAX_RECV_DLENGTH:
+		case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+		case ISCSI_PARAM_HDRDGST_EN:
+		case ISCSI_PARAM_DATADGST_EN:
+		case ISCSI_PARAM_CONN_ADDRESS:
+		case ISCSI_PARAM_CONN_PORT:
+		case ISCSI_PARAM_EXP_STATSN:
+		case ISCSI_PARAM_PERSISTENT_ADDRESS:
+		case ISCSI_PARAM_PERSISTENT_PORT:
+		case ISCSI_PARAM_PING_TMO:
+		case ISCSI_PARAM_RECV_TMO:
+			return S_IRUGO;
+		default:
+			return 0;
+		}
+	}
+
+	return 0;
+}
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
index ff60b7f..4a1f2e3 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.h
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -26,6 +26,8 @@
 #define BE2_IPV4  0x1
 #define BE2_IPV6  0x10
 
+mode_t be2iscsi_attr_is_visible(int param_type, int param);
+
 void beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
 				struct beiscsi_offload_params *params);
 
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 0a9bdfa..d2a3e4a 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -4364,10 +4364,7 @@
 	.name = DRV_NAME,
 	.caps = CAP_RECOVERY_L0 | CAP_HDRDGST | CAP_TEXT_NEGO |
 		CAP_MULTI_R2T | CAP_DATADGST | CAP_DATA_PATH_OFFLOAD,
-	.param_mask = ISCSI_MAX_RECV_DLENGTH |
-		ISCSI_MAX_XMIT_DLENGTH |
-		ISCSI_HDRDGST_EN |
-		ISCSI_DATADGST_EN |
+	.param_mask =
 		ISCSI_INITIAL_R2T_EN |
 		ISCSI_MAX_R2T |
 		ISCSI_IMM_DATA_EN |
@@ -4376,17 +4373,11 @@
 		ISCSI_PDU_INORDER_EN |
 		ISCSI_DATASEQ_INORDER_EN |
 		ISCSI_ERL |
-		ISCSI_CONN_PORT |
-		ISCSI_CONN_ADDRESS |
-		ISCSI_EXP_STATSN |
-		ISCSI_PERSISTENT_PORT |
-		ISCSI_PERSISTENT_ADDRESS |
 		ISCSI_TARGET_NAME | ISCSI_TPGT |
 		ISCSI_USERNAME | ISCSI_PASSWORD |
 		ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
 		ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
 		ISCSI_LU_RESET_TMO |
-		ISCSI_PING_TMO | ISCSI_RECV_TMO |
 		ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
 	.host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
 				ISCSI_HOST_INITIATOR_NAME,
@@ -4395,6 +4386,7 @@
 	.create_conn = beiscsi_conn_create,
 	.bind_conn = beiscsi_conn_bind,
 	.destroy_conn = iscsi_conn_teardown,
+	.attr_is_visible = be2iscsi_attr_is_visible,
 	.set_param = beiscsi_set_param,
 	.get_conn_param = iscsi_conn_get_param,
 	.get_session_param = iscsi_session_get_param,
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index cffd4d7..2d529c9 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -2177,6 +2177,30 @@
 	return 0;
 }
 
+static mode_t bnx2i_attr_is_visible(int param_type, int param)
+{
+	switch (param_type) {
+	case ISCSI_PARAM:
+		switch (param) {
+		case ISCSI_PARAM_MAX_RECV_DLENGTH:
+		case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+		case ISCSI_PARAM_HDRDGST_EN:
+		case ISCSI_PARAM_DATADGST_EN:
+		case ISCSI_PARAM_CONN_ADDRESS:
+		case ISCSI_PARAM_CONN_PORT:
+		case ISCSI_PARAM_EXP_STATSN:
+		case ISCSI_PARAM_PERSISTENT_ADDRESS:
+		case ISCSI_PARAM_PERSISTENT_PORT:
+		case ISCSI_PARAM_PING_TMO:
+		case ISCSI_PARAM_RECV_TMO:
+			return S_IRUGO;
+		default:
+			return 0;
+		}
+	}
+
+	return 0;
+}
 
 /*
  * 'Scsi_Host_Template' structure and 'iscsi_tranport' structure template
@@ -2207,11 +2231,7 @@
 				  CAP_MULTI_R2T | CAP_DATADGST |
 				  CAP_DATA_PATH_OFFLOAD |
 				  CAP_TEXT_NEGO,
-	.param_mask		= ISCSI_MAX_RECV_DLENGTH |
-				  ISCSI_MAX_XMIT_DLENGTH |
-				  ISCSI_HDRDGST_EN |
-				  ISCSI_DATADGST_EN |
-				  ISCSI_INITIAL_R2T_EN |
+	.param_mask		= ISCSI_INITIAL_R2T_EN |
 				  ISCSI_MAX_R2T |
 				  ISCSI_IMM_DATA_EN |
 				  ISCSI_FIRST_BURST |
@@ -2219,17 +2239,11 @@
 				  ISCSI_PDU_INORDER_EN |
 				  ISCSI_DATASEQ_INORDER_EN |
 				  ISCSI_ERL |
-				  ISCSI_CONN_PORT |
-				  ISCSI_CONN_ADDRESS |
-				  ISCSI_EXP_STATSN |
-				  ISCSI_PERSISTENT_PORT |
-				  ISCSI_PERSISTENT_ADDRESS |
 				  ISCSI_TARGET_NAME | ISCSI_TPGT |
 				  ISCSI_USERNAME | ISCSI_PASSWORD |
 				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
 				  ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
 				  ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
-				  ISCSI_PING_TMO | ISCSI_RECV_TMO |
 				  ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
 	.host_param_mask	= ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
 				  ISCSI_HOST_NETDEV_NAME,
@@ -2238,6 +2252,7 @@
 	.create_conn		= bnx2i_conn_create,
 	.bind_conn		= bnx2i_conn_bind,
 	.destroy_conn		= bnx2i_conn_destroy,
+	.attr_is_visible	= bnx2i_attr_is_visible,
 	.set_param		= iscsi_set_param,
 	.get_conn_param		= iscsi_conn_get_param,
 	.get_session_param	= iscsi_session_get_param,
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index bd22041..c13b3f0 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -106,25 +106,21 @@
 	.caps		= CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST
 				| CAP_DATADGST | CAP_DIGEST_OFFLOAD |
 				CAP_PADDING_OFFLOAD | CAP_TEXT_NEGO,
-	.param_mask	= ISCSI_MAX_RECV_DLENGTH | ISCSI_MAX_XMIT_DLENGTH |
-				ISCSI_HDRDGST_EN | ISCSI_DATADGST_EN |
+	.param_mask	=
 				ISCSI_INITIAL_R2T_EN | ISCSI_MAX_R2T |
 				ISCSI_IMM_DATA_EN | ISCSI_FIRST_BURST |
 				ISCSI_MAX_BURST | ISCSI_PDU_INORDER_EN |
 				ISCSI_DATASEQ_INORDER_EN | ISCSI_ERL |
-				ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS |
-				ISCSI_EXP_STATSN | ISCSI_PERSISTENT_PORT |
-				ISCSI_PERSISTENT_ADDRESS |
 				ISCSI_TARGET_NAME | ISCSI_TPGT |
 				ISCSI_USERNAME | ISCSI_PASSWORD |
 				ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
 				ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
 				ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
-				ISCSI_PING_TMO | ISCSI_RECV_TMO |
 				ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
 	.host_param_mask	= ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
 				ISCSI_HOST_INITIATOR_NAME |
 				ISCSI_HOST_NETDEV_NAME,
+	.attr_is_visible	= cxgbi_attr_is_visible,
 	.get_host_param	= cxgbi_get_host_param,
 	.set_host_param	= cxgbi_set_host_param,
 	/* session management */
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index ae13c49..89fca4b 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -107,25 +107,21 @@
 	.caps		= CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST |
 				CAP_DATADGST | CAP_DIGEST_OFFLOAD |
 				CAP_PADDING_OFFLOAD | CAP_TEXT_NEGO,
-	.param_mask	= ISCSI_MAX_RECV_DLENGTH | ISCSI_MAX_XMIT_DLENGTH |
-				ISCSI_HDRDGST_EN | ISCSI_DATADGST_EN |
+	.param_mask	=
 				ISCSI_INITIAL_R2T_EN | ISCSI_MAX_R2T |
 				ISCSI_IMM_DATA_EN | ISCSI_FIRST_BURST |
 				ISCSI_MAX_BURST | ISCSI_PDU_INORDER_EN |
 				ISCSI_DATASEQ_INORDER_EN | ISCSI_ERL |
-				ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS |
-				ISCSI_EXP_STATSN | ISCSI_PERSISTENT_PORT |
-				ISCSI_PERSISTENT_ADDRESS |
 				ISCSI_TARGET_NAME | ISCSI_TPGT |
 				ISCSI_USERNAME | ISCSI_PASSWORD |
 				ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
 				ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
 				ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
-				ISCSI_PING_TMO | ISCSI_RECV_TMO |
 				ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
 	.host_param_mask	= ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
 				ISCSI_HOST_INITIATOR_NAME |
 				ISCSI_HOST_NETDEV_NAME,
+	.attr_is_visible	= cxgbi_attr_is_visible,
 	.get_host_param	= cxgbi_get_host_param,
 	.set_host_param	= cxgbi_set_host_param,
 	/* session management */
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 77ac217..e5f4f96 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -2566,6 +2566,32 @@
 }
 EXPORT_SYMBOL_GPL(cxgbi_iscsi_cleanup);
 
+mode_t cxgbi_attr_is_visible(int param_type, int param)
+{
+	switch (param_type) {
+	case ISCSI_PARAM:
+		switch (param) {
+		case ISCSI_PARAM_MAX_RECV_DLENGTH:
+		case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+		case ISCSI_PARAM_HDRDGST_EN:
+		case ISCSI_PARAM_DATADGST_EN:
+		case ISCSI_PARAM_CONN_ADDRESS:
+		case ISCSI_PARAM_CONN_PORT:
+		case ISCSI_PARAM_EXP_STATSN:
+		case ISCSI_PARAM_PERSISTENT_ADDRESS:
+		case ISCSI_PARAM_PERSISTENT_PORT:
+		case ISCSI_PARAM_PING_TMO:
+		case ISCSI_PARAM_RECV_TMO:
+			return S_IRUGO;
+		default:
+			return 0;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cxgbi_attr_is_visible);
+
 static int __init libcxgbi_init_module(void)
 {
 	sw_tag_idx_bits = (__ilog2_u32(ISCSI_ITT_MASK)) + 1;
diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h
index 9267844..5d453a0 100644
--- a/drivers/scsi/cxgbi/libcxgbi.h
+++ b/drivers/scsi/cxgbi/libcxgbi.h
@@ -709,6 +709,7 @@
 
 void cxgbi_cleanup_task(struct iscsi_task *task);
 
+mode_t cxgbi_attr_is_visible(int param_type, int param);
 void cxgbi_get_conn_stats(struct iscsi_cls_conn *, struct iscsi_stats *);
 int cxgbi_set_conn_param(struct iscsi_cls_conn *,
 			enum iscsi_param, char *, int);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 7724414..1dcb4d1 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -872,6 +872,31 @@
 	iscsi_host_free(shost);
 }
 
+static mode_t iscsi_sw_tcp_attr_is_visible(int param_type, int param)
+{
+	switch (param_type) {
+	case ISCSI_PARAM:
+		switch (param) {
+		case ISCSI_PARAM_MAX_RECV_DLENGTH:
+		case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+		case ISCSI_PARAM_HDRDGST_EN:
+		case ISCSI_PARAM_DATADGST_EN:
+		case ISCSI_PARAM_CONN_ADDRESS:
+		case ISCSI_PARAM_CONN_PORT:
+		case ISCSI_PARAM_EXP_STATSN:
+		case ISCSI_PARAM_PERSISTENT_ADDRESS:
+		case ISCSI_PARAM_PERSISTENT_PORT:
+		case ISCSI_PARAM_PING_TMO:
+		case ISCSI_PARAM_RECV_TMO:
+			return S_IRUGO;
+		default:
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
 static int iscsi_sw_tcp_slave_alloc(struct scsi_device *sdev)
 {
 	set_bit(QUEUE_FLAG_BIDI, &sdev->request_queue->queue_flags);
@@ -910,11 +935,7 @@
 	.name			= "tcp",
 	.caps			= CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST
 				  | CAP_DATADGST,
-	.param_mask		= ISCSI_MAX_RECV_DLENGTH |
-				  ISCSI_MAX_XMIT_DLENGTH |
-				  ISCSI_HDRDGST_EN |
-				  ISCSI_DATADGST_EN |
-				  ISCSI_INITIAL_R2T_EN |
+	.param_mask		= ISCSI_INITIAL_R2T_EN |
 				  ISCSI_MAX_R2T |
 				  ISCSI_IMM_DATA_EN |
 				  ISCSI_FIRST_BURST |
@@ -922,17 +943,11 @@
 				  ISCSI_PDU_INORDER_EN |
 				  ISCSI_DATASEQ_INORDER_EN |
 				  ISCSI_ERL |
-				  ISCSI_CONN_PORT |
-				  ISCSI_CONN_ADDRESS |
-				  ISCSI_EXP_STATSN |
-				  ISCSI_PERSISTENT_PORT |
-				  ISCSI_PERSISTENT_ADDRESS |
 				  ISCSI_TARGET_NAME | ISCSI_TPGT |
 				  ISCSI_USERNAME | ISCSI_PASSWORD |
 				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
 				  ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
 				  ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
-				  ISCSI_PING_TMO | ISCSI_RECV_TMO |
 				  ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
 	.host_param_mask	= ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
 				  ISCSI_HOST_INITIATOR_NAME |
@@ -944,6 +959,7 @@
 	.create_conn		= iscsi_sw_tcp_conn_create,
 	.bind_conn		= iscsi_sw_tcp_conn_bind,
 	.destroy_conn		= iscsi_sw_tcp_conn_destroy,
+	.attr_is_visible	= iscsi_sw_tcp_attr_is_visible,
 	.set_param		= iscsi_sw_tcp_conn_set_param,
 	.get_conn_param		= iscsi_sw_tcp_conn_get_param,
 	.get_session_param	= iscsi_session_get_param,
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 32df0c5..f8a1506 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -100,6 +100,7 @@
 static int qla4xxx_slave_configure(struct scsi_device *device);
 static void qla4xxx_slave_destroy(struct scsi_device *sdev);
 static void qla4xxx_scan_start(struct Scsi_Host *shost);
+static mode_t ql4_attr_is_visible(int param_type, int param);
 
 static struct qla4_8xxx_legacy_intr_set legacy_intr[] =
     QLA82XX_LEGACY_INTR_CONFIG;
@@ -137,8 +138,7 @@
 	.name			= DRIVER_NAME,
 	.caps			= CAP_FW_DB | CAP_SENDTARGETS_OFFLOAD |
 				  CAP_DATA_PATH_OFFLOAD,
-	.param_mask		= ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS |
-				  ISCSI_TARGET_NAME | ISCSI_TPGT |
+	.param_mask		= ISCSI_TARGET_NAME | ISCSI_TPGT |
 				  ISCSI_TARGET_ALIAS,
 	.host_param_mask	= ISCSI_HOST_HWADDRESS |
 				  ISCSI_HOST_IPADDRESS |
@@ -155,6 +155,7 @@
 				  ISCSI_NET_IPV6_LINKLOCAL_AUTOCFG |
 				  ISCSI_NET_IFACE_ENABLE,
 	.tgt_dscvr		= qla4xxx_tgt_dscvr,
+	.attr_is_visible	= ql4_attr_is_visible,
 	.get_conn_param		= qla4xxx_conn_get_param,
 	.get_session_param	= qla4xxx_sess_get_param,
 	.get_host_param		= qla4xxx_host_get_param,
@@ -165,6 +166,22 @@
 
 static struct scsi_transport_template *qla4xxx_scsi_transport;
 
+static mode_t ql4_attr_is_visible(int param_type, int param)
+{
+	switch (param_type) {
+	case ISCSI_PARAM:
+		switch (param) {
+		case ISCSI_PARAM_CONN_ADDRESS:
+		case ISCSI_PARAM_CONN_PORT:
+			return S_IRUGO;
+		default:
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
 static int qla4xxx_get_iface_param(struct iscsi_iface *iface,
 				   enum iscsi_param_type param_type,
 				   int param, char *buf)
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 4d5e64f..e9eca98 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -78,7 +78,6 @@
 
 	struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
 	struct transport_container conn_cont;
-	struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
 	struct transport_container session_cont;
 	struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
 };
@@ -2030,6 +2029,70 @@
 iscsi_conn_ep_attr(address, ISCSI_PARAM_CONN_ADDRESS);
 iscsi_conn_ep_attr(port, ISCSI_PARAM_CONN_PORT);
 
+static struct attribute *iscsi_conn_attrs[] = {
+	&dev_attr_conn_max_recv_dlength.attr,
+	&dev_attr_conn_max_xmit_dlength.attr,
+	&dev_attr_conn_header_digest.attr,
+	&dev_attr_conn_data_digest.attr,
+	&dev_attr_conn_ifmarker.attr,
+	&dev_attr_conn_ofmarker.attr,
+	&dev_attr_conn_address.attr,
+	&dev_attr_conn_port.attr,
+	&dev_attr_conn_exp_statsn.attr,
+	&dev_attr_conn_persistent_address.attr,
+	&dev_attr_conn_persistent_port.attr,
+	&dev_attr_conn_ping_tmo.attr,
+	&dev_attr_conn_recv_tmo.attr,
+	NULL,
+};
+
+static mode_t iscsi_conn_attr_is_visible(struct kobject *kobj,
+					 struct attribute *attr, int i)
+{
+	struct device *cdev = container_of(kobj, struct device, kobj);
+	struct iscsi_cls_conn *conn = transport_class_to_conn(cdev);
+	struct iscsi_transport *t = conn->transport;
+	int param;
+
+	if (attr == &dev_attr_conn_max_recv_dlength.attr)
+		param = ISCSI_PARAM_MAX_RECV_DLENGTH;
+	else if (attr == &dev_attr_conn_max_xmit_dlength.attr)
+		param = ISCSI_PARAM_MAX_XMIT_DLENGTH;
+	else if (attr == &dev_attr_conn_header_digest.attr)
+		param = ISCSI_PARAM_HDRDGST_EN;
+	else if (attr == &dev_attr_conn_data_digest.attr)
+		param = ISCSI_PARAM_DATADGST_EN;
+	else if (attr == &dev_attr_conn_ifmarker.attr)
+		param = ISCSI_PARAM_IFMARKER_EN;
+	else if (attr == &dev_attr_conn_ofmarker.attr)
+		param = ISCSI_PARAM_OFMARKER_EN;
+	else if (attr == &dev_attr_conn_address.attr)
+		param = ISCSI_PARAM_CONN_ADDRESS;
+	else if (attr == &dev_attr_conn_port.attr)
+		param = ISCSI_PARAM_CONN_PORT;
+	else if (attr == &dev_attr_conn_exp_statsn.attr)
+		param = ISCSI_PARAM_EXP_STATSN;
+	else if (attr == &dev_attr_conn_persistent_address.attr)
+		param = ISCSI_PARAM_PERSISTENT_ADDRESS;
+	else if (attr == &dev_attr_conn_persistent_port.attr)
+		param = ISCSI_PARAM_PERSISTENT_PORT;
+	else if (attr == &dev_attr_conn_ping_tmo.attr)
+		param = ISCSI_PARAM_PING_TMO;
+	else if (attr == &dev_attr_conn_recv_tmo.attr)
+		param = ISCSI_PARAM_RECV_TMO;
+	else {
+		WARN_ONCE(1, "Invalid conn attr");
+		return 0;
+	}
+
+	return t->attr_is_visible(ISCSI_PARAM, param);
+}
+
+static struct attribute_group iscsi_conn_group = {
+	.attrs = iscsi_conn_attrs,
+	.is_visible = iscsi_conn_attr_is_visible,
+};
+
 /*
  * iSCSI session attrs
  */
@@ -2171,14 +2234,6 @@
 	}								\
 } while (0)
 
-#define SETUP_CONN_RD_ATTR(field, param_flag)				\
-do {									\
-	if (tt->param_mask & param_flag) {				\
-		priv->conn_attrs[count] = &dev_attr_conn_##field; \
-		count++;						\
-	}								\
-} while (0)
-
 #define SETUP_HOST_RD_ATTR(field, param_flag)				\
 do {									\
 	if (tt->host_param_mask & param_flag) {				\
@@ -2299,29 +2354,11 @@
 	count = 0;
 
 	/* connection parameters */
-	priv->conn_cont.ac.attrs = &priv->conn_attrs[0];
 	priv->conn_cont.ac.class = &iscsi_connection_class.class;
 	priv->conn_cont.ac.match = iscsi_conn_match;
+	priv->conn_cont.ac.grp = &iscsi_conn_group;
 	transport_container_register(&priv->conn_cont);
 
-	SETUP_CONN_RD_ATTR(max_recv_dlength, ISCSI_MAX_RECV_DLENGTH);
-	SETUP_CONN_RD_ATTR(max_xmit_dlength, ISCSI_MAX_XMIT_DLENGTH);
-	SETUP_CONN_RD_ATTR(header_digest, ISCSI_HDRDGST_EN);
-	SETUP_CONN_RD_ATTR(data_digest, ISCSI_DATADGST_EN);
-	SETUP_CONN_RD_ATTR(ifmarker, ISCSI_IFMARKER_EN);
-	SETUP_CONN_RD_ATTR(ofmarker, ISCSI_OFMARKER_EN);
-	SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS);
-	SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT);
-	SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);
-	SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
-	SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
-	SETUP_CONN_RD_ATTR(ping_tmo, ISCSI_PING_TMO);
-	SETUP_CONN_RD_ATTR(recv_tmo, ISCSI_RECV_TMO);
-
-	BUG_ON(count > ISCSI_CONN_ATTRS);
-	priv->conn_attrs[count] = NULL;
-	count = 0;
-
 	/* session parameters */
 	priv->session_cont.ac.attrs = &priv->session_attrs[0];
 	priv->session_cont.ac.class = &iscsi_session_class.class;