aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2008-05-21 16:54:13 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-07-12 09:22:20 -0400
commitd82ff9be733a2e6da4f6c2ab4e9216f3f536503d (patch)
treeec02aa5148e8d9739683fb703732b7edbaf3b3ac
parent7970634b81a6e3561954517bca42615542c4535b (diff)
[SCSI] iscsi class: add endpoint class
Add sysfs representation for the endpoint, so userspace can match the host and session to the endpoint. This will allow us to set the host's parent correctly at host creation time. The next patches will convert tcp and iser, and fix iser's dma_mask bug. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c190
-rw-r--r--include/scsi/iscsi_if.h2
-rw-r--r--include/scsi/scsi_transport_iscsi.h19
3 files changed, 172 insertions, 39 deletions
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index ac9d298f54e7..c3c07ccccca7 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -33,6 +33,7 @@
33#define ISCSI_SESSION_ATTRS 19 33#define ISCSI_SESSION_ATTRS 19
34#define ISCSI_CONN_ATTRS 13 34#define ISCSI_CONN_ATTRS 13
35#define ISCSI_HOST_ATTRS 4 35#define ISCSI_HOST_ATTRS 4
36
36#define ISCSI_TRANSPORT_VERSION "2.0-869" 37#define ISCSI_TRANSPORT_VERSION "2.0-869"
37 38
38struct iscsi_internal { 39struct iscsi_internal {
@@ -112,6 +113,123 @@ static struct attribute_group iscsi_transport_group = {
112 .attrs = iscsi_transport_attrs, 113 .attrs = iscsi_transport_attrs,
113}; 114};
114 115
116/*
117 * iSCSI endpoint attrs
118 */
119#define iscsi_dev_to_endpoint(_dev) \
120 container_of(_dev, struct iscsi_endpoint, dev)
121
122#define ISCSI_ATTR(_prefix,_name,_mode,_show,_store) \
123struct device_attribute dev_attr_##_prefix##_##_name = \
124 __ATTR(_name,_mode,_show,_store)
125
126static void iscsi_endpoint_release(struct device *dev)
127{
128 struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
129 kfree(ep);
130}
131
132static struct class iscsi_endpoint_class = {
133 .name = "iscsi_endpoint",
134 .dev_release = iscsi_endpoint_release,
135};
136
137static ssize_t
138show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf)
139{
140 struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
141 return sprintf(buf, "%u\n", ep->id);
142}
143static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL);
144
145static struct attribute *iscsi_endpoint_attrs[] = {
146 &dev_attr_ep_handle.attr,
147 NULL,
148};
149
150static struct attribute_group iscsi_endpoint_group = {
151 .attrs = iscsi_endpoint_attrs,
152};
153
154#define ISCSI_MAX_EPID -1
155
156static int iscsi_match_epid(struct device *dev, void *data)
157{
158 struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
159 unsigned int *epid = (unsigned int *) data;
160
161 return *epid == ep->id;
162}
163
164struct iscsi_endpoint *
165iscsi_create_endpoint(int dd_size)
166{
167 struct device *dev;
168 struct iscsi_endpoint *ep;
169 unsigned int id;
170 int err;
171
172 for (id = 1; id < ISCSI_MAX_EPID; id++) {
173 dev = class_find_device(&iscsi_endpoint_class, &id,
174 iscsi_match_epid);
175 if (!dev)
176 break;
177 }
178 if (id == ISCSI_MAX_EPID) {
179 printk(KERN_ERR "Too many connections. Max supported %u\n",
180 ISCSI_MAX_EPID - 1);
181 return NULL;
182 }
183
184 ep = kzalloc(sizeof(*ep) + dd_size, GFP_KERNEL);
185 if (!ep)
186 return NULL;
187
188 ep->id = id;
189 ep->dev.class = &iscsi_endpoint_class;
190 snprintf(ep->dev.bus_id, BUS_ID_SIZE, "ep-%u", id);
191 err = device_register(&ep->dev);
192 if (err)
193 goto free_ep;
194
195 err = sysfs_create_group(&ep->dev.kobj, &iscsi_endpoint_group);
196 if (err)
197 goto unregister_dev;
198
199 if (dd_size)
200 ep->dd_data = &ep[1];
201 return ep;
202
203unregister_dev:
204 device_unregister(&ep->dev);
205 return NULL;
206
207free_ep:
208 kfree(ep);
209 return NULL;
210}
211EXPORT_SYMBOL_GPL(iscsi_create_endpoint);
212
213void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
214{
215 sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group);
216 device_unregister(&ep->dev);
217}
218EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint);
219
220struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
221{
222 struct device *dev;
223
224 dev = class_find_device(&iscsi_endpoint_class, &handle,
225 iscsi_match_epid);
226 if (!dev)
227 return NULL;
228
229 return iscsi_dev_to_endpoint(dev);
230}
231EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
232
115static int iscsi_setup_host(struct transport_container *tc, struct device *dev, 233static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
116 struct device *cdev) 234 struct device *cdev)
117{ 235{
@@ -1094,33 +1212,16 @@ int iscsi_session_event(struct iscsi_cls_session *session,
1094EXPORT_SYMBOL_GPL(iscsi_session_event); 1212EXPORT_SYMBOL_GPL(iscsi_session_event);
1095 1213
1096static int 1214static int
1097iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev, 1215iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep,
1098 uint32_t host_no, uint32_t initial_cmdsn, 1216 struct iscsi_uevent *ev, uint32_t initial_cmdsn,
1099 uint16_t cmds_max, uint16_t queue_depth) 1217 uint16_t cmds_max, uint16_t queue_depth)
1100{ 1218{
1101 struct iscsi_transport *transport = priv->iscsi_transport; 1219 struct iscsi_transport *transport = priv->iscsi_transport;
1102 struct iscsi_cls_session *session; 1220 struct iscsi_cls_session *session;
1103 struct Scsi_Host *shost = NULL; 1221 uint32_t host_no;
1104 1222
1105 /* 1223 session = transport->create_session(ep, cmds_max, queue_depth,
1106 * Software iscsi allocates a host per session, but
1107 * offload drivers (and possibly iser one day) allocate a host per
1108 * hba/nic/rnic. Offload will match a host here, but software will
1109 * return a new hostno after the create_session callback has returned.
1110 */
1111 if (host_no != UINT_MAX) {
1112 shost = scsi_host_lookup(host_no);
1113 if (IS_ERR(shost)) {
1114 printk(KERN_ERR "Could not find host no %u to "
1115 "create session\n", host_no);
1116 return -ENODEV;
1117 }
1118 }
1119
1120 session = transport->create_session(shost, cmds_max, queue_depth,
1121 initial_cmdsn, &host_no); 1224 initial_cmdsn, &host_no);
1122 if (shost)
1123 scsi_host_put(shost);
1124 if (!session) 1225 if (!session)
1125 return -ENOMEM; 1226 return -ENOMEM;
1126 1227
@@ -1199,6 +1300,7 @@ static int
1199iscsi_if_transport_ep(struct iscsi_transport *transport, 1300iscsi_if_transport_ep(struct iscsi_transport *transport,
1200 struct iscsi_uevent *ev, int msg_type) 1301 struct iscsi_uevent *ev, int msg_type)
1201{ 1302{
1303 struct iscsi_endpoint *ep;
1202 struct sockaddr *dst_addr; 1304 struct sockaddr *dst_addr;
1203 int rc = 0; 1305 int rc = 0;
1204 1306
@@ -1208,22 +1310,33 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
1208 return -EINVAL; 1310 return -EINVAL;
1209 1311
1210 dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); 1312 dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
1211 rc = transport->ep_connect(dst_addr, 1313 ep = transport->ep_connect(dst_addr,
1212 ev->u.ep_connect.non_blocking, 1314 ev->u.ep_connect.non_blocking);
1213 &ev->r.ep_connect_ret.handle); 1315 if (IS_ERR(ep))
1316 return PTR_ERR(ep);
1317
1318 ev->r.ep_connect_ret.handle = ep->id;
1214 break; 1319 break;
1215 case ISCSI_UEVENT_TRANSPORT_EP_POLL: 1320 case ISCSI_UEVENT_TRANSPORT_EP_POLL:
1216 if (!transport->ep_poll) 1321 if (!transport->ep_poll)
1217 return -EINVAL; 1322 return -EINVAL;
1218 1323
1219 ev->r.retcode = transport->ep_poll(ev->u.ep_poll.ep_handle, 1324 ep = iscsi_lookup_endpoint(ev->u.ep_poll.ep_handle);
1325 if (!ep)
1326 return -EINVAL;
1327
1328 ev->r.retcode = transport->ep_poll(ep,
1220 ev->u.ep_poll.timeout_ms); 1329 ev->u.ep_poll.timeout_ms);
1221 break; 1330 break;
1222 case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: 1331 case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
1223 if (!transport->ep_disconnect) 1332 if (!transport->ep_disconnect)
1224 return -EINVAL; 1333 return -EINVAL;
1225 1334
1226 transport->ep_disconnect(ev->u.ep_disconnect.ep_handle); 1335 ep = iscsi_lookup_endpoint(ev->u.ep_disconnect.ep_handle);
1336 if (!ep)
1337 return -EINVAL;
1338
1339 transport->ep_disconnect(ep);
1227 break; 1340 break;
1228 } 1341 }
1229 return rc; 1342 return rc;
@@ -1283,12 +1396,12 @@ static int
1283iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 1396iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1284{ 1397{
1285 int err = 0; 1398 int err = 0;
1286 uint32_t host_no = UINT_MAX;
1287 struct iscsi_uevent *ev = NLMSG_DATA(nlh); 1399 struct iscsi_uevent *ev = NLMSG_DATA(nlh);
1288 struct iscsi_transport *transport = NULL; 1400 struct iscsi_transport *transport = NULL;
1289 struct iscsi_internal *priv; 1401 struct iscsi_internal *priv;
1290 struct iscsi_cls_session *session; 1402 struct iscsi_cls_session *session;
1291 struct iscsi_cls_conn *conn; 1403 struct iscsi_cls_conn *conn;
1404 struct iscsi_endpoint *ep = NULL;
1292 1405
1293 priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); 1406 priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
1294 if (!priv) 1407 if (!priv)
@@ -1302,14 +1415,17 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1302 1415
1303 switch (nlh->nlmsg_type) { 1416 switch (nlh->nlmsg_type) {
1304 case ISCSI_UEVENT_CREATE_SESSION: 1417 case ISCSI_UEVENT_CREATE_SESSION:
1305 err = iscsi_if_create_session(priv, ev, host_no, 1418 err = iscsi_if_create_session(priv, ep, ev,
1306 ev->u.c_session.initial_cmdsn, 1419 ev->u.c_session.initial_cmdsn,
1307 ev->u.c_session.cmds_max, 1420 ev->u.c_session.cmds_max,
1308 ev->u.c_session.queue_depth); 1421 ev->u.c_session.queue_depth);
1309 break; 1422 break;
1310 case ISCSI_UEVENT_CREATE_BOUND_SESSION: 1423 case ISCSI_UEVENT_CREATE_BOUND_SESSION:
1311 err = iscsi_if_create_session(priv, ev, 1424 ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
1312 ev->u.c_bound_session.host_no, 1425 if (!ep)
1426 return -EINVAL;
1427
1428 err = iscsi_if_create_session(priv, ep, ev,
1313 ev->u.c_bound_session.initial_cmdsn, 1429 ev->u.c_bound_session.initial_cmdsn,
1314 ev->u.c_bound_session.cmds_max, 1430 ev->u.c_bound_session.cmds_max,
1315 ev->u.c_bound_session.queue_depth); 1431 ev->u.c_bound_session.queue_depth);
@@ -1774,6 +1890,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
1774 1890
1775unregister_dev: 1891unregister_dev:
1776 device_unregister(&priv->dev); 1892 device_unregister(&priv->dev);
1893 return NULL;
1777free_priv: 1894free_priv:
1778 kfree(priv); 1895 kfree(priv);
1779 return NULL; 1896 return NULL;
@@ -1821,10 +1938,14 @@ static __init int iscsi_transport_init(void)
1821 if (err) 1938 if (err)
1822 return err; 1939 return err;
1823 1940
1824 err = transport_class_register(&iscsi_host_class); 1941 err = class_register(&iscsi_endpoint_class);
1825 if (err) 1942 if (err)
1826 goto unregister_transport_class; 1943 goto unregister_transport_class;
1827 1944
1945 err = transport_class_register(&iscsi_host_class);
1946 if (err)
1947 goto unregister_endpoint_class;
1948
1828 err = transport_class_register(&iscsi_connection_class); 1949 err = transport_class_register(&iscsi_connection_class);
1829 if (err) 1950 if (err)
1830 goto unregister_host_class; 1951 goto unregister_host_class;
@@ -1833,8 +1954,8 @@ static __init int iscsi_transport_init(void)
1833 if (err) 1954 if (err)
1834 goto unregister_conn_class; 1955 goto unregister_conn_class;
1835 1956
1836 nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, NULL, 1957 nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx,
1837 THIS_MODULE); 1958 NULL, THIS_MODULE);
1838 if (!nls) { 1959 if (!nls) {
1839 err = -ENOBUFS; 1960 err = -ENOBUFS;
1840 goto unregister_session_class; 1961 goto unregister_session_class;
@@ -1854,6 +1975,8 @@ unregister_conn_class:
1854 transport_class_unregister(&iscsi_connection_class); 1975 transport_class_unregister(&iscsi_connection_class);
1855unregister_host_class: 1976unregister_host_class:
1856 transport_class_unregister(&iscsi_host_class); 1977 transport_class_unregister(&iscsi_host_class);
1978unregister_endpoint_class:
1979 class_unregister(&iscsi_endpoint_class);
1857unregister_transport_class: 1980unregister_transport_class:
1858 class_unregister(&iscsi_transport_class); 1981 class_unregister(&iscsi_transport_class);
1859 return err; 1982 return err;
@@ -1866,6 +1989,7 @@ static void __exit iscsi_transport_exit(void)
1866 transport_class_unregister(&iscsi_connection_class); 1989 transport_class_unregister(&iscsi_connection_class);
1867 transport_class_unregister(&iscsi_session_class); 1990 transport_class_unregister(&iscsi_session_class);
1868 transport_class_unregister(&iscsi_host_class); 1991 transport_class_unregister(&iscsi_host_class);
1992 class_unregister(&iscsi_endpoint_class);
1869 class_unregister(&iscsi_transport_class); 1993 class_unregister(&iscsi_transport_class);
1870} 1994}
1871 1995
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 801a677777cc..a0f13a280e71 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -80,7 +80,7 @@ struct iscsi_uevent {
80 uint16_t queue_depth; 80 uint16_t queue_depth;
81 } c_session; 81 } c_session;
82 struct msg_create_bound_session { 82 struct msg_create_bound_session {
83 uint32_t host_no; 83 uint64_t ep_handle;
84 uint32_t initial_cmdsn; 84 uint32_t initial_cmdsn;
85 uint16_t cmds_max; 85 uint16_t cmds_max;
86 uint16_t queue_depth; 86 uint16_t queue_depth;
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index d6b823195563..f5444e033cc9 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -30,6 +30,7 @@
30 30
31struct scsi_transport_template; 31struct scsi_transport_template;
32struct iscsi_transport; 32struct iscsi_transport;
33struct iscsi_endpoint;
33struct Scsi_Host; 34struct Scsi_Host;
34struct iscsi_cls_conn; 35struct iscsi_cls_conn;
35struct iscsi_conn; 36struct iscsi_conn;
@@ -85,7 +86,7 @@ struct iscsi_transport {
85 /* LLD sets this to indicate what values it can export to sysfs */ 86 /* LLD sets this to indicate what values it can export to sysfs */
86 uint64_t param_mask; 87 uint64_t param_mask;
87 uint64_t host_param_mask; 88 uint64_t host_param_mask;
88 struct iscsi_cls_session *(*create_session) (struct Scsi_Host *shost, 89 struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep,
89 uint16_t cmds_max, uint16_t qdepth, 90 uint16_t cmds_max, uint16_t qdepth,
90 uint32_t sn, uint32_t *hn); 91 uint32_t sn, uint32_t *hn);
91 void (*destroy_session) (struct iscsi_cls_session *session); 92 void (*destroy_session) (struct iscsi_cls_session *session);
@@ -117,10 +118,10 @@ struct iscsi_transport {
117 void (*cleanup_task) (struct iscsi_conn *conn, 118 void (*cleanup_task) (struct iscsi_conn *conn,
118 struct iscsi_task *task); 119 struct iscsi_task *task);
119 void (*session_recovery_timedout) (struct iscsi_cls_session *session); 120 void (*session_recovery_timedout) (struct iscsi_cls_session *session);
120 int (*ep_connect) (struct sockaddr *dst_addr, int non_blocking, 121 struct iscsi_endpoint *(*ep_connect) (struct sockaddr *dst_addr,
121 uint64_t *ep_handle); 122 int non_blocking);
122 int (*ep_poll) (uint64_t ep_handle, int timeout_ms); 123 int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms);
123 void (*ep_disconnect) (uint64_t ep_handle); 124 void (*ep_disconnect) (struct iscsi_endpoint *ep);
124 int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type, 125 int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
125 uint32_t enable, struct sockaddr *dst_addr); 126 uint32_t enable, struct sockaddr *dst_addr);
126}; 127};
@@ -203,6 +204,11 @@ struct iscsi_cls_host {
203extern void iscsi_host_for_each_session(struct Scsi_Host *shost, 204extern void iscsi_host_for_each_session(struct Scsi_Host *shost,
204 void (*fn)(struct iscsi_cls_session *)); 205 void (*fn)(struct iscsi_cls_session *));
205 206
207struct iscsi_endpoint {
208 void *dd_data; /* LLD private data */
209 struct device dev;
210 unsigned int id;
211};
206 212
207/* 213/*
208 * session and connection functions that can be used by HW iSCSI LLDs 214 * session and connection functions that can be used by HW iSCSI LLDs
@@ -233,5 +239,8 @@ extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn);
233extern void iscsi_unblock_session(struct iscsi_cls_session *session); 239extern void iscsi_unblock_session(struct iscsi_cls_session *session);
234extern void iscsi_block_session(struct iscsi_cls_session *session); 240extern void iscsi_block_session(struct iscsi_cls_session *session);
235extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time); 241extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time);
242extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size);
243extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
244extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
236 245
237#endif 246#endif