diff options
-rw-r--r-- | drivers/scsi/scsi_transport_iscsi.c | 189 | ||||
-rw-r--r-- | include/scsi/iscsi_if.h | 21 | ||||
-rw-r--r-- | include/scsi/scsi_transport_iscsi.h | 26 |
3 files changed, 233 insertions, 3 deletions
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 212a8d84674..4d5e64f429e 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c | |||
@@ -270,6 +270,185 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle) | |||
270 | } | 270 | } |
271 | EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint); | 271 | EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint); |
272 | 272 | ||
273 | /* | ||
274 | * Interface to display network param to sysfs | ||
275 | */ | ||
276 | |||
277 | static void iscsi_iface_release(struct device *dev) | ||
278 | { | ||
279 | struct iscsi_iface *iface = iscsi_dev_to_iface(dev); | ||
280 | struct device *parent = iface->dev.parent; | ||
281 | |||
282 | kfree(iface); | ||
283 | put_device(parent); | ||
284 | } | ||
285 | |||
286 | |||
287 | static struct class iscsi_iface_class = { | ||
288 | .name = "iscsi_iface", | ||
289 | .dev_release = iscsi_iface_release, | ||
290 | }; | ||
291 | |||
292 | #define ISCSI_IFACE_ATTR(_prefix, _name, _mode, _show, _store) \ | ||
293 | struct device_attribute dev_attr_##_prefix##_##_name = \ | ||
294 | __ATTR(_name, _mode, _show, _store) | ||
295 | |||
296 | /* iface attrs show */ | ||
297 | #define iscsi_iface_attr_show(type, name, param_type, param) \ | ||
298 | static ssize_t \ | ||
299 | show_##type##_##name(struct device *dev, struct device_attribute *attr, \ | ||
300 | char *buf) \ | ||
301 | { \ | ||
302 | struct iscsi_iface *iface = iscsi_dev_to_iface(dev); \ | ||
303 | struct iscsi_transport *t = iface->transport; \ | ||
304 | return t->get_iface_param(iface, param_type, param, buf); \ | ||
305 | } \ | ||
306 | |||
307 | #define iscsi_iface_net_attr(type, name, param) \ | ||
308 | iscsi_iface_attr_show(type, name, ISCSI_NET_PARAM, param) \ | ||
309 | static ISCSI_IFACE_ATTR(type, name, S_IRUGO, show_##type##_##name, NULL); | ||
310 | |||
311 | /* generic read only ipvi4 attribute */ | ||
312 | iscsi_iface_net_attr(ipv4_iface, ipaddress, ISCSI_NET_PARAM_IPV4_ADDR); | ||
313 | iscsi_iface_net_attr(ipv4_iface, gateway, ISCSI_NET_PARAM_IPV4_GW); | ||
314 | iscsi_iface_net_attr(ipv4_iface, subnet, ISCSI_NET_PARAM_IPV4_SUBNET); | ||
315 | iscsi_iface_net_attr(ipv4_iface, bootproto, ISCSI_NET_PARAM_IPV4_BOOTPROTO); | ||
316 | |||
317 | /* generic read only ipv6 attribute */ | ||
318 | iscsi_iface_net_attr(ipv6_iface, ipaddress, ISCSI_NET_PARAM_IPV6_ADDR); | ||
319 | iscsi_iface_net_attr(ipv6_iface, link_local_addr, ISCSI_NET_PARAM_IPV6_LINKLOCAL); | ||
320 | iscsi_iface_net_attr(ipv6_iface, router_addr, ISCSI_NET_PARAM_IPV6_ROUTER); | ||
321 | iscsi_iface_net_attr(ipv6_iface, ipaddr_autocfg, | ||
322 | ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG); | ||
323 | iscsi_iface_net_attr(ipv6_iface, linklocal_autocfg, | ||
324 | ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG); | ||
325 | |||
326 | /* common read only iface attribute */ | ||
327 | iscsi_iface_net_attr(iface, enabled, ISCSI_NET_PARAM_IFACE_ENABLE); | ||
328 | iscsi_iface_net_attr(iface, vlan, ISCSI_NET_PARAM_VLAN_ID); | ||
329 | |||
330 | static mode_t iscsi_iface_attr_is_visible(struct kobject *kobj, | ||
331 | struct attribute *attr, int i) | ||
332 | { | ||
333 | struct device *dev = container_of(kobj, struct device, kobj); | ||
334 | struct iscsi_iface *iface = iscsi_dev_to_iface(dev); | ||
335 | struct iscsi_transport *t = iface->transport; | ||
336 | |||
337 | if (attr == &dev_attr_iface_enabled.attr) | ||
338 | return (t->iface_param_mask & ISCSI_NET_IFACE_ENABLE) ? | ||
339 | S_IRUGO : 0; | ||
340 | else if (attr == &dev_attr_iface_vlan.attr) | ||
341 | return (t->iface_param_mask & ISCSI_NET_VLAN_ID) ? S_IRUGO : 0; | ||
342 | |||
343 | if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) { | ||
344 | if (attr == &dev_attr_ipv4_iface_ipaddress.attr) | ||
345 | return (t->iface_param_mask & ISCSI_NET_IPV4_ADDR) ? | ||
346 | S_IRUGO : 0; | ||
347 | else if (attr == &dev_attr_ipv4_iface_gateway.attr) | ||
348 | return (t->iface_param_mask & ISCSI_NET_IPV4_GW) ? | ||
349 | S_IRUGO : 0; | ||
350 | else if (attr == &dev_attr_ipv4_iface_subnet.attr) | ||
351 | return (t->iface_param_mask & ISCSI_NET_IPV4_SUBNET) ? | ||
352 | S_IRUGO : 0; | ||
353 | else if (attr == &dev_attr_ipv4_iface_bootproto.attr) | ||
354 | return (t->iface_param_mask & ISCSI_NET_IPV4_BOOTPROTO) ? | ||
355 | S_IRUGO : 0; | ||
356 | } else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) { | ||
357 | if (attr == &dev_attr_ipv6_iface_ipaddress.attr) | ||
358 | return (t->iface_param_mask & ISCSI_NET_IPV6_ADDR) ? | ||
359 | S_IRUGO : 0; | ||
360 | else if (attr == &dev_attr_ipv6_iface_link_local_addr.attr) | ||
361 | return (t->iface_param_mask & ISCSI_NET_IPV6_LINKLOCAL) ? | ||
362 | S_IRUGO : 0; | ||
363 | else if (attr == &dev_attr_ipv6_iface_router_addr.attr) | ||
364 | return (t->iface_param_mask & ISCSI_NET_IPV6_ROUTER) ? | ||
365 | S_IRUGO : 0; | ||
366 | else if (attr == &dev_attr_ipv6_iface_ipaddr_autocfg.attr) | ||
367 | return (t->iface_param_mask & ISCSI_NET_IPV6_ADDR_AUTOCFG) ? | ||
368 | S_IRUGO : 0; | ||
369 | else if (attr == &dev_attr_ipv6_iface_linklocal_autocfg.attr) | ||
370 | return (t->iface_param_mask & ISCSI_NET_IPV6_LINKLOCAL_AUTOCFG) ? | ||
371 | S_IRUGO : 0; | ||
372 | } | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static struct attribute *iscsi_iface_attrs[] = { | ||
378 | &dev_attr_iface_enabled.attr, | ||
379 | &dev_attr_iface_vlan.attr, | ||
380 | &dev_attr_ipv4_iface_ipaddress.attr, | ||
381 | &dev_attr_ipv4_iface_gateway.attr, | ||
382 | &dev_attr_ipv4_iface_subnet.attr, | ||
383 | &dev_attr_ipv4_iface_bootproto.attr, | ||
384 | &dev_attr_ipv6_iface_ipaddress.attr, | ||
385 | &dev_attr_ipv6_iface_link_local_addr.attr, | ||
386 | &dev_attr_ipv6_iface_router_addr.attr, | ||
387 | &dev_attr_ipv6_iface_ipaddr_autocfg.attr, | ||
388 | &dev_attr_ipv6_iface_linklocal_autocfg.attr, | ||
389 | NULL, | ||
390 | }; | ||
391 | |||
392 | static struct attribute_group iscsi_iface_group = { | ||
393 | .attrs = iscsi_iface_attrs, | ||
394 | .is_visible = iscsi_iface_attr_is_visible, | ||
395 | }; | ||
396 | |||
397 | struct iscsi_iface * | ||
398 | iscsi_create_iface(struct Scsi_Host *shost, struct iscsi_transport *transport, | ||
399 | uint32_t iface_type, uint32_t iface_num, int dd_size) | ||
400 | { | ||
401 | struct iscsi_iface *iface; | ||
402 | int err; | ||
403 | |||
404 | iface = kzalloc(sizeof(*iface) + dd_size, GFP_KERNEL); | ||
405 | if (!iface) | ||
406 | return NULL; | ||
407 | |||
408 | iface->transport = transport; | ||
409 | iface->iface_type = iface_type; | ||
410 | iface->iface_num = iface_num; | ||
411 | iface->dev.release = iscsi_iface_release; | ||
412 | iface->dev.class = &iscsi_iface_class; | ||
413 | /* parent reference released in iscsi_iface_release */ | ||
414 | iface->dev.parent = get_device(&shost->shost_gendev); | ||
415 | if (iface_type == ISCSI_IFACE_TYPE_IPV4) | ||
416 | dev_set_name(&iface->dev, "ipv4-iface-%u-%u", shost->host_no, | ||
417 | iface_num); | ||
418 | else | ||
419 | dev_set_name(&iface->dev, "ipv6-iface-%u-%u", shost->host_no, | ||
420 | iface_num); | ||
421 | |||
422 | err = device_register(&iface->dev); | ||
423 | if (err) | ||
424 | goto free_iface; | ||
425 | |||
426 | err = sysfs_create_group(&iface->dev.kobj, &iscsi_iface_group); | ||
427 | if (err) | ||
428 | goto unreg_iface; | ||
429 | |||
430 | if (dd_size) | ||
431 | iface->dd_data = &iface[1]; | ||
432 | return iface; | ||
433 | |||
434 | unreg_iface: | ||
435 | device_unregister(&iface->dev); | ||
436 | return NULL; | ||
437 | |||
438 | free_iface: | ||
439 | put_device(iface->dev.parent); | ||
440 | kfree(iface); | ||
441 | return NULL; | ||
442 | } | ||
443 | EXPORT_SYMBOL_GPL(iscsi_create_iface); | ||
444 | |||
445 | void iscsi_destroy_iface(struct iscsi_iface *iface) | ||
446 | { | ||
447 | sysfs_remove_group(&iface->dev.kobj, &iscsi_iface_group); | ||
448 | device_unregister(&iface->dev); | ||
449 | } | ||
450 | EXPORT_SYMBOL_GPL(iscsi_destroy_iface); | ||
451 | |||
273 | static int iscsi_setup_host(struct transport_container *tc, struct device *dev, | 452 | static int iscsi_setup_host(struct transport_container *tc, struct device *dev, |
274 | struct device *cdev) | 453 | struct device *cdev) |
275 | { | 454 | { |
@@ -2175,6 +2354,7 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
2175 | 2354 | ||
2176 | BUG_ON(count > ISCSI_SESSION_ATTRS); | 2355 | BUG_ON(count > ISCSI_SESSION_ATTRS); |
2177 | priv->session_attrs[count] = NULL; | 2356 | priv->session_attrs[count] = NULL; |
2357 | count = 0; | ||
2178 | 2358 | ||
2179 | spin_lock_irqsave(&iscsi_transport_lock, flags); | 2359 | spin_lock_irqsave(&iscsi_transport_lock, flags); |
2180 | list_add(&priv->list, &iscsi_transports); | 2360 | list_add(&priv->list, &iscsi_transports); |
@@ -2237,10 +2417,14 @@ static __init int iscsi_transport_init(void) | |||
2237 | if (err) | 2417 | if (err) |
2238 | goto unregister_transport_class; | 2418 | goto unregister_transport_class; |
2239 | 2419 | ||
2240 | err = transport_class_register(&iscsi_host_class); | 2420 | err = class_register(&iscsi_iface_class); |
2241 | if (err) | 2421 | if (err) |
2242 | goto unregister_endpoint_class; | 2422 | goto unregister_endpoint_class; |
2243 | 2423 | ||
2424 | err = transport_class_register(&iscsi_host_class); | ||
2425 | if (err) | ||
2426 | goto unregister_iface_class; | ||
2427 | |||
2244 | err = transport_class_register(&iscsi_connection_class); | 2428 | err = transport_class_register(&iscsi_connection_class); |
2245 | if (err) | 2429 | if (err) |
2246 | goto unregister_host_class; | 2430 | goto unregister_host_class; |
@@ -2270,6 +2454,8 @@ unregister_conn_class: | |||
2270 | transport_class_unregister(&iscsi_connection_class); | 2454 | transport_class_unregister(&iscsi_connection_class); |
2271 | unregister_host_class: | 2455 | unregister_host_class: |
2272 | transport_class_unregister(&iscsi_host_class); | 2456 | transport_class_unregister(&iscsi_host_class); |
2457 | unregister_iface_class: | ||
2458 | class_unregister(&iscsi_iface_class); | ||
2273 | unregister_endpoint_class: | 2459 | unregister_endpoint_class: |
2274 | class_unregister(&iscsi_endpoint_class); | 2460 | class_unregister(&iscsi_endpoint_class); |
2275 | unregister_transport_class: | 2461 | unregister_transport_class: |
@@ -2285,6 +2471,7 @@ static void __exit iscsi_transport_exit(void) | |||
2285 | transport_class_unregister(&iscsi_session_class); | 2471 | transport_class_unregister(&iscsi_session_class); |
2286 | transport_class_unregister(&iscsi_host_class); | 2472 | transport_class_unregister(&iscsi_host_class); |
2287 | class_unregister(&iscsi_endpoint_class); | 2473 | class_unregister(&iscsi_endpoint_class); |
2474 | class_unregister(&iscsi_iface_class); | ||
2288 | class_unregister(&iscsi_transport_class); | 2475 | class_unregister(&iscsi_transport_class); |
2289 | } | 2476 | } |
2290 | 2477 | ||
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index e93831e8787..a563753d578 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h | |||
@@ -296,10 +296,27 @@ enum iscsi_net_param { | |||
296 | ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG = 11, | 296 | ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG = 11, |
297 | ISCSI_NET_PARAM_IFACE_ENABLE = 12, | 297 | ISCSI_NET_PARAM_IFACE_ENABLE = 12, |
298 | ISCSI_NET_PARAM_VLAN_ID = 13, | 298 | ISCSI_NET_PARAM_VLAN_ID = 13, |
299 | ISCSI_NET_IFACE_TYPE = 14, | 299 | ISCSI_NET_PARAM_IFACE_TYPE = 14, |
300 | ISCSI_NET_IFACE_NAME = 15, | 300 | ISCSI_NET_PARAM_IFACE_NAME = 15, |
301 | }; | 301 | }; |
302 | 302 | ||
303 | #define ISCSI_NET_IPV4_ADDR (1ULL << ISCSI_NET_PARAM_IPV4_ADDR) | ||
304 | #define ISCSI_NET_IPV4_SUBNET (1ULL << ISCSI_NET_PARAM_IPV4_SUBNET) | ||
305 | #define ISCSI_NET_IPV4_GW (1ULL << ISCSI_NET_PARAM_IPV4_GW) | ||
306 | #define ISCSI_NET_IPV4_BOOTPROTO (1ULL << ISCSI_NET_PARAM_IPV4_BOOTPROTO) | ||
307 | #define ISCSI_NET_MAC (1ULL << ISCSI_NET_PARAM_MAC) | ||
308 | #define ISCSI_NET_IPV6_LINKLOCAL (1ULL << ISCSI_NET_PARAM_IPV6_LINKLOCAL) | ||
309 | #define ISCSI_NET_IPV6_ADDR (1ULL << ISCSI_NET_PARAM_IPV6_ADDR) | ||
310 | #define ISCSI_NET_IPV6_ROUTER (1ULL << ISCSI_NET_PARAM_IPV6_ROUTER) | ||
311 | #define ISCSI_NET_IPV6_ADDR_AUTOCFG \ | ||
312 | (1ULL << ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG) | ||
313 | #define ISCSI_NET_IPV6_LINKLOCAL_AUTOCFG \ | ||
314 | (1ULL << ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG) | ||
315 | #define ISCSI_NET_IPV6_ROUTER_AUTOCFG \ | ||
316 | (1ULL << ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG) | ||
317 | #define ISCSI_NET_IFACE_ENABLE (1ULL << ISCSI_NET_PARAM_IFACE_ENABLE) | ||
318 | #define ISCSI_NET_VLAN_ID (1ULL << ISCSI_NET_PARAM_VLAN_ID) | ||
319 | |||
303 | /* | 320 | /* |
304 | * Common error codes | 321 | * Common error codes |
305 | */ | 322 | */ |
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 9fcce7cd367..e1f210a173a 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h | |||
@@ -37,6 +37,7 @@ struct iscsi_cls_conn; | |||
37 | struct iscsi_conn; | 37 | struct iscsi_conn; |
38 | struct iscsi_task; | 38 | struct iscsi_task; |
39 | struct sockaddr; | 39 | struct sockaddr; |
40 | struct iscsi_iface; | ||
40 | 41 | ||
41 | /** | 42 | /** |
42 | * struct iscsi_transport - iSCSI Transport template | 43 | * struct iscsi_transport - iSCSI Transport template |
@@ -87,6 +88,8 @@ struct iscsi_transport { | |||
87 | /* LLD sets this to indicate what values it can export to sysfs */ | 88 | /* LLD sets this to indicate what values it can export to sysfs */ |
88 | uint64_t param_mask; | 89 | uint64_t param_mask; |
89 | uint64_t host_param_mask; | 90 | uint64_t host_param_mask; |
91 | uint64_t iface_param_mask; | ||
92 | |||
90 | struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep, | 93 | struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep, |
91 | uint16_t cmds_max, uint16_t qdepth, | 94 | uint16_t cmds_max, uint16_t qdepth, |
92 | uint32_t sn); | 95 | uint32_t sn); |
@@ -138,6 +141,9 @@ struct iscsi_transport { | |||
138 | uint32_t enable, struct sockaddr *dst_addr); | 141 | uint32_t enable, struct sockaddr *dst_addr); |
139 | int (*set_path) (struct Scsi_Host *shost, struct iscsi_path *params); | 142 | int (*set_path) (struct Scsi_Host *shost, struct iscsi_path *params); |
140 | int (*set_iface_param) (struct Scsi_Host *shost, char *data, int count); | 143 | int (*set_iface_param) (struct Scsi_Host *shost, char *data, int count); |
144 | int (*get_iface_param) (struct iscsi_iface *iface, | ||
145 | enum iscsi_param_type param_type, | ||
146 | int param, char *buf); | ||
141 | }; | 147 | }; |
142 | 148 | ||
143 | /* | 149 | /* |
@@ -229,6 +235,20 @@ struct iscsi_endpoint { | |||
229 | struct iscsi_cls_conn *conn; | 235 | struct iscsi_cls_conn *conn; |
230 | }; | 236 | }; |
231 | 237 | ||
238 | struct iscsi_iface { | ||
239 | struct device dev; | ||
240 | struct iscsi_transport *transport; | ||
241 | uint32_t iface_type; /* IPv4 or IPv6 */ | ||
242 | uint32_t iface_num; /* iface number, 0 - n */ | ||
243 | void *dd_data; /* LLD private data */ | ||
244 | }; | ||
245 | |||
246 | #define iscsi_dev_to_iface(_dev) \ | ||
247 | container_of(_dev, struct iscsi_iface, dev) | ||
248 | |||
249 | #define iscsi_iface_to_shost(_iface) \ | ||
250 | dev_to_shost(_iface->dev.parent) | ||
251 | |||
232 | /* | 252 | /* |
233 | * session and connection functions that can be used by HW iSCSI LLDs | 253 | * session and connection functions that can be used by HW iSCSI LLDs |
234 | */ | 254 | */ |
@@ -262,5 +282,11 @@ extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size); | |||
262 | extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep); | 282 | extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep); |
263 | extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle); | 283 | extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle); |
264 | extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd); | 284 | extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd); |
285 | extern struct iscsi_iface *iscsi_create_iface(struct Scsi_Host *shost, | ||
286 | struct iscsi_transport *t, | ||
287 | uint32_t iface_type, | ||
288 | uint32_t iface_num, int dd_size); | ||
289 | extern void iscsi_destroy_iface(struct iscsi_iface *iface); | ||
290 | extern struct iscsi_iface *iscsi_lookup_iface(int handle); | ||
265 | 291 | ||
266 | #endif | 292 | #endif |