aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_transport_iscsi.c
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2006-04-06 22:13:36 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-04-14 15:03:41 -0400
commitfd7255f51a13ea915099c7e488001dfbbeb05104 (patch)
tree964624f68f000848dae1a9f4c396502849707826 /drivers/scsi/scsi_transport_iscsi.c
parentb5c7a12dc29ae0990d9e867749bdd717a3160325 (diff)
[SCSI] iscsi: add sysfs attrs for uspace sync up
For iscsi boot when going from initramfs to the real root we need to stop the userpsace iscsi daemon. To later restart it iscsid needs to be able to rebuild itself and part of that process is matching a session running the kernel with the iscsid representation. To do this the attached patch adds several required iscsi values. If the LLD does not provide them becuase, login is done in userspace, then the transport class and userspace set ths up for the LLD. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/scsi_transport_iscsi.c')
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c262
1 files changed, 208 insertions, 54 deletions
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 10ff0f0210ba..72a71ebc9d03 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -31,21 +31,13 @@
31#include <scsi/scsi_transport_iscsi.h> 31#include <scsi/scsi_transport_iscsi.h>
32#include <scsi/iscsi_if.h> 32#include <scsi/iscsi_if.h>
33 33
34#define ISCSI_SESSION_ATTRS 8 34#define ISCSI_SESSION_ATTRS 10
35#define ISCSI_CONN_ATTRS 6 35#define ISCSI_CONN_ATTRS 10
36 36
37struct iscsi_internal { 37struct iscsi_internal {
38 struct scsi_transport_template t; 38 struct scsi_transport_template t;
39 struct iscsi_transport *iscsi_transport; 39 struct iscsi_transport *iscsi_transport;
40 struct list_head list; 40 struct list_head list;
41 /*
42 * based on transport capabilities, at register time we set these
43 * bits to tell the transport class it wants attributes displayed
44 * in sysfs or that it can support different iSCSI Data-Path
45 * capabilities
46 */
47 uint32_t param_mask;
48
49 struct class_device cdev; 41 struct class_device cdev;
50 /* 42 /*
51 * We do not have any private or other attrs. 43 * We do not have any private or other attrs.
@@ -223,6 +215,7 @@ static void iscsi_session_release(struct device *dev)
223 215
224 shost = iscsi_session_to_shost(session); 216 shost = iscsi_session_to_shost(session);
225 scsi_host_put(shost); 217 scsi_host_put(shost);
218 kfree(session->targetname);
226 kfree(session); 219 kfree(session);
227 module_put(transport->owner); 220 module_put(transport->owner);
228} 221}
@@ -304,6 +297,7 @@ static void iscsi_conn_release(struct device *dev)
304 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); 297 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
305 struct device *parent = conn->dev.parent; 298 struct device *parent = conn->dev.parent;
306 299
300 kfree(conn->persistent_address);
307 kfree(conn); 301 kfree(conn);
308 put_device(parent); 302 put_device(parent);
309} 303}
@@ -870,6 +864,67 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev
870 return 0; 864 return 0;
871} 865}
872 866
867static void
868iscsi_copy_param(struct iscsi_uevent *ev, uint32_t *value, char *data)
869{
870 if (ev->u.set_param.len != sizeof(uint32_t))
871 BUG();
872 memcpy(value, data, min_t(uint32_t, sizeof(uint32_t),
873 ev->u.set_param.len));
874}
875
876static int
877iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
878{
879 char *data = (char*)ev + sizeof(*ev);
880 struct iscsi_cls_conn *conn;
881 struct iscsi_cls_session *session;
882 int err = 0;
883 uint32_t value = 0;
884
885 session = iscsi_session_lookup(ev->u.set_param.sid);
886 conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid);
887 if (!conn || !session)
888 return -EINVAL;
889
890 switch (ev->u.set_param.param) {
891 case ISCSI_PARAM_TARGET_NAME:
892 /* this should not change between logins */
893 if (session->targetname)
894 return 0;
895
896 session->targetname = kstrdup(data, GFP_KERNEL);
897 if (!session->targetname)
898 return -ENOMEM;
899 break;
900 case ISCSI_PARAM_TPGT:
901 iscsi_copy_param(ev, &value, data);
902 session->tpgt = value;
903 break;
904 case ISCSI_PARAM_PERSISTENT_PORT:
905 iscsi_copy_param(ev, &value, data);
906 conn->persistent_port = value;
907 break;
908 case ISCSI_PARAM_PERSISTENT_ADDRESS:
909 /*
910 * this is the address returned in discovery so it should
911 * not change between logins.
912 */
913 if (conn->persistent_address)
914 return 0;
915
916 conn->persistent_address = kstrdup(data, GFP_KERNEL);
917 if (!conn->persistent_address)
918 return -ENOMEM;
919 break;
920 default:
921 iscsi_copy_param(ev, &value, data);
922 err = transport->set_param(conn, ev->u.set_param.param, value);
923 }
924
925 return err;
926}
927
873static int 928static int
874iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 929iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
875{ 930{
@@ -917,12 +972,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
917 err = -EINVAL; 972 err = -EINVAL;
918 break; 973 break;
919 case ISCSI_UEVENT_SET_PARAM: 974 case ISCSI_UEVENT_SET_PARAM:
920 conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid); 975 err = iscsi_set_param(transport, ev);
921 if (conn)
922 ev->r.retcode = transport->set_param(conn,
923 ev->u.set_param.param, ev->u.set_param.value);
924 else
925 err = -EINVAL;
926 break; 976 break;
927 case ISCSI_UEVENT_START_CONN: 977 case ISCSI_UEVENT_START_CONN:
928 conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid); 978 conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid);
@@ -1028,6 +1078,10 @@ free_skb:
1028#define iscsi_cdev_to_conn(_cdev) \ 1078#define iscsi_cdev_to_conn(_cdev) \
1029 iscsi_dev_to_conn(_cdev->dev) 1079 iscsi_dev_to_conn(_cdev->dev)
1030 1080
1081#define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \
1082struct class_device_attribute class_device_attr_##_prefix##_##_name = \
1083 __ATTR(_name,_mode,_show,_store)
1084
1031/* 1085/*
1032 * iSCSI connection attrs 1086 * iSCSI connection attrs
1033 */ 1087 */
@@ -1045,7 +1099,8 @@ show_conn_int_param_##param(struct class_device *cdev, char *buf) \
1045 1099
1046#define iscsi_conn_int_attr(field, param, format) \ 1100#define iscsi_conn_int_attr(field, param, format) \
1047 iscsi_conn_int_attr_show(param, format) \ 1101 iscsi_conn_int_attr_show(param, format) \
1048static CLASS_DEVICE_ATTR(field, S_IRUGO, show_conn_int_param_##param, NULL); 1102static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_int_param_##param, \
1103 NULL);
1049 1104
1050iscsi_conn_int_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH, "%u"); 1105iscsi_conn_int_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH, "%u");
1051iscsi_conn_int_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH, "%u"); 1106iscsi_conn_int_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH, "%u");
@@ -1053,6 +1108,25 @@ iscsi_conn_int_attr(header_digest, ISCSI_PARAM_HDRDGST_EN, "%d");
1053iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d"); 1108iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d");
1054iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d"); 1109iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d");
1055iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d"); 1110iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d");
1111iscsi_conn_int_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT, "%d");
1112iscsi_conn_int_attr(port, ISCSI_PARAM_CONN_PORT, "%d");
1113
1114#define iscsi_conn_str_attr_show(param) \
1115static ssize_t \
1116show_conn_str_param_##param(struct class_device *cdev, char *buf) \
1117{ \
1118 struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
1119 struct iscsi_transport *t = conn->transport; \
1120 return t->get_conn_str_param(conn, param, buf); \
1121}
1122
1123#define iscsi_conn_str_attr(field, param) \
1124 iscsi_conn_str_attr_show(param) \
1125static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_str_param_##param, \
1126 NULL);
1127
1128iscsi_conn_str_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
1129iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS);
1056 1130
1057#define iscsi_cdev_to_session(_cdev) \ 1131#define iscsi_cdev_to_session(_cdev) \
1058 iscsi_dev_to_session(_cdev->dev) 1132 iscsi_dev_to_session(_cdev->dev)
@@ -1074,7 +1148,8 @@ show_session_int_param_##param(struct class_device *cdev, char *buf) \
1074 1148
1075#define iscsi_session_int_attr(field, param, format) \ 1149#define iscsi_session_int_attr(field, param, format) \
1076 iscsi_session_int_attr_show(param, format) \ 1150 iscsi_session_int_attr_show(param, format) \
1077static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_int_param_##param, NULL); 1151static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_int_param_##param, \
1152 NULL);
1078 1153
1079iscsi_session_int_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, "%d"); 1154iscsi_session_int_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, "%d");
1080iscsi_session_int_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, "%hu"); 1155iscsi_session_int_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, "%hu");
@@ -1084,18 +1159,88 @@ iscsi_session_int_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, "%u");
1084iscsi_session_int_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, "%d"); 1159iscsi_session_int_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, "%d");
1085iscsi_session_int_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, "%d"); 1160iscsi_session_int_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, "%d");
1086iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d"); 1161iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d");
1162iscsi_session_int_attr(tpgt, ISCSI_PARAM_TPGT, "%d");
1087 1163
1088#define SETUP_SESSION_RD_ATTR(field, param) \ 1164#define iscsi_session_str_attr_show(param) \
1089 if (priv->param_mask & (1 << param)) { \ 1165static ssize_t \
1090 priv->session_attrs[count] = &class_device_attr_##field;\ 1166show_session_str_param_##param(struct class_device *cdev, char *buf) \
1091 count++; \ 1167{ \
1092 } 1168 struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
1169 struct iscsi_transport *t = session->transport; \
1170 return t->get_session_str_param(session, param, buf); \
1171}
1172
1173#define iscsi_session_str_attr(field, param) \
1174 iscsi_session_str_attr_show(param) \
1175static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_str_param_##param, \
1176 NULL);
1177
1178iscsi_session_str_attr(targetname, ISCSI_PARAM_TARGET_NAME);
1093 1179
1094#define SETUP_CONN_RD_ATTR(field, param) \ 1180/*
1095 if (priv->param_mask & (1 << param)) { \ 1181 * Private session and conn attrs. userspace uses several iscsi values
1096 priv->conn_attrs[count] = &class_device_attr_##field; \ 1182 * to identify each session between reboots. Some of these values may not
1183 * be present in the iscsi_transport/LLD driver becuase userspace handles
1184 * login (and failback for login redirect) so for these type of drivers
1185 * the class manages the attrs and values for the iscsi_transport/LLD
1186 */
1187#define iscsi_priv_session_attr_show(field, format) \
1188static ssize_t \
1189show_priv_session_##field(struct class_device *cdev, char *buf) \
1190{ \
1191 struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
1192 return sprintf(buf, format"\n", session->field); \
1193}
1194
1195#define iscsi_priv_session_attr(field, format) \
1196 iscsi_priv_session_attr_show(field, format) \
1197static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \
1198 NULL)
1199iscsi_priv_session_attr(targetname, "%s");
1200iscsi_priv_session_attr(tpgt, "%d");
1201
1202#define iscsi_priv_conn_attr_show(field, format) \
1203static ssize_t \
1204show_priv_conn_##field(struct class_device *cdev, char *buf) \
1205{ \
1206 struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
1207 return sprintf(buf, format"\n", conn->field); \
1208}
1209
1210#define iscsi_priv_conn_attr(field, format) \
1211 iscsi_priv_conn_attr_show(field, format) \
1212static ISCSI_CLASS_ATTR(priv_conn, field, S_IRUGO, show_priv_conn_##field, \
1213 NULL)
1214iscsi_priv_conn_attr(persistent_address, "%s");
1215iscsi_priv_conn_attr(persistent_port, "%d");
1216
1217#define SETUP_PRIV_SESSION_RD_ATTR(field) \
1218do { \
1219 priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
1220 count++; \
1221} while (0)
1222
1223#define SETUP_SESSION_RD_ATTR(field, param_flag) \
1224do { \
1225 if (tt->param_mask & param_flag) { \
1226 priv->session_attrs[count] = &class_device_attr_sess_##field; \
1097 count++; \ 1227 count++; \
1098 } 1228 } \
1229} while (0)
1230
1231#define SETUP_PRIV_CONN_RD_ATTR(field) \
1232do { \
1233 priv->conn_attrs[count] = &class_device_attr_priv_conn_##field; \
1234 count++; \
1235} while (0)
1236
1237#define SETUP_CONN_RD_ATTR(field, param_flag) \
1238do { \
1239 if (tt->param_mask & param_flag) { \
1240 priv->conn_attrs[count] = &class_device_attr_conn_##field; \
1241 count++; \
1242 } \
1243} while (0)
1099 1244
1100static int iscsi_session_match(struct attribute_container *cont, 1245static int iscsi_session_match(struct attribute_container *cont,
1101 struct device *dev) 1246 struct device *dev)
@@ -1173,31 +1318,30 @@ iscsi_register_transport(struct iscsi_transport *tt)
1173 if (err) 1318 if (err)
1174 goto unregister_cdev; 1319 goto unregister_cdev;
1175 1320
1176 /* setup parameters mask */
1177 priv->param_mask = 0xFFFFFFFF;
1178 if (!(tt->caps & CAP_MULTI_R2T))
1179 priv->param_mask &= ~(1 << ISCSI_PARAM_MAX_R2T);
1180 if (!(tt->caps & CAP_HDRDGST))
1181 priv->param_mask &= ~(1 << ISCSI_PARAM_HDRDGST_EN);
1182 if (!(tt->caps & CAP_DATADGST))
1183 priv->param_mask &= ~(1 << ISCSI_PARAM_DATADGST_EN);
1184 if (!(tt->caps & CAP_MARKERS)) {
1185 priv->param_mask &= ~(1 << ISCSI_PARAM_IFMARKER_EN);
1186 priv->param_mask &= ~(1 << ISCSI_PARAM_OFMARKER_EN);
1187 }
1188
1189 /* connection parameters */ 1321 /* connection parameters */
1190 priv->conn_cont.ac.attrs = &priv->conn_attrs[0]; 1322 priv->conn_cont.ac.attrs = &priv->conn_attrs[0];
1191 priv->conn_cont.ac.class = &iscsi_connection_class.class; 1323 priv->conn_cont.ac.class = &iscsi_connection_class.class;
1192 priv->conn_cont.ac.match = iscsi_conn_match; 1324 priv->conn_cont.ac.match = iscsi_conn_match;
1193 transport_container_register(&priv->conn_cont); 1325 transport_container_register(&priv->conn_cont);
1194 1326
1195 SETUP_CONN_RD_ATTR(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH); 1327 SETUP_CONN_RD_ATTR(max_recv_dlength, ISCSI_MAX_RECV_DLENGTH);
1196 SETUP_CONN_RD_ATTR(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH); 1328 SETUP_CONN_RD_ATTR(max_xmit_dlength, ISCSI_MAX_XMIT_DLENGTH);
1197 SETUP_CONN_RD_ATTR(header_digest, ISCSI_PARAM_HDRDGST_EN); 1329 SETUP_CONN_RD_ATTR(header_digest, ISCSI_HDRDGST_EN);
1198 SETUP_CONN_RD_ATTR(data_digest, ISCSI_PARAM_DATADGST_EN); 1330 SETUP_CONN_RD_ATTR(data_digest, ISCSI_DATADGST_EN);
1199 SETUP_CONN_RD_ATTR(ifmarker, ISCSI_PARAM_IFMARKER_EN); 1331 SETUP_CONN_RD_ATTR(ifmarker, ISCSI_IFMARKER_EN);
1200 SETUP_CONN_RD_ATTR(ofmarker, ISCSI_PARAM_OFMARKER_EN); 1332 SETUP_CONN_RD_ATTR(ofmarker, ISCSI_OFMARKER_EN);
1333 SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS);
1334 SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT);
1335
1336 if (tt->param_mask & ISCSI_PERSISTENT_ADDRESS)
1337 SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
1338 else
1339 SETUP_PRIV_CONN_RD_ATTR(persistent_address);
1340
1341 if (tt->param_mask & ISCSI_PERSISTENT_PORT)
1342 SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
1343 else
1344 SETUP_PRIV_CONN_RD_ATTR(persistent_port);
1201 1345
1202 BUG_ON(count > ISCSI_CONN_ATTRS); 1346 BUG_ON(count > ISCSI_CONN_ATTRS);
1203 priv->conn_attrs[count] = NULL; 1347 priv->conn_attrs[count] = NULL;
@@ -1209,14 +1353,24 @@ iscsi_register_transport(struct iscsi_transport *tt)
1209 priv->session_cont.ac.match = iscsi_session_match; 1353 priv->session_cont.ac.match = iscsi_session_match;
1210 transport_container_register(&priv->session_cont); 1354 transport_container_register(&priv->session_cont);
1211 1355
1212 SETUP_SESSION_RD_ATTR(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN); 1356 SETUP_SESSION_RD_ATTR(initial_r2t, ISCSI_INITIAL_R2T_EN);
1213 SETUP_SESSION_RD_ATTR(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T); 1357 SETUP_SESSION_RD_ATTR(max_outstanding_r2t, ISCSI_MAX_R2T);
1214 SETUP_SESSION_RD_ATTR(immediate_data, ISCSI_PARAM_IMM_DATA_EN); 1358 SETUP_SESSION_RD_ATTR(immediate_data, ISCSI_IMM_DATA_EN);
1215 SETUP_SESSION_RD_ATTR(first_burst_len, ISCSI_PARAM_FIRST_BURST); 1359 SETUP_SESSION_RD_ATTR(first_burst_len, ISCSI_FIRST_BURST);
1216 SETUP_SESSION_RD_ATTR(max_burst_len, ISCSI_PARAM_MAX_BURST); 1360 SETUP_SESSION_RD_ATTR(max_burst_len, ISCSI_MAX_BURST);
1217 SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN); 1361 SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN);
1218 SETUP_SESSION_RD_ATTR(data_seq_in_order,ISCSI_PARAM_DATASEQ_INORDER_EN) 1362 SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN);
1219 SETUP_SESSION_RD_ATTR(erl, ISCSI_PARAM_ERL); 1363 SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL);
1364
1365 if (tt->param_mask & ISCSI_TARGET_NAME)
1366 SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
1367 else
1368 SETUP_PRIV_SESSION_RD_ATTR(targetname);
1369
1370 if (tt->param_mask & ISCSI_TPGT)
1371 SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT);
1372 else
1373 SETUP_PRIV_SESSION_RD_ATTR(tpgt);
1220 1374
1221 BUG_ON(count > ISCSI_SESSION_ATTRS); 1375 BUG_ON(count > ISCSI_SESSION_ATTRS);
1222 priv->session_attrs[count] = NULL; 1376 priv->session_attrs[count] = NULL;