diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/scsi_transport_iscsi.c | 190 |
1 files changed, 157 insertions, 33 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 | ||
38 | struct iscsi_internal { | 39 | struct 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) \ | ||
123 | struct device_attribute dev_attr_##_prefix##_##_name = \ | ||
124 | __ATTR(_name,_mode,_show,_store) | ||
125 | |||
126 | static void iscsi_endpoint_release(struct device *dev) | ||
127 | { | ||
128 | struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); | ||
129 | kfree(ep); | ||
130 | } | ||
131 | |||
132 | static struct class iscsi_endpoint_class = { | ||
133 | .name = "iscsi_endpoint", | ||
134 | .dev_release = iscsi_endpoint_release, | ||
135 | }; | ||
136 | |||
137 | static ssize_t | ||
138 | show_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 | } | ||
143 | static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL); | ||
144 | |||
145 | static struct attribute *iscsi_endpoint_attrs[] = { | ||
146 | &dev_attr_ep_handle.attr, | ||
147 | NULL, | ||
148 | }; | ||
149 | |||
150 | static struct attribute_group iscsi_endpoint_group = { | ||
151 | .attrs = iscsi_endpoint_attrs, | ||
152 | }; | ||
153 | |||
154 | #define ISCSI_MAX_EPID -1 | ||
155 | |||
156 | static 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 | |||
164 | struct iscsi_endpoint * | ||
165 | iscsi_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 | |||
203 | unregister_dev: | ||
204 | device_unregister(&ep->dev); | ||
205 | return NULL; | ||
206 | |||
207 | free_ep: | ||
208 | kfree(ep); | ||
209 | return NULL; | ||
210 | } | ||
211 | EXPORT_SYMBOL_GPL(iscsi_create_endpoint); | ||
212 | |||
213 | void iscsi_destroy_endpoint(struct iscsi_endpoint *ep) | ||
214 | { | ||
215 | sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group); | ||
216 | device_unregister(&ep->dev); | ||
217 | } | ||
218 | EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint); | ||
219 | |||
220 | struct 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 | } | ||
231 | EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint); | ||
232 | |||
115 | static int iscsi_setup_host(struct transport_container *tc, struct device *dev, | 233 | static 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, | |||
1094 | EXPORT_SYMBOL_GPL(iscsi_session_event); | 1212 | EXPORT_SYMBOL_GPL(iscsi_session_event); |
1095 | 1213 | ||
1096 | static int | 1214 | static int |
1097 | iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev, | 1215 | iscsi_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 | |||
1199 | iscsi_if_transport_ep(struct iscsi_transport *transport, | 1300 | iscsi_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 | |||
1283 | iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | 1396 | iscsi_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 | ||
1775 | unregister_dev: | 1891 | unregister_dev: |
1776 | device_unregister(&priv->dev); | 1892 | device_unregister(&priv->dev); |
1893 | return NULL; | ||
1777 | free_priv: | 1894 | free_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); |
1855 | unregister_host_class: | 1976 | unregister_host_class: |
1856 | transport_class_unregister(&iscsi_host_class); | 1977 | transport_class_unregister(&iscsi_host_class); |
1978 | unregister_endpoint_class: | ||
1979 | class_unregister(&iscsi_endpoint_class); | ||
1857 | unregister_transport_class: | 1980 | unregister_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 | ||