blob: e4a989fa477d3bc3f94788455dec8f0b6ba2ff5d [file] [log] [blame]
Alex Aizman0896b752005-08-04 19:33:07 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * iSCSI transport class definitions
3 *
4 * Copyright (C) IBM Corporation, 2004
Alex Aizman0896b752005-08-04 19:33:07 -07005 * Copyright (C) Mike Christie, 2004 - 2005
6 * Copyright (C) Dmitry Yusupov, 2004 - 2005
7 * Copyright (C) Alex Aizman, 2004 - 2005
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23#include <linux/module.h>
Arjan van de Ven0b950672006-01-11 13:16:10 +010024#include <linux/mutex.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Mike Christie90eeb012011-07-25 13:48:50 -050026#include <linux/bsg-lib.h>
Mike Christie8d4a6902011-10-06 03:56:57 -050027#include <linux/idr.h>
Alex Aizman0896b752005-08-04 19:33:07 -070028#include <net/tcp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <scsi/scsi.h>
30#include <scsi/scsi_host.h>
31#include <scsi/scsi_device.h>
32#include <scsi/scsi_transport.h>
33#include <scsi/scsi_transport_iscsi.h>
Alex Aizman0896b752005-08-04 19:33:07 -070034#include <scsi/iscsi_if.h>
Mike Christiec01be6d2010-07-22 16:59:49 +053035#include <scsi/scsi_cmnd.h>
Mike Christie90eeb012011-07-25 13:48:50 -050036#include <scsi/scsi_bsg_iscsi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Mike Christie4c2133c2008-06-16 10:11:34 -050038#define ISCSI_TRANSPORT_VERSION "2.0-870"
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Mike Christie632248a2009-08-20 15:11:01 -050040static int dbg_session;
41module_param_named(debug_session, dbg_session, int,
42 S_IRUGO | S_IWUSR);
43MODULE_PARM_DESC(debug_session,
44 "Turn on debugging for sessions in scsi_transport_iscsi "
45 "module. Set to 1 to turn on, and zero to turn off. Default "
46 "is off.");
47
48static int dbg_conn;
49module_param_named(debug_conn, dbg_conn, int,
50 S_IRUGO | S_IWUSR);
51MODULE_PARM_DESC(debug_conn,
52 "Turn on debugging for connections in scsi_transport_iscsi "
53 "module. Set to 1 to turn on, and zero to turn off. Default "
54 "is off.");
55
56#define ISCSI_DBG_TRANS_SESSION(_session, dbg_fmt, arg...) \
57 do { \
58 if (dbg_session) \
59 iscsi_cls_session_printk(KERN_INFO, _session, \
60 "%s: " dbg_fmt, \
61 __func__, ##arg); \
62 } while (0);
63
64#define ISCSI_DBG_TRANS_CONN(_conn, dbg_fmt, arg...) \
65 do { \
66 if (dbg_conn) \
67 iscsi_cls_conn_printk(KERN_INFO, _conn, \
68 "%s: " dbg_fmt, \
69 __func__, ##arg); \
70 } while (0);
71
Linus Torvalds1da177e2005-04-16 15:20:36 -070072struct iscsi_internal {
73 struct scsi_transport_template t;
Alex Aizman0896b752005-08-04 19:33:07 -070074 struct iscsi_transport *iscsi_transport;
75 struct list_head list;
Tony Jonesee959b02008-02-22 00:13:36 +010076 struct device dev;
Mike Christie30a6c652006-04-06 21:13:39 -050077
Alex Aizman0896b752005-08-04 19:33:07 -070078 struct transport_container conn_cont;
Alex Aizman0896b752005-08-04 19:33:07 -070079 struct transport_container session_cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080};
81
Mike Christie41be1442007-02-28 17:32:18 -060082static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
Mike Christied8bf5412007-12-13 12:43:27 -060083static struct workqueue_struct *iscsi_eh_timer_workq;
Mike Christieb5c7a122006-04-06 21:13:33 -050084
Mike Christie8d4a6902011-10-06 03:56:57 -050085static DEFINE_IDA(iscsi_sess_ida);
Alex Aizman0896b752005-08-04 19:33:07 -070086/*
87 * list of registered transports and lock that must
88 * be held while accessing list. The iscsi_transport_lock must
Arjan van de Ven0b950672006-01-11 13:16:10 +010089 * be acquired after the rx_queue_mutex.
Alex Aizman0896b752005-08-04 19:33:07 -070090 */
91static LIST_HEAD(iscsi_transports);
92static DEFINE_SPINLOCK(iscsi_transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Alex Aizman0896b752005-08-04 19:33:07 -070094#define to_iscsi_internal(tmpl) \
95 container_of(tmpl, struct iscsi_internal, t)
96
Tony Jonesee959b02008-02-22 00:13:36 +010097#define dev_to_iscsi_internal(_dev) \
98 container_of(_dev, struct iscsi_internal, dev)
Alex Aizman0896b752005-08-04 19:33:07 -070099
Tony Jonesee959b02008-02-22 00:13:36 +0100100static void iscsi_transport_release(struct device *dev)
Alex Aizman0896b752005-08-04 19:33:07 -0700101{
Tony Jonesee959b02008-02-22 00:13:36 +0100102 struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
Alex Aizman0896b752005-08-04 19:33:07 -0700103 kfree(priv);
104}
105
106/*
107 * iscsi_transport_class represents the iscsi_transports that are
108 * registered.
109 */
110static struct class iscsi_transport_class = {
111 .name = "iscsi_transport",
Tony Jonesee959b02008-02-22 00:13:36 +0100112 .dev_release = iscsi_transport_release,
Alex Aizman0896b752005-08-04 19:33:07 -0700113};
114
115static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +0100116show_transport_handle(struct device *dev, struct device_attribute *attr,
117 char *buf)
Alex Aizman0896b752005-08-04 19:33:07 -0700118{
Tony Jonesee959b02008-02-22 00:13:36 +0100119 struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
Mike Christie762e2bf2005-09-12 21:01:46 -0500120 return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
Alex Aizman0896b752005-08-04 19:33:07 -0700121}
Tony Jonesee959b02008-02-22 00:13:36 +0100122static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
Alex Aizman0896b752005-08-04 19:33:07 -0700123
124#define show_transport_attr(name, format) \
125static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100126show_transport_##name(struct device *dev, \
127 struct device_attribute *attr,char *buf) \
Alex Aizman0896b752005-08-04 19:33:07 -0700128{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100129 struct iscsi_internal *priv = dev_to_iscsi_internal(dev); \
Alex Aizman0896b752005-08-04 19:33:07 -0700130 return sprintf(buf, format"\n", priv->iscsi_transport->name); \
131} \
Tony Jonesee959b02008-02-22 00:13:36 +0100132static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
Alex Aizman0896b752005-08-04 19:33:07 -0700133
134show_transport_attr(caps, "0x%x");
Alex Aizman0896b752005-08-04 19:33:07 -0700135
136static struct attribute *iscsi_transport_attrs[] = {
Tony Jonesee959b02008-02-22 00:13:36 +0100137 &dev_attr_handle.attr,
138 &dev_attr_caps.attr,
Alex Aizman0896b752005-08-04 19:33:07 -0700139 NULL,
140};
141
142static struct attribute_group iscsi_transport_group = {
143 .attrs = iscsi_transport_attrs,
144};
145
Mike Christied82ff9be2008-05-21 15:54:13 -0500146/*
147 * iSCSI endpoint attrs
148 */
149#define iscsi_dev_to_endpoint(_dev) \
150 container_of(_dev, struct iscsi_endpoint, dev)
151
152#define ISCSI_ATTR(_prefix,_name,_mode,_show,_store) \
153struct device_attribute dev_attr_##_prefix##_##_name = \
154 __ATTR(_name,_mode,_show,_store)
155
156static void iscsi_endpoint_release(struct device *dev)
157{
158 struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
159 kfree(ep);
160}
161
162static struct class iscsi_endpoint_class = {
163 .name = "iscsi_endpoint",
164 .dev_release = iscsi_endpoint_release,
165};
166
167static ssize_t
168show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf)
169{
170 struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
Mike Christie21536062008-09-24 11:46:11 -0500171 return sprintf(buf, "%llu\n", (unsigned long long) ep->id);
Mike Christied82ff9be2008-05-21 15:54:13 -0500172}
173static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL);
174
175static struct attribute *iscsi_endpoint_attrs[] = {
176 &dev_attr_ep_handle.attr,
177 NULL,
178};
179
180static struct attribute_group iscsi_endpoint_group = {
181 .attrs = iscsi_endpoint_attrs,
182};
183
184#define ISCSI_MAX_EPID -1
185
Michał Mirosław9f3b7952013-02-01 20:40:17 +0100186static int iscsi_match_epid(struct device *dev, const void *data)
Mike Christied82ff9be2008-05-21 15:54:13 -0500187{
188 struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
Michał Mirosław9f3b7952013-02-01 20:40:17 +0100189 const uint64_t *epid = data;
Mike Christied82ff9be2008-05-21 15:54:13 -0500190
191 return *epid == ep->id;
192}
193
194struct iscsi_endpoint *
195iscsi_create_endpoint(int dd_size)
196{
197 struct device *dev;
198 struct iscsi_endpoint *ep;
Mike Christie21536062008-09-24 11:46:11 -0500199 uint64_t id;
Mike Christied82ff9be2008-05-21 15:54:13 -0500200 int err;
201
202 for (id = 1; id < ISCSI_MAX_EPID; id++) {
Greg Kroah-Hartman695794a2008-05-22 17:21:08 -0400203 dev = class_find_device(&iscsi_endpoint_class, NULL, &id,
Mike Christied82ff9be2008-05-21 15:54:13 -0500204 iscsi_match_epid);
205 if (!dev)
206 break;
207 }
208 if (id == ISCSI_MAX_EPID) {
209 printk(KERN_ERR "Too many connections. Max supported %u\n",
210 ISCSI_MAX_EPID - 1);
211 return NULL;
212 }
213
214 ep = kzalloc(sizeof(*ep) + dd_size, GFP_KERNEL);
215 if (!ep)
216 return NULL;
217
218 ep->id = id;
219 ep->dev.class = &iscsi_endpoint_class;
Kay Sievers71610f52008-12-03 22:41:36 +0100220 dev_set_name(&ep->dev, "ep-%llu", (unsigned long long) id);
Mike Christied82ff9be2008-05-21 15:54:13 -0500221 err = device_register(&ep->dev);
222 if (err)
223 goto free_ep;
224
225 err = sysfs_create_group(&ep->dev.kobj, &iscsi_endpoint_group);
226 if (err)
227 goto unregister_dev;
228
229 if (dd_size)
230 ep->dd_data = &ep[1];
231 return ep;
232
233unregister_dev:
234 device_unregister(&ep->dev);
235 return NULL;
236
237free_ep:
238 kfree(ep);
239 return NULL;
240}
241EXPORT_SYMBOL_GPL(iscsi_create_endpoint);
242
243void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
244{
245 sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group);
246 device_unregister(&ep->dev);
247}
248EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint);
249
250struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
251{
Mike Christief80f8682008-06-16 10:11:35 -0500252 struct iscsi_endpoint *ep;
Mike Christied82ff9be2008-05-21 15:54:13 -0500253 struct device *dev;
254
Greg Kroah-Hartman695794a2008-05-22 17:21:08 -0400255 dev = class_find_device(&iscsi_endpoint_class, NULL, &handle,
Mike Christied82ff9be2008-05-21 15:54:13 -0500256 iscsi_match_epid);
257 if (!dev)
258 return NULL;
259
Mike Christief80f8682008-06-16 10:11:35 -0500260 ep = iscsi_dev_to_endpoint(dev);
261 /*
262 * we can drop this now because the interface will prevent
263 * removals and lookups from racing.
264 */
265 put_device(dev);
266 return ep;
Mike Christied82ff9be2008-05-21 15:54:13 -0500267}
268EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
269
Mike Christie8d079132011-07-25 13:48:40 -0500270/*
271 * Interface to display network param to sysfs
272 */
273
274static void iscsi_iface_release(struct device *dev)
275{
276 struct iscsi_iface *iface = iscsi_dev_to_iface(dev);
277 struct device *parent = iface->dev.parent;
278
279 kfree(iface);
280 put_device(parent);
281}
282
283
284static struct class iscsi_iface_class = {
285 .name = "iscsi_iface",
286 .dev_release = iscsi_iface_release,
287};
288
289#define ISCSI_IFACE_ATTR(_prefix, _name, _mode, _show, _store) \
290struct device_attribute dev_attr_##_prefix##_##_name = \
291 __ATTR(_name, _mode, _show, _store)
292
293/* iface attrs show */
294#define iscsi_iface_attr_show(type, name, param_type, param) \
295static ssize_t \
296show_##type##_##name(struct device *dev, struct device_attribute *attr, \
297 char *buf) \
298{ \
299 struct iscsi_iface *iface = iscsi_dev_to_iface(dev); \
300 struct iscsi_transport *t = iface->transport; \
301 return t->get_iface_param(iface, param_type, param, buf); \
302} \
303
304#define iscsi_iface_net_attr(type, name, param) \
305 iscsi_iface_attr_show(type, name, ISCSI_NET_PARAM, param) \
306static ISCSI_IFACE_ATTR(type, name, S_IRUGO, show_##type##_##name, NULL);
307
308/* generic read only ipvi4 attribute */
309iscsi_iface_net_attr(ipv4_iface, ipaddress, ISCSI_NET_PARAM_IPV4_ADDR);
310iscsi_iface_net_attr(ipv4_iface, gateway, ISCSI_NET_PARAM_IPV4_GW);
311iscsi_iface_net_attr(ipv4_iface, subnet, ISCSI_NET_PARAM_IPV4_SUBNET);
312iscsi_iface_net_attr(ipv4_iface, bootproto, ISCSI_NET_PARAM_IPV4_BOOTPROTO);
313
314/* generic read only ipv6 attribute */
315iscsi_iface_net_attr(ipv6_iface, ipaddress, ISCSI_NET_PARAM_IPV6_ADDR);
316iscsi_iface_net_attr(ipv6_iface, link_local_addr, ISCSI_NET_PARAM_IPV6_LINKLOCAL);
317iscsi_iface_net_attr(ipv6_iface, router_addr, ISCSI_NET_PARAM_IPV6_ROUTER);
318iscsi_iface_net_attr(ipv6_iface, ipaddr_autocfg,
319 ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG);
Mike Christie88f4f512011-10-06 03:56:58 -0500320iscsi_iface_net_attr(ipv6_iface, link_local_autocfg,
Mike Christie8d079132011-07-25 13:48:40 -0500321 ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG);
322
323/* common read only iface attribute */
324iscsi_iface_net_attr(iface, enabled, ISCSI_NET_PARAM_IFACE_ENABLE);
Mike Christie2d636732011-10-11 17:55:11 -0500325iscsi_iface_net_attr(iface, vlan_id, ISCSI_NET_PARAM_VLAN_ID);
Mike Christie4223b9e2011-07-25 13:48:47 -0500326iscsi_iface_net_attr(iface, vlan_priority, ISCSI_NET_PARAM_VLAN_PRIORITY);
327iscsi_iface_net_attr(iface, vlan_enabled, ISCSI_NET_PARAM_VLAN_ENABLED);
Vikas Chaudhary8c7d40f2011-08-01 03:26:12 -0700328iscsi_iface_net_attr(iface, mtu, ISCSI_NET_PARAM_MTU);
Vikas Chaudharyfcb51242011-08-01 03:26:18 -0700329iscsi_iface_net_attr(iface, port, ISCSI_NET_PARAM_PORT);
Mike Christie8d079132011-07-25 13:48:40 -0500330
Al Viro587a1f12011-07-23 23:11:19 -0400331static umode_t iscsi_iface_attr_is_visible(struct kobject *kobj,
Mike Christie8d079132011-07-25 13:48:40 -0500332 struct attribute *attr, int i)
333{
334 struct device *dev = container_of(kobj, struct device, kobj);
335 struct iscsi_iface *iface = iscsi_dev_to_iface(dev);
336 struct iscsi_transport *t = iface->transport;
Mike Christieb78dbba2011-07-25 13:48:44 -0500337 int param;
Mike Christie8d079132011-07-25 13:48:40 -0500338
339 if (attr == &dev_attr_iface_enabled.attr)
Mike Christieb78dbba2011-07-25 13:48:44 -0500340 param = ISCSI_NET_PARAM_IFACE_ENABLE;
Mike Christie2d636732011-10-11 17:55:11 -0500341 else if (attr == &dev_attr_iface_vlan_id.attr)
Mike Christieb78dbba2011-07-25 13:48:44 -0500342 param = ISCSI_NET_PARAM_VLAN_ID;
Mike Christie4223b9e2011-07-25 13:48:47 -0500343 else if (attr == &dev_attr_iface_vlan_priority.attr)
344 param = ISCSI_NET_PARAM_VLAN_PRIORITY;
345 else if (attr == &dev_attr_iface_vlan_enabled.attr)
346 param = ISCSI_NET_PARAM_VLAN_ENABLED;
Vikas Chaudhary8c7d40f2011-08-01 03:26:12 -0700347 else if (attr == &dev_attr_iface_mtu.attr)
348 param = ISCSI_NET_PARAM_MTU;
Vikas Chaudharyfcb51242011-08-01 03:26:18 -0700349 else if (attr == &dev_attr_iface_port.attr)
350 param = ISCSI_NET_PARAM_PORT;
Mike Christieb78dbba2011-07-25 13:48:44 -0500351 else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
Mike Christie8d079132011-07-25 13:48:40 -0500352 if (attr == &dev_attr_ipv4_iface_ipaddress.attr)
Mike Christieb78dbba2011-07-25 13:48:44 -0500353 param = ISCSI_NET_PARAM_IPV4_ADDR;
Mike Christie8d079132011-07-25 13:48:40 -0500354 else if (attr == &dev_attr_ipv4_iface_gateway.attr)
Mike Christieb78dbba2011-07-25 13:48:44 -0500355 param = ISCSI_NET_PARAM_IPV4_GW;
Mike Christie8d079132011-07-25 13:48:40 -0500356 else if (attr == &dev_attr_ipv4_iface_subnet.attr)
Mike Christieb78dbba2011-07-25 13:48:44 -0500357 param = ISCSI_NET_PARAM_IPV4_SUBNET;
Mike Christie8d079132011-07-25 13:48:40 -0500358 else if (attr == &dev_attr_ipv4_iface_bootproto.attr)
Mike Christieb78dbba2011-07-25 13:48:44 -0500359 param = ISCSI_NET_PARAM_IPV4_BOOTPROTO;
360 else
361 return 0;
Mike Christie8d079132011-07-25 13:48:40 -0500362 } else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) {
363 if (attr == &dev_attr_ipv6_iface_ipaddress.attr)
Mike Christieb78dbba2011-07-25 13:48:44 -0500364 param = ISCSI_NET_PARAM_IPV6_ADDR;
Mike Christie8d079132011-07-25 13:48:40 -0500365 else if (attr == &dev_attr_ipv6_iface_link_local_addr.attr)
Mike Christieb78dbba2011-07-25 13:48:44 -0500366 param = ISCSI_NET_PARAM_IPV6_LINKLOCAL;
Mike Christie8d079132011-07-25 13:48:40 -0500367 else if (attr == &dev_attr_ipv6_iface_router_addr.attr)
Mike Christieb78dbba2011-07-25 13:48:44 -0500368 param = ISCSI_NET_PARAM_IPV6_ROUTER;
Mike Christie8d079132011-07-25 13:48:40 -0500369 else if (attr == &dev_attr_ipv6_iface_ipaddr_autocfg.attr)
Mike Christieb78dbba2011-07-25 13:48:44 -0500370 param = ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG;
Mike Christie88f4f512011-10-06 03:56:58 -0500371 else if (attr == &dev_attr_ipv6_iface_link_local_autocfg.attr)
Mike Christieb78dbba2011-07-25 13:48:44 -0500372 param = ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG;
373 else
374 return 0;
375 } else {
376 WARN_ONCE(1, "Invalid iface attr");
377 return 0;
Mike Christie8d079132011-07-25 13:48:40 -0500378 }
379
Mike Christieb78dbba2011-07-25 13:48:44 -0500380 return t->attr_is_visible(ISCSI_NET_PARAM, param);
Mike Christie8d079132011-07-25 13:48:40 -0500381}
382
383static struct attribute *iscsi_iface_attrs[] = {
384 &dev_attr_iface_enabled.attr,
Mike Christie2d636732011-10-11 17:55:11 -0500385 &dev_attr_iface_vlan_id.attr,
Mike Christie4223b9e2011-07-25 13:48:47 -0500386 &dev_attr_iface_vlan_priority.attr,
387 &dev_attr_iface_vlan_enabled.attr,
Mike Christie8d079132011-07-25 13:48:40 -0500388 &dev_attr_ipv4_iface_ipaddress.attr,
389 &dev_attr_ipv4_iface_gateway.attr,
390 &dev_attr_ipv4_iface_subnet.attr,
391 &dev_attr_ipv4_iface_bootproto.attr,
392 &dev_attr_ipv6_iface_ipaddress.attr,
393 &dev_attr_ipv6_iface_link_local_addr.attr,
394 &dev_attr_ipv6_iface_router_addr.attr,
395 &dev_attr_ipv6_iface_ipaddr_autocfg.attr,
Mike Christie88f4f512011-10-06 03:56:58 -0500396 &dev_attr_ipv6_iface_link_local_autocfg.attr,
Vikas Chaudhary8c7d40f2011-08-01 03:26:12 -0700397 &dev_attr_iface_mtu.attr,
Vikas Chaudharyfcb51242011-08-01 03:26:18 -0700398 &dev_attr_iface_port.attr,
Mike Christie8d079132011-07-25 13:48:40 -0500399 NULL,
400};
401
402static struct attribute_group iscsi_iface_group = {
403 .attrs = iscsi_iface_attrs,
404 .is_visible = iscsi_iface_attr_is_visible,
405};
406
407struct iscsi_iface *
408iscsi_create_iface(struct Scsi_Host *shost, struct iscsi_transport *transport,
409 uint32_t iface_type, uint32_t iface_num, int dd_size)
410{
411 struct iscsi_iface *iface;
412 int err;
413
414 iface = kzalloc(sizeof(*iface) + dd_size, GFP_KERNEL);
415 if (!iface)
416 return NULL;
417
418 iface->transport = transport;
419 iface->iface_type = iface_type;
420 iface->iface_num = iface_num;
421 iface->dev.release = iscsi_iface_release;
422 iface->dev.class = &iscsi_iface_class;
423 /* parent reference released in iscsi_iface_release */
424 iface->dev.parent = get_device(&shost->shost_gendev);
425 if (iface_type == ISCSI_IFACE_TYPE_IPV4)
426 dev_set_name(&iface->dev, "ipv4-iface-%u-%u", shost->host_no,
427 iface_num);
428 else
429 dev_set_name(&iface->dev, "ipv6-iface-%u-%u", shost->host_no,
430 iface_num);
431
432 err = device_register(&iface->dev);
433 if (err)
434 goto free_iface;
435
436 err = sysfs_create_group(&iface->dev.kobj, &iscsi_iface_group);
437 if (err)
438 goto unreg_iface;
439
440 if (dd_size)
441 iface->dd_data = &iface[1];
442 return iface;
443
444unreg_iface:
445 device_unregister(&iface->dev);
446 return NULL;
447
448free_iface:
449 put_device(iface->dev.parent);
450 kfree(iface);
451 return NULL;
452}
453EXPORT_SYMBOL_GPL(iscsi_create_iface);
454
455void iscsi_destroy_iface(struct iscsi_iface *iface)
456{
457 sysfs_remove_group(&iface->dev.kobj, &iscsi_iface_group);
458 device_unregister(&iface->dev);
459}
460EXPORT_SYMBOL_GPL(iscsi_destroy_iface);
461
Mike Christie90eeb012011-07-25 13:48:50 -0500462/*
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -0400463 * Interface to display flash node params to sysfs
464 */
465
466#define ISCSI_FLASHNODE_ATTR(_prefix, _name, _mode, _show, _store) \
467struct device_attribute dev_attr_##_prefix##_##_name = \
468 __ATTR(_name, _mode, _show, _store)
469
470/* flash node session attrs show */
471#define iscsi_flashnode_sess_attr_show(type, name, param) \
472static ssize_t \
473show_##type##_##name(struct device *dev, struct device_attribute *attr, \
474 char *buf) \
475{ \
476 struct iscsi_bus_flash_session *fnode_sess = \
477 iscsi_dev_to_flash_session(dev);\
478 struct iscsi_transport *t = fnode_sess->transport; \
479 return t->get_flashnode_param(fnode_sess, param, buf); \
480} \
481
482
483#define iscsi_flashnode_sess_attr(type, name, param) \
484 iscsi_flashnode_sess_attr_show(type, name, param) \
485static ISCSI_FLASHNODE_ATTR(type, name, S_IRUGO, \
486 show_##type##_##name, NULL);
487
488/* Flash node session attributes */
489
490iscsi_flashnode_sess_attr(fnode, auto_snd_tgt_disable,
491 ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE);
492iscsi_flashnode_sess_attr(fnode, discovery_session,
493 ISCSI_FLASHNODE_DISCOVERY_SESS);
494iscsi_flashnode_sess_attr(fnode, portal_type, ISCSI_FLASHNODE_PORTAL_TYPE);
495iscsi_flashnode_sess_attr(fnode, entry_enable, ISCSI_FLASHNODE_ENTRY_EN);
496iscsi_flashnode_sess_attr(fnode, immediate_data, ISCSI_FLASHNODE_IMM_DATA_EN);
497iscsi_flashnode_sess_attr(fnode, initial_r2t, ISCSI_FLASHNODE_INITIAL_R2T_EN);
498iscsi_flashnode_sess_attr(fnode, data_seq_in_order,
499 ISCSI_FLASHNODE_DATASEQ_INORDER);
500iscsi_flashnode_sess_attr(fnode, data_pdu_in_order,
501 ISCSI_FLASHNODE_PDU_INORDER);
502iscsi_flashnode_sess_attr(fnode, chap_auth, ISCSI_FLASHNODE_CHAP_AUTH_EN);
503iscsi_flashnode_sess_attr(fnode, discovery_logout,
504 ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN);
505iscsi_flashnode_sess_attr(fnode, bidi_chap, ISCSI_FLASHNODE_BIDI_CHAP_EN);
506iscsi_flashnode_sess_attr(fnode, discovery_auth_optional,
507 ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL);
508iscsi_flashnode_sess_attr(fnode, erl, ISCSI_FLASHNODE_ERL);
509iscsi_flashnode_sess_attr(fnode, first_burst_len, ISCSI_FLASHNODE_FIRST_BURST);
510iscsi_flashnode_sess_attr(fnode, def_time2wait, ISCSI_FLASHNODE_DEF_TIME2WAIT);
511iscsi_flashnode_sess_attr(fnode, def_time2retain,
512 ISCSI_FLASHNODE_DEF_TIME2RETAIN);
513iscsi_flashnode_sess_attr(fnode, max_outstanding_r2t, ISCSI_FLASHNODE_MAX_R2T);
514iscsi_flashnode_sess_attr(fnode, isid, ISCSI_FLASHNODE_ISID);
515iscsi_flashnode_sess_attr(fnode, tsid, ISCSI_FLASHNODE_TSID);
516iscsi_flashnode_sess_attr(fnode, max_burst_len, ISCSI_FLASHNODE_MAX_BURST);
517iscsi_flashnode_sess_attr(fnode, def_taskmgmt_tmo,
518 ISCSI_FLASHNODE_DEF_TASKMGMT_TMO);
519iscsi_flashnode_sess_attr(fnode, targetalias, ISCSI_FLASHNODE_ALIAS);
520iscsi_flashnode_sess_attr(fnode, targetname, ISCSI_FLASHNODE_NAME);
521iscsi_flashnode_sess_attr(fnode, tpgt, ISCSI_FLASHNODE_TPGT);
522iscsi_flashnode_sess_attr(fnode, discovery_parent_idx,
523 ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX);
524iscsi_flashnode_sess_attr(fnode, discovery_parent_type,
525 ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE);
526iscsi_flashnode_sess_attr(fnode, chap_in_idx, ISCSI_FLASHNODE_CHAP_IN_IDX);
527iscsi_flashnode_sess_attr(fnode, chap_out_idx, ISCSI_FLASHNODE_CHAP_OUT_IDX);
528iscsi_flashnode_sess_attr(fnode, username, ISCSI_FLASHNODE_USERNAME);
529iscsi_flashnode_sess_attr(fnode, username_in, ISCSI_FLASHNODE_USERNAME_IN);
530iscsi_flashnode_sess_attr(fnode, password, ISCSI_FLASHNODE_PASSWORD);
531iscsi_flashnode_sess_attr(fnode, password_in, ISCSI_FLASHNODE_PASSWORD_IN);
532iscsi_flashnode_sess_attr(fnode, is_boot_target, ISCSI_FLASHNODE_IS_BOOT_TGT);
533
534static struct attribute *iscsi_flashnode_sess_attrs[] = {
535 &dev_attr_fnode_auto_snd_tgt_disable.attr,
536 &dev_attr_fnode_discovery_session.attr,
537 &dev_attr_fnode_portal_type.attr,
538 &dev_attr_fnode_entry_enable.attr,
539 &dev_attr_fnode_immediate_data.attr,
540 &dev_attr_fnode_initial_r2t.attr,
541 &dev_attr_fnode_data_seq_in_order.attr,
542 &dev_attr_fnode_data_pdu_in_order.attr,
543 &dev_attr_fnode_chap_auth.attr,
544 &dev_attr_fnode_discovery_logout.attr,
545 &dev_attr_fnode_bidi_chap.attr,
546 &dev_attr_fnode_discovery_auth_optional.attr,
547 &dev_attr_fnode_erl.attr,
548 &dev_attr_fnode_first_burst_len.attr,
549 &dev_attr_fnode_def_time2wait.attr,
550 &dev_attr_fnode_def_time2retain.attr,
551 &dev_attr_fnode_max_outstanding_r2t.attr,
552 &dev_attr_fnode_isid.attr,
553 &dev_attr_fnode_tsid.attr,
554 &dev_attr_fnode_max_burst_len.attr,
555 &dev_attr_fnode_def_taskmgmt_tmo.attr,
556 &dev_attr_fnode_targetalias.attr,
557 &dev_attr_fnode_targetname.attr,
558 &dev_attr_fnode_tpgt.attr,
559 &dev_attr_fnode_discovery_parent_idx.attr,
560 &dev_attr_fnode_discovery_parent_type.attr,
561 &dev_attr_fnode_chap_in_idx.attr,
562 &dev_attr_fnode_chap_out_idx.attr,
563 &dev_attr_fnode_username.attr,
564 &dev_attr_fnode_username_in.attr,
565 &dev_attr_fnode_password.attr,
566 &dev_attr_fnode_password_in.attr,
567 &dev_attr_fnode_is_boot_target.attr,
568 NULL,
569};
570
571static umode_t iscsi_flashnode_sess_attr_is_visible(struct kobject *kobj,
572 struct attribute *attr,
573 int i)
574{
575 struct device *dev = container_of(kobj, struct device, kobj);
576 struct iscsi_bus_flash_session *fnode_sess =
577 iscsi_dev_to_flash_session(dev);
578 struct iscsi_transport *t = fnode_sess->transport;
579 int param;
580
581 if (attr == &dev_attr_fnode_auto_snd_tgt_disable.attr) {
582 param = ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE;
583 } else if (attr == &dev_attr_fnode_discovery_session.attr) {
584 param = ISCSI_FLASHNODE_DISCOVERY_SESS;
585 } else if (attr == &dev_attr_fnode_portal_type.attr) {
586 param = ISCSI_FLASHNODE_PORTAL_TYPE;
587 } else if (attr == &dev_attr_fnode_entry_enable.attr) {
588 param = ISCSI_FLASHNODE_ENTRY_EN;
589 } else if (attr == &dev_attr_fnode_immediate_data.attr) {
590 param = ISCSI_FLASHNODE_IMM_DATA_EN;
591 } else if (attr == &dev_attr_fnode_initial_r2t.attr) {
592 param = ISCSI_FLASHNODE_INITIAL_R2T_EN;
593 } else if (attr == &dev_attr_fnode_data_seq_in_order.attr) {
594 param = ISCSI_FLASHNODE_DATASEQ_INORDER;
595 } else if (attr == &dev_attr_fnode_data_pdu_in_order.attr) {
596 param = ISCSI_FLASHNODE_PDU_INORDER;
597 } else if (attr == &dev_attr_fnode_chap_auth.attr) {
598 param = ISCSI_FLASHNODE_CHAP_AUTH_EN;
599 } else if (attr == &dev_attr_fnode_discovery_logout.attr) {
600 param = ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN;
601 } else if (attr == &dev_attr_fnode_bidi_chap.attr) {
602 param = ISCSI_FLASHNODE_BIDI_CHAP_EN;
603 } else if (attr == &dev_attr_fnode_discovery_auth_optional.attr) {
604 param = ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL;
605 } else if (attr == &dev_attr_fnode_erl.attr) {
606 param = ISCSI_FLASHNODE_ERL;
607 } else if (attr == &dev_attr_fnode_first_burst_len.attr) {
608 param = ISCSI_FLASHNODE_FIRST_BURST;
609 } else if (attr == &dev_attr_fnode_def_time2wait.attr) {
610 param = ISCSI_FLASHNODE_DEF_TIME2WAIT;
611 } else if (attr == &dev_attr_fnode_def_time2retain.attr) {
612 param = ISCSI_FLASHNODE_DEF_TIME2RETAIN;
613 } else if (attr == &dev_attr_fnode_max_outstanding_r2t.attr) {
614 param = ISCSI_FLASHNODE_MAX_R2T;
615 } else if (attr == &dev_attr_fnode_isid.attr) {
616 param = ISCSI_FLASHNODE_ISID;
617 } else if (attr == &dev_attr_fnode_tsid.attr) {
618 param = ISCSI_FLASHNODE_TSID;
619 } else if (attr == &dev_attr_fnode_max_burst_len.attr) {
620 param = ISCSI_FLASHNODE_MAX_BURST;
621 } else if (attr == &dev_attr_fnode_def_taskmgmt_tmo.attr) {
622 param = ISCSI_FLASHNODE_DEF_TASKMGMT_TMO;
623 } else if (attr == &dev_attr_fnode_targetalias.attr) {
624 param = ISCSI_FLASHNODE_ALIAS;
625 } else if (attr == &dev_attr_fnode_targetname.attr) {
626 param = ISCSI_FLASHNODE_NAME;
627 } else if (attr == &dev_attr_fnode_tpgt.attr) {
628 param = ISCSI_FLASHNODE_TPGT;
629 } else if (attr == &dev_attr_fnode_discovery_parent_idx.attr) {
630 param = ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX;
631 } else if (attr == &dev_attr_fnode_discovery_parent_type.attr) {
632 param = ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE;
633 } else if (attr == &dev_attr_fnode_chap_in_idx.attr) {
634 param = ISCSI_FLASHNODE_CHAP_IN_IDX;
635 } else if (attr == &dev_attr_fnode_chap_out_idx.attr) {
636 param = ISCSI_FLASHNODE_CHAP_OUT_IDX;
637 } else if (attr == &dev_attr_fnode_username.attr) {
638 param = ISCSI_FLASHNODE_USERNAME;
639 } else if (attr == &dev_attr_fnode_username_in.attr) {
640 param = ISCSI_FLASHNODE_USERNAME_IN;
641 } else if (attr == &dev_attr_fnode_password.attr) {
642 param = ISCSI_FLASHNODE_PASSWORD;
643 } else if (attr == &dev_attr_fnode_password_in.attr) {
644 param = ISCSI_FLASHNODE_PASSWORD_IN;
645 } else if (attr == &dev_attr_fnode_is_boot_target.attr) {
646 param = ISCSI_FLASHNODE_IS_BOOT_TGT;
647 } else {
648 WARN_ONCE(1, "Invalid flashnode session attr");
649 return 0;
650 }
651
652 return t->attr_is_visible(ISCSI_FLASHNODE_PARAM, param);
653}
654
655static struct attribute_group iscsi_flashnode_sess_attr_group = {
656 .attrs = iscsi_flashnode_sess_attrs,
657 .is_visible = iscsi_flashnode_sess_attr_is_visible,
658};
659
660static const struct attribute_group *iscsi_flashnode_sess_attr_groups[] = {
661 &iscsi_flashnode_sess_attr_group,
662 NULL,
663};
664
665static void iscsi_flashnode_sess_release(struct device *dev)
666{
667 struct iscsi_bus_flash_session *fnode_sess =
668 iscsi_dev_to_flash_session(dev);
669
670 kfree(fnode_sess->targetname);
671 kfree(fnode_sess->targetalias);
672 kfree(fnode_sess->portal_type);
673 kfree(fnode_sess);
674}
675
676struct device_type iscsi_flashnode_sess_dev_type = {
677 .name = "iscsi_flashnode_sess_dev_type",
678 .groups = iscsi_flashnode_sess_attr_groups,
679 .release = iscsi_flashnode_sess_release,
680};
681
682/* flash node connection attrs show */
683#define iscsi_flashnode_conn_attr_show(type, name, param) \
684static ssize_t \
685show_##type##_##name(struct device *dev, struct device_attribute *attr, \
686 char *buf) \
687{ \
688 struct iscsi_bus_flash_conn *fnode_conn = iscsi_dev_to_flash_conn(dev);\
689 struct iscsi_bus_flash_session *fnode_sess = \
690 iscsi_flash_conn_to_flash_session(fnode_conn);\
691 struct iscsi_transport *t = fnode_conn->transport; \
692 return t->get_flashnode_param(fnode_sess, param, buf); \
693} \
694
695
696#define iscsi_flashnode_conn_attr(type, name, param) \
697 iscsi_flashnode_conn_attr_show(type, name, param) \
698static ISCSI_FLASHNODE_ATTR(type, name, S_IRUGO, \
699 show_##type##_##name, NULL);
700
701/* Flash node connection attributes */
702
703iscsi_flashnode_conn_attr(fnode, is_fw_assigned_ipv6,
704 ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6);
705iscsi_flashnode_conn_attr(fnode, header_digest, ISCSI_FLASHNODE_HDR_DGST_EN);
706iscsi_flashnode_conn_attr(fnode, data_digest, ISCSI_FLASHNODE_DATA_DGST_EN);
707iscsi_flashnode_conn_attr(fnode, snack_req, ISCSI_FLASHNODE_SNACK_REQ_EN);
708iscsi_flashnode_conn_attr(fnode, tcp_timestamp_stat,
709 ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT);
710iscsi_flashnode_conn_attr(fnode, tcp_nagle_disable,
711 ISCSI_FLASHNODE_TCP_NAGLE_DISABLE);
712iscsi_flashnode_conn_attr(fnode, tcp_wsf_disable,
713 ISCSI_FLASHNODE_TCP_WSF_DISABLE);
714iscsi_flashnode_conn_attr(fnode, tcp_timer_scale,
715 ISCSI_FLASHNODE_TCP_TIMER_SCALE);
716iscsi_flashnode_conn_attr(fnode, tcp_timestamp_enable,
717 ISCSI_FLASHNODE_TCP_TIMESTAMP_EN);
718iscsi_flashnode_conn_attr(fnode, fragment_disable,
719 ISCSI_FLASHNODE_IP_FRAG_DISABLE);
720iscsi_flashnode_conn_attr(fnode, keepalive_tmo, ISCSI_FLASHNODE_KEEPALIVE_TMO);
721iscsi_flashnode_conn_attr(fnode, port, ISCSI_FLASHNODE_PORT);
722iscsi_flashnode_conn_attr(fnode, ipaddress, ISCSI_FLASHNODE_IPADDR);
723iscsi_flashnode_conn_attr(fnode, max_recv_dlength,
724 ISCSI_FLASHNODE_MAX_RECV_DLENGTH);
725iscsi_flashnode_conn_attr(fnode, max_xmit_dlength,
726 ISCSI_FLASHNODE_MAX_XMIT_DLENGTH);
727iscsi_flashnode_conn_attr(fnode, local_port, ISCSI_FLASHNODE_LOCAL_PORT);
728iscsi_flashnode_conn_attr(fnode, ipv4_tos, ISCSI_FLASHNODE_IPV4_TOS);
729iscsi_flashnode_conn_attr(fnode, ipv6_traffic_class, ISCSI_FLASHNODE_IPV6_TC);
730iscsi_flashnode_conn_attr(fnode, ipv6_flow_label,
731 ISCSI_FLASHNODE_IPV6_FLOW_LABEL);
732iscsi_flashnode_conn_attr(fnode, redirect_ipaddr,
733 ISCSI_FLASHNODE_REDIRECT_IPADDR);
734iscsi_flashnode_conn_attr(fnode, max_segment_size,
735 ISCSI_FLASHNODE_MAX_SEGMENT_SIZE);
736iscsi_flashnode_conn_attr(fnode, link_local_ipv6,
737 ISCSI_FLASHNODE_LINK_LOCAL_IPV6);
738iscsi_flashnode_conn_attr(fnode, tcp_xmit_wsf, ISCSI_FLASHNODE_TCP_XMIT_WSF);
739iscsi_flashnode_conn_attr(fnode, tcp_recv_wsf, ISCSI_FLASHNODE_TCP_RECV_WSF);
740iscsi_flashnode_conn_attr(fnode, statsn, ISCSI_FLASHNODE_STATSN);
741iscsi_flashnode_conn_attr(fnode, exp_statsn, ISCSI_FLASHNODE_EXP_STATSN);
742
743static struct attribute *iscsi_flashnode_conn_attrs[] = {
744 &dev_attr_fnode_is_fw_assigned_ipv6.attr,
745 &dev_attr_fnode_header_digest.attr,
746 &dev_attr_fnode_data_digest.attr,
747 &dev_attr_fnode_snack_req.attr,
748 &dev_attr_fnode_tcp_timestamp_stat.attr,
749 &dev_attr_fnode_tcp_nagle_disable.attr,
750 &dev_attr_fnode_tcp_wsf_disable.attr,
751 &dev_attr_fnode_tcp_timer_scale.attr,
752 &dev_attr_fnode_tcp_timestamp_enable.attr,
753 &dev_attr_fnode_fragment_disable.attr,
754 &dev_attr_fnode_max_recv_dlength.attr,
755 &dev_attr_fnode_max_xmit_dlength.attr,
756 &dev_attr_fnode_keepalive_tmo.attr,
757 &dev_attr_fnode_port.attr,
758 &dev_attr_fnode_ipaddress.attr,
759 &dev_attr_fnode_redirect_ipaddr.attr,
760 &dev_attr_fnode_max_segment_size.attr,
761 &dev_attr_fnode_local_port.attr,
762 &dev_attr_fnode_ipv4_tos.attr,
763 &dev_attr_fnode_ipv6_traffic_class.attr,
764 &dev_attr_fnode_ipv6_flow_label.attr,
765 &dev_attr_fnode_link_local_ipv6.attr,
766 &dev_attr_fnode_tcp_xmit_wsf.attr,
767 &dev_attr_fnode_tcp_recv_wsf.attr,
768 &dev_attr_fnode_statsn.attr,
769 &dev_attr_fnode_exp_statsn.attr,
770 NULL,
771};
772
773static umode_t iscsi_flashnode_conn_attr_is_visible(struct kobject *kobj,
774 struct attribute *attr,
775 int i)
776{
777 struct device *dev = container_of(kobj, struct device, kobj);
778 struct iscsi_bus_flash_conn *fnode_conn = iscsi_dev_to_flash_conn(dev);
779 struct iscsi_transport *t = fnode_conn->transport;
780 int param;
781
782 if (attr == &dev_attr_fnode_is_fw_assigned_ipv6.attr) {
783 param = ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6;
784 } else if (attr == &dev_attr_fnode_header_digest.attr) {
785 param = ISCSI_FLASHNODE_HDR_DGST_EN;
786 } else if (attr == &dev_attr_fnode_data_digest.attr) {
787 param = ISCSI_FLASHNODE_DATA_DGST_EN;
788 } else if (attr == &dev_attr_fnode_snack_req.attr) {
789 param = ISCSI_FLASHNODE_SNACK_REQ_EN;
790 } else if (attr == &dev_attr_fnode_tcp_timestamp_stat.attr) {
791 param = ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT;
792 } else if (attr == &dev_attr_fnode_tcp_nagle_disable.attr) {
793 param = ISCSI_FLASHNODE_TCP_NAGLE_DISABLE;
794 } else if (attr == &dev_attr_fnode_tcp_wsf_disable.attr) {
795 param = ISCSI_FLASHNODE_TCP_WSF_DISABLE;
796 } else if (attr == &dev_attr_fnode_tcp_timer_scale.attr) {
797 param = ISCSI_FLASHNODE_TCP_TIMER_SCALE;
798 } else if (attr == &dev_attr_fnode_tcp_timestamp_enable.attr) {
799 param = ISCSI_FLASHNODE_TCP_TIMESTAMP_EN;
800 } else if (attr == &dev_attr_fnode_fragment_disable.attr) {
801 param = ISCSI_FLASHNODE_IP_FRAG_DISABLE;
802 } else if (attr == &dev_attr_fnode_max_recv_dlength.attr) {
803 param = ISCSI_FLASHNODE_MAX_RECV_DLENGTH;
804 } else if (attr == &dev_attr_fnode_max_xmit_dlength.attr) {
805 param = ISCSI_FLASHNODE_MAX_XMIT_DLENGTH;
806 } else if (attr == &dev_attr_fnode_keepalive_tmo.attr) {
807 param = ISCSI_FLASHNODE_KEEPALIVE_TMO;
808 } else if (attr == &dev_attr_fnode_port.attr) {
809 param = ISCSI_FLASHNODE_PORT;
810 } else if (attr == &dev_attr_fnode_ipaddress.attr) {
811 param = ISCSI_FLASHNODE_IPADDR;
812 } else if (attr == &dev_attr_fnode_redirect_ipaddr.attr) {
813 param = ISCSI_FLASHNODE_REDIRECT_IPADDR;
814 } else if (attr == &dev_attr_fnode_max_segment_size.attr) {
815 param = ISCSI_FLASHNODE_MAX_SEGMENT_SIZE;
816 } else if (attr == &dev_attr_fnode_local_port.attr) {
817 param = ISCSI_FLASHNODE_LOCAL_PORT;
818 } else if (attr == &dev_attr_fnode_ipv4_tos.attr) {
819 param = ISCSI_FLASHNODE_IPV4_TOS;
820 } else if (attr == &dev_attr_fnode_ipv6_traffic_class.attr) {
821 param = ISCSI_FLASHNODE_IPV6_TC;
822 } else if (attr == &dev_attr_fnode_ipv6_flow_label.attr) {
823 param = ISCSI_FLASHNODE_IPV6_FLOW_LABEL;
824 } else if (attr == &dev_attr_fnode_link_local_ipv6.attr) {
825 param = ISCSI_FLASHNODE_LINK_LOCAL_IPV6;
826 } else if (attr == &dev_attr_fnode_tcp_xmit_wsf.attr) {
827 param = ISCSI_FLASHNODE_TCP_XMIT_WSF;
828 } else if (attr == &dev_attr_fnode_tcp_recv_wsf.attr) {
829 param = ISCSI_FLASHNODE_TCP_RECV_WSF;
830 } else if (attr == &dev_attr_fnode_statsn.attr) {
831 param = ISCSI_FLASHNODE_STATSN;
832 } else if (attr == &dev_attr_fnode_exp_statsn.attr) {
833 param = ISCSI_FLASHNODE_EXP_STATSN;
834 } else {
835 WARN_ONCE(1, "Invalid flashnode connection attr");
836 return 0;
837 }
838
839 return t->attr_is_visible(ISCSI_FLASHNODE_PARAM, param);
840}
841
842static struct attribute_group iscsi_flashnode_conn_attr_group = {
843 .attrs = iscsi_flashnode_conn_attrs,
844 .is_visible = iscsi_flashnode_conn_attr_is_visible,
845};
846
847static const struct attribute_group *iscsi_flashnode_conn_attr_groups[] = {
848 &iscsi_flashnode_conn_attr_group,
849 NULL,
850};
851
852static void iscsi_flashnode_conn_release(struct device *dev)
853{
854 struct iscsi_bus_flash_conn *fnode_conn = iscsi_dev_to_flash_conn(dev);
855
856 kfree(fnode_conn->ipaddress);
857 kfree(fnode_conn->redirect_ipaddr);
858 kfree(fnode_conn->link_local_ipv6_addr);
859 kfree(fnode_conn);
860}
861
862struct device_type iscsi_flashnode_conn_dev_type = {
863 .name = "iscsi_flashnode_conn_dev_type",
864 .groups = iscsi_flashnode_conn_attr_groups,
865 .release = iscsi_flashnode_conn_release,
866};
867
868struct bus_type iscsi_flashnode_bus;
869
870int iscsi_flashnode_bus_match(struct device *dev,
871 struct device_driver *drv)
872{
873 if (dev->bus == &iscsi_flashnode_bus)
874 return 1;
875 return 0;
876}
877EXPORT_SYMBOL_GPL(iscsi_flashnode_bus_match);
878
879struct bus_type iscsi_flashnode_bus = {
880 .name = "iscsi_flashnode",
881 .match = &iscsi_flashnode_bus_match,
882};
883
884/**
885 * iscsi_create_flashnode_sess - Add flashnode session entry in sysfs
886 * @shost: pointer to host data
887 * @index: index of flashnode to add in sysfs
888 * @transport: pointer to transport data
889 * @dd_size: total size to allocate
890 *
891 * Adds a sysfs entry for the flashnode session attributes
892 *
893 * Returns:
894 * pointer to allocated flashnode sess on sucess
895 * %NULL on failure
896 */
897struct iscsi_bus_flash_session *
898iscsi_create_flashnode_sess(struct Scsi_Host *shost, int index,
899 struct iscsi_transport *transport,
900 int dd_size)
901{
902 struct iscsi_bus_flash_session *fnode_sess;
903 int err;
904
905 fnode_sess = kzalloc(sizeof(*fnode_sess) + dd_size, GFP_KERNEL);
906 if (!fnode_sess)
907 return NULL;
908
909 fnode_sess->transport = transport;
910 fnode_sess->target_id = index;
911 fnode_sess->dev.type = &iscsi_flashnode_sess_dev_type;
912 fnode_sess->dev.bus = &iscsi_flashnode_bus;
913 fnode_sess->dev.parent = &shost->shost_gendev;
914 dev_set_name(&fnode_sess->dev, "flashnode_sess-%u:%u",
915 shost->host_no, index);
916
917 err = device_register(&fnode_sess->dev);
918 if (err)
919 goto free_fnode_sess;
920
921 if (dd_size)
922 fnode_sess->dd_data = &fnode_sess[1];
923
924 return fnode_sess;
925
926free_fnode_sess:
927 kfree(fnode_sess);
928 return NULL;
929}
930EXPORT_SYMBOL_GPL(iscsi_create_flashnode_sess);
931
932/**
933 * iscsi_create_flashnode_conn - Add flashnode conn entry in sysfs
934 * @shost: pointer to host data
935 * @fnode_sess: pointer to the parent flashnode session entry
936 * @transport: pointer to transport data
937 * @dd_size: total size to allocate
938 *
939 * Adds a sysfs entry for the flashnode connection attributes
940 *
941 * Returns:
942 * pointer to allocated flashnode conn on success
943 * %NULL on failure
944 */
945struct iscsi_bus_flash_conn *
946iscsi_create_flashnode_conn(struct Scsi_Host *shost,
947 struct iscsi_bus_flash_session *fnode_sess,
948 struct iscsi_transport *transport,
949 int dd_size)
950{
951 struct iscsi_bus_flash_conn *fnode_conn;
952 int err;
953
954 fnode_conn = kzalloc(sizeof(*fnode_conn) + dd_size, GFP_KERNEL);
955 if (!fnode_conn)
956 return NULL;
957
958 fnode_conn->transport = transport;
959 fnode_conn->dev.type = &iscsi_flashnode_conn_dev_type;
960 fnode_conn->dev.bus = &iscsi_flashnode_bus;
961 fnode_conn->dev.parent = &fnode_sess->dev;
962 dev_set_name(&fnode_conn->dev, "flashnode_conn-%u:%u:0",
963 shost->host_no, fnode_sess->target_id);
964
965 err = device_register(&fnode_conn->dev);
966 if (err)
967 goto free_fnode_conn;
968
969 if (dd_size)
970 fnode_conn->dd_data = &fnode_conn[1];
971
972 return fnode_conn;
973
974free_fnode_conn:
975 kfree(fnode_conn);
976 return NULL;
977}
978EXPORT_SYMBOL_GPL(iscsi_create_flashnode_conn);
979
980/**
981 * iscsi_is_flashnode_conn_dev - verify passed device is to be flashnode conn
982 * @dev: device to verify
983 * @data: pointer to data containing value to use for verification
984 *
985 * Verifies if the passed device is flashnode conn device
986 *
987 * Returns:
988 * 1 on success
989 * 0 on failure
990 */
991int iscsi_is_flashnode_conn_dev(struct device *dev, void *data)
992{
993 return dev->bus == &iscsi_flashnode_bus;
994}
995EXPORT_SYMBOL_GPL(iscsi_is_flashnode_conn_dev);
996
997static int iscsi_destroy_flashnode_conn(struct iscsi_bus_flash_conn *fnode_conn)
998{
999 device_unregister(&fnode_conn->dev);
1000 return 0;
1001}
1002
1003static int flashnode_match_index(struct device *dev, void *data)
1004{
1005 struct iscsi_bus_flash_session *fnode_sess = NULL;
1006 int ret = 0;
1007
1008 if (!iscsi_flashnode_bus_match(dev, NULL))
1009 goto exit_match_index;
1010
1011 fnode_sess = iscsi_dev_to_flash_session(dev);
1012 ret = (fnode_sess->target_id == *((int *)data)) ? 1 : 0;
1013
1014exit_match_index:
1015 return ret;
1016}
1017
1018/**
1019 * iscsi_get_flashnode_by_index -finds flashnode session entry by index
1020 * @shost: pointer to host data
Mike Christie8526cb12013-05-06 12:06:56 -05001021 * @idx: index to match
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04001022 *
1023 * Finds the flashnode session object for the passed index
1024 *
1025 * Returns:
1026 * pointer to found flashnode session object on success
1027 * %NULL on failure
1028 */
1029static struct iscsi_bus_flash_session *
Mike Christie8526cb12013-05-06 12:06:56 -05001030iscsi_get_flashnode_by_index(struct Scsi_Host *shost, uint32_t idx)
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04001031{
1032 struct iscsi_bus_flash_session *fnode_sess = NULL;
1033 struct device *dev;
1034
Mike Christie8526cb12013-05-06 12:06:56 -05001035 dev = device_find_child(&shost->shost_gendev, &idx,
1036 flashnode_match_index);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04001037 if (dev)
1038 fnode_sess = iscsi_dev_to_flash_session(dev);
1039
1040 return fnode_sess;
1041}
1042
1043/**
1044 * iscsi_find_flashnode_sess - finds flashnode session entry
1045 * @shost: pointer to host data
1046 * @data: pointer to data containing value to use for comparison
1047 * @fn: function pointer that does actual comparison
1048 *
1049 * Finds the flashnode session object comparing the data passed using logic
1050 * defined in passed function pointer
1051 *
1052 * Returns:
1053 * pointer to found flashnode session device object on success
1054 * %NULL on failure
1055 */
1056struct device *
1057iscsi_find_flashnode_sess(struct Scsi_Host *shost, void *data,
1058 int (*fn)(struct device *dev, void *data))
1059{
Mike Christie8526cb12013-05-06 12:06:56 -05001060 return device_find_child(&shost->shost_gendev, data, fn);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04001061}
1062EXPORT_SYMBOL_GPL(iscsi_find_flashnode_sess);
1063
1064/**
1065 * iscsi_find_flashnode_conn - finds flashnode connection entry
1066 * @fnode_sess: pointer to parent flashnode session entry
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04001067 *
1068 * Finds the flashnode connection object comparing the data passed using logic
1069 * defined in passed function pointer
1070 *
1071 * Returns:
1072 * pointer to found flashnode connection device object on success
1073 * %NULL on failure
1074 */
1075struct device *
Mike Christie8526cb12013-05-06 12:06:56 -05001076iscsi_find_flashnode_conn(struct iscsi_bus_flash_session *fnode_sess)
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04001077{
Mike Christie8526cb12013-05-06 12:06:56 -05001078 return device_find_child(&fnode_sess->dev, NULL,
1079 iscsi_is_flashnode_conn_dev);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04001080}
1081EXPORT_SYMBOL_GPL(iscsi_find_flashnode_conn);
1082
1083static int iscsi_iter_destroy_flashnode_conn_fn(struct device *dev, void *data)
1084{
1085 if (!iscsi_is_flashnode_conn_dev(dev, NULL))
1086 return 0;
1087
1088 return iscsi_destroy_flashnode_conn(iscsi_dev_to_flash_conn(dev));
1089}
1090
1091/**
1092 * iscsi_destroy_flashnode_sess - destory flashnode session entry
1093 * @fnode_sess: pointer to flashnode session entry to be destroyed
1094 *
1095 * Deletes the flashnode session entry and all children flashnode connection
1096 * entries from sysfs
1097 */
1098void iscsi_destroy_flashnode_sess(struct iscsi_bus_flash_session *fnode_sess)
1099{
1100 int err;
1101
1102 err = device_for_each_child(&fnode_sess->dev, NULL,
1103 iscsi_iter_destroy_flashnode_conn_fn);
1104 if (err)
1105 pr_err("Could not delete all connections for %s. Error %d.\n",
1106 fnode_sess->dev.kobj.name, err);
1107
1108 device_unregister(&fnode_sess->dev);
1109}
1110EXPORT_SYMBOL_GPL(iscsi_destroy_flashnode_sess);
1111
1112static int iscsi_iter_destroy_flashnode_fn(struct device *dev, void *data)
1113{
1114 if (!iscsi_flashnode_bus_match(dev, NULL))
1115 return 0;
1116
1117 iscsi_destroy_flashnode_sess(iscsi_dev_to_flash_session(dev));
1118 return 0;
1119}
1120
1121/**
1122 * iscsi_destroy_all_flashnode - destory all flashnode session entries
1123 * @shost: pointer to host data
1124 *
1125 * Destroys all the flashnode session entries and all corresponding children
1126 * flashnode connection entries from sysfs
1127 */
1128void iscsi_destroy_all_flashnode(struct Scsi_Host *shost)
1129{
1130 device_for_each_child(&shost->shost_gendev, NULL,
1131 iscsi_iter_destroy_flashnode_fn);
1132}
1133EXPORT_SYMBOL_GPL(iscsi_destroy_all_flashnode);
1134
1135/*
Mike Christie90eeb012011-07-25 13:48:50 -05001136 * BSG support
1137 */
1138/**
1139 * iscsi_bsg_host_dispatch - Dispatch command to LLD.
1140 * @job: bsg job to be processed
1141 */
1142static int iscsi_bsg_host_dispatch(struct bsg_job *job)
1143{
1144 struct Scsi_Host *shost = iscsi_job_to_shost(job);
1145 struct iscsi_bsg_request *req = job->request;
1146 struct iscsi_bsg_reply *reply = job->reply;
1147 struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
1148 int cmdlen = sizeof(uint32_t); /* start with length of msgcode */
1149 int ret;
1150
1151 /* check if we have the msgcode value at least */
1152 if (job->request_len < sizeof(uint32_t)) {
1153 ret = -ENOMSG;
1154 goto fail_host_msg;
1155 }
1156
1157 /* Validate the host command */
1158 switch (req->msgcode) {
1159 case ISCSI_BSG_HST_VENDOR:
1160 cmdlen += sizeof(struct iscsi_bsg_host_vendor);
1161 if ((shost->hostt->vendor_id == 0L) ||
1162 (req->rqst_data.h_vendor.vendor_id !=
1163 shost->hostt->vendor_id)) {
1164 ret = -ESRCH;
1165 goto fail_host_msg;
1166 }
1167 break;
1168 default:
1169 ret = -EBADR;
1170 goto fail_host_msg;
1171 }
1172
1173 /* check if we really have all the request data needed */
1174 if (job->request_len < cmdlen) {
1175 ret = -ENOMSG;
1176 goto fail_host_msg;
1177 }
1178
1179 ret = i->iscsi_transport->bsg_request(job);
1180 if (!ret)
1181 return 0;
1182
1183fail_host_msg:
1184 /* return the errno failure code as the only status */
1185 BUG_ON(job->reply_len < sizeof(uint32_t));
1186 reply->reply_payload_rcv_len = 0;
1187 reply->result = ret;
1188 job->reply_len = sizeof(uint32_t);
1189 bsg_job_done(job, ret, 0);
1190 return 0;
1191}
1192
1193/**
1194 * iscsi_bsg_host_add - Create and add the bsg hooks to receive requests
1195 * @shost: shost for iscsi_host
Marcos Paulo de Souzaeae627e2011-11-02 11:17:17 -02001196 * @ihost: iscsi_cls_host adding the structures to
Mike Christie90eeb012011-07-25 13:48:50 -05001197 */
1198static int
1199iscsi_bsg_host_add(struct Scsi_Host *shost, struct iscsi_cls_host *ihost)
1200{
1201 struct device *dev = &shost->shost_gendev;
1202 struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
1203 struct request_queue *q;
1204 char bsg_name[20];
1205 int ret;
1206
1207 if (!i->iscsi_transport->bsg_request)
1208 return -ENOTSUPP;
1209
1210 snprintf(bsg_name, sizeof(bsg_name), "iscsi_host%d", shost->host_no);
1211
1212 q = __scsi_alloc_queue(shost, bsg_request_fn);
1213 if (!q)
1214 return -ENOMEM;
1215
1216 ret = bsg_setup_queue(dev, q, bsg_name, iscsi_bsg_host_dispatch, 0);
1217 if (ret) {
1218 shost_printk(KERN_ERR, shost, "bsg interface failed to "
1219 "initialize - no request queue\n");
1220 blk_cleanup_queue(q);
1221 return ret;
1222 }
1223
1224 ihost->bsg_q = q;
1225 return 0;
1226}
1227
Mike Christie30a6c652006-04-06 21:13:39 -05001228static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
Tony Jonesee959b02008-02-22 00:13:36 +01001229 struct device *cdev)
Mike Christie30a6c652006-04-06 21:13:39 -05001230{
1231 struct Scsi_Host *shost = dev_to_shost(dev);
Mike Christie32c6e1b2008-05-21 15:53:58 -05001232 struct iscsi_cls_host *ihost = shost->shost_data;
Mike Christie30a6c652006-04-06 21:13:39 -05001233
1234 memset(ihost, 0, sizeof(*ihost));
Mike Christie8aae18a2008-01-31 13:36:48 -06001235 atomic_set(&ihost->nr_scans, 0);
Mike Christie79706342008-05-21 15:54:12 -05001236 mutex_init(&ihost->mutex);
Mike Christie90eeb012011-07-25 13:48:50 -05001237
1238 iscsi_bsg_host_add(shost, ihost);
1239 /* ignore any bsg add error - we just can't do sgio */
1240
1241 return 0;
1242}
1243
1244static int iscsi_remove_host(struct transport_container *tc,
1245 struct device *dev, struct device *cdev)
1246{
1247 struct Scsi_Host *shost = dev_to_shost(dev);
1248 struct iscsi_cls_host *ihost = shost->shost_data;
1249
1250 if (ihost->bsg_q) {
Tejun Heo86072d82012-06-04 20:40:54 -07001251 bsg_unregister_queue(ihost->bsg_q);
Mike Christie90eeb012011-07-25 13:48:50 -05001252 blk_cleanup_queue(ihost->bsg_q);
1253 }
Mike Christie30a6c652006-04-06 21:13:39 -05001254 return 0;
1255}
1256
1257static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
1258 "iscsi_host",
1259 iscsi_setup_host,
Mike Christie90eeb012011-07-25 13:48:50 -05001260 iscsi_remove_host,
Mike Christie30a6c652006-04-06 21:13:39 -05001261 NULL);
1262
Alex Aizman0896b752005-08-04 19:33:07 -07001263static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
1264 "iscsi_session",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 NULL,
1266 NULL,
1267 NULL);
1268
Alex Aizman0896b752005-08-04 19:33:07 -07001269static DECLARE_TRANSPORT_CLASS(iscsi_connection_class,
1270 "iscsi_connection",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 NULL,
1272 NULL,
1273 NULL);
Alex Aizman0896b752005-08-04 19:33:07 -07001274
1275static struct sock *nls;
Arjan van de Ven0b950672006-01-11 13:16:10 +01001276static DEFINE_MUTEX(rx_queue_mutex);
Alex Aizman0896b752005-08-04 19:33:07 -07001277
Mike Christie7b7232f2006-02-01 21:06:49 -06001278static LIST_HEAD(sesslist);
1279static DEFINE_SPINLOCK(sesslock);
Alex Aizman0896b752005-08-04 19:33:07 -07001280static LIST_HEAD(connlist);
1281static DEFINE_SPINLOCK(connlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
Mike Christieb5c7a122006-04-06 21:13:33 -05001283static uint32_t iscsi_conn_get_sid(struct iscsi_cls_conn *conn)
1284{
1285 struct iscsi_cls_session *sess = iscsi_dev_to_session(conn->dev.parent);
1286 return sess->sid;
1287}
1288
1289/*
1290 * Returns the matching session to a given sid
1291 */
1292static struct iscsi_cls_session *iscsi_session_lookup(uint32_t sid)
Mike Christie7b7232f2006-02-01 21:06:49 -06001293{
1294 unsigned long flags;
1295 struct iscsi_cls_session *sess;
1296
1297 spin_lock_irqsave(&sesslock, flags);
1298 list_for_each_entry(sess, &sesslist, sess_list) {
Mike Christieb5c7a122006-04-06 21:13:33 -05001299 if (sess->sid == sid) {
Mike Christie7b7232f2006-02-01 21:06:49 -06001300 spin_unlock_irqrestore(&sesslock, flags);
1301 return sess;
1302 }
1303 }
1304 spin_unlock_irqrestore(&sesslock, flags);
1305 return NULL;
1306}
1307
Mike Christieb5c7a122006-04-06 21:13:33 -05001308/*
1309 * Returns the matching connection to a given sid / cid tuple
1310 */
1311static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid)
Mike Christie7b7232f2006-02-01 21:06:49 -06001312{
1313 unsigned long flags;
1314 struct iscsi_cls_conn *conn;
1315
1316 spin_lock_irqsave(&connlock, flags);
1317 list_for_each_entry(conn, &connlist, conn_list) {
Mike Christieb5c7a122006-04-06 21:13:33 -05001318 if ((conn->cid == cid) && (iscsi_conn_get_sid(conn) == sid)) {
Mike Christie7b7232f2006-02-01 21:06:49 -06001319 spin_unlock_irqrestore(&connlock, flags);
1320 return conn;
1321 }
1322 }
1323 spin_unlock_irqrestore(&connlock, flags);
1324 return NULL;
1325}
1326
Mike Christie7b8631b2006-01-13 18:05:50 -06001327/*
1328 * The following functions can be used by LLDs that allocate
1329 * their own scsi_hosts or by software iscsi LLDs
1330 */
Mike Christie6eabafb2008-01-31 13:36:43 -06001331static struct {
1332 int value;
1333 char *name;
1334} iscsi_session_state_names[] = {
1335 { ISCSI_SESSION_LOGGED_IN, "LOGGED_IN" },
1336 { ISCSI_SESSION_FAILED, "FAILED" },
1337 { ISCSI_SESSION_FREE, "FREE" },
1338};
1339
Adrian Bunk3b0f2082008-02-13 23:30:17 +02001340static const char *iscsi_session_state_name(int state)
Mike Christie6eabafb2008-01-31 13:36:43 -06001341{
1342 int i;
1343 char *name = NULL;
1344
1345 for (i = 0; i < ARRAY_SIZE(iscsi_session_state_names); i++) {
1346 if (iscsi_session_state_names[i].value == state) {
1347 name = iscsi_session_state_names[i].name;
1348 break;
1349 }
1350 }
1351 return name;
1352}
1353
1354int iscsi_session_chkready(struct iscsi_cls_session *session)
1355{
1356 unsigned long flags;
1357 int err;
1358
1359 spin_lock_irqsave(&session->lock, flags);
1360 switch (session->state) {
1361 case ISCSI_SESSION_LOGGED_IN:
1362 err = 0;
1363 break;
1364 case ISCSI_SESSION_FAILED:
Andrew Vasquez9a1a69a12009-04-29 13:12:39 -05001365 err = DID_IMM_RETRY << 16;
Mike Christie6eabafb2008-01-31 13:36:43 -06001366 break;
1367 case ISCSI_SESSION_FREE:
Mike Christie56d7fcf2008-08-19 18:45:26 -05001368 err = DID_TRANSPORT_FAILFAST << 16;
Mike Christie6eabafb2008-01-31 13:36:43 -06001369 break;
1370 default:
1371 err = DID_NO_CONNECT << 16;
1372 break;
1373 }
1374 spin_unlock_irqrestore(&session->lock, flags);
1375 return err;
1376}
1377EXPORT_SYMBOL_GPL(iscsi_session_chkready);
1378
Manish Rangankar17fa5752011-07-25 13:48:52 -05001379int iscsi_is_session_online(struct iscsi_cls_session *session)
1380{
1381 unsigned long flags;
1382 int ret = 0;
1383
1384 spin_lock_irqsave(&session->lock, flags);
1385 if (session->state == ISCSI_SESSION_LOGGED_IN)
1386 ret = 1;
1387 spin_unlock_irqrestore(&session->lock, flags);
1388 return ret;
1389}
1390EXPORT_SYMBOL_GPL(iscsi_is_session_online);
1391
Mike Christie7b8631b2006-01-13 18:05:50 -06001392static void iscsi_session_release(struct device *dev)
1393{
1394 struct iscsi_cls_session *session = iscsi_dev_to_session(dev);
Mike Christie7b8631b2006-01-13 18:05:50 -06001395 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
Mike Christie7b8631b2006-01-13 18:05:50 -06001397 shost = iscsi_session_to_shost(session);
1398 scsi_host_put(shost);
Mike Christie632248a2009-08-20 15:11:01 -05001399 ISCSI_DBG_TRANS_SESSION(session, "Completing session release\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06001400 kfree(session);
Mike Christie7b8631b2006-01-13 18:05:50 -06001401}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Nilesh Javali6260a5d2012-02-27 03:08:51 -08001403int iscsi_is_session_dev(const struct device *dev)
Mike Christie7b8631b2006-01-13 18:05:50 -06001404{
1405 return dev->release == iscsi_session_release;
1406}
Nilesh Javali6260a5d2012-02-27 03:08:51 -08001407EXPORT_SYMBOL_GPL(iscsi_is_session_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
Mike Christiea4804cd2008-05-21 15:54:00 -05001409static int iscsi_iter_session_fn(struct device *dev, void *data)
1410{
1411 void (* fn) (struct iscsi_cls_session *) = data;
1412
1413 if (!iscsi_is_session_dev(dev))
1414 return 0;
1415 fn(iscsi_dev_to_session(dev));
1416 return 0;
1417}
1418
1419void iscsi_host_for_each_session(struct Scsi_Host *shost,
1420 void (*fn)(struct iscsi_cls_session *))
1421{
1422 device_for_each_child(&shost->shost_gendev, fn,
1423 iscsi_iter_session_fn);
1424}
1425EXPORT_SYMBOL_GPL(iscsi_host_for_each_session);
1426
Mike Christie8aae18a2008-01-31 13:36:48 -06001427/**
1428 * iscsi_scan_finished - helper to report when running scans are done
1429 * @shost: scsi host
1430 * @time: scan run time
1431 *
1432 * This function can be used by drives like qla4xxx to report to the scsi
1433 * layer when the scans it kicked off at module load time are done.
1434 */
1435int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time)
1436{
Mike Christie32c6e1b2008-05-21 15:53:58 -05001437 struct iscsi_cls_host *ihost = shost->shost_data;
Mike Christie8aae18a2008-01-31 13:36:48 -06001438 /*
1439 * qla4xxx will have kicked off some session unblocks before calling
1440 * scsi_scan_host, so just wait for them to complete.
1441 */
1442 return !atomic_read(&ihost->nr_scans);
1443}
1444EXPORT_SYMBOL_GPL(iscsi_scan_finished);
1445
Mike Christie79706342008-05-21 15:54:12 -05001446struct iscsi_scan_data {
1447 unsigned int channel;
1448 unsigned int id;
1449 unsigned int lun;
1450};
1451
1452static int iscsi_user_scan_session(struct device *dev, void *data)
1453{
1454 struct iscsi_scan_data *scan_data = data;
1455 struct iscsi_cls_session *session;
1456 struct Scsi_Host *shost;
1457 struct iscsi_cls_host *ihost;
1458 unsigned long flags;
1459 unsigned int id;
1460
1461 if (!iscsi_is_session_dev(dev))
1462 return 0;
1463
1464 session = iscsi_dev_to_session(dev);
Mike Christie632248a2009-08-20 15:11:01 -05001465
1466 ISCSI_DBG_TRANS_SESSION(session, "Scanning session\n");
1467
Mike Christie79706342008-05-21 15:54:12 -05001468 shost = iscsi_session_to_shost(session);
1469 ihost = shost->shost_data;
1470
1471 mutex_lock(&ihost->mutex);
1472 spin_lock_irqsave(&session->lock, flags);
1473 if (session->state != ISCSI_SESSION_LOGGED_IN) {
1474 spin_unlock_irqrestore(&session->lock, flags);
Mike Christie632248a2009-08-20 15:11:01 -05001475 goto user_scan_exit;
Mike Christie79706342008-05-21 15:54:12 -05001476 }
1477 id = session->target_id;
1478 spin_unlock_irqrestore(&session->lock, flags);
1479
1480 if (id != ISCSI_MAX_TARGET) {
1481 if ((scan_data->channel == SCAN_WILD_CARD ||
1482 scan_data->channel == 0) &&
1483 (scan_data->id == SCAN_WILD_CARD ||
1484 scan_data->id == id))
1485 scsi_scan_target(&session->dev, 0, id,
1486 scan_data->lun, 1);
1487 }
Mike Christie632248a2009-08-20 15:11:01 -05001488
1489user_scan_exit:
Mike Christie79706342008-05-21 15:54:12 -05001490 mutex_unlock(&ihost->mutex);
Mike Christie632248a2009-08-20 15:11:01 -05001491 ISCSI_DBG_TRANS_SESSION(session, "Completed session scan\n");
Mike Christie79706342008-05-21 15:54:12 -05001492 return 0;
1493}
1494
Mike Christie30a6c652006-04-06 21:13:39 -05001495static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
1496 uint id, uint lun)
1497{
Mike Christie79706342008-05-21 15:54:12 -05001498 struct iscsi_scan_data scan_data;
Mike Christie30a6c652006-04-06 21:13:39 -05001499
Mike Christie79706342008-05-21 15:54:12 -05001500 scan_data.channel = channel;
1501 scan_data.id = id;
1502 scan_data.lun = lun;
Mike Christie30a6c652006-04-06 21:13:39 -05001503
Mike Christie79706342008-05-21 15:54:12 -05001504 return device_for_each_child(&shost->shost_gendev, &scan_data,
1505 iscsi_user_scan_session);
Mike Christie30a6c652006-04-06 21:13:39 -05001506}
1507
Mike Christiebd976f62008-01-31 13:36:46 -06001508static void iscsi_scan_session(struct work_struct *work)
1509{
1510 struct iscsi_cls_session *session =
1511 container_of(work, struct iscsi_cls_session, scan_work);
Mike Christie8aae18a2008-01-31 13:36:48 -06001512 struct Scsi_Host *shost = iscsi_session_to_shost(session);
Mike Christie32c6e1b2008-05-21 15:53:58 -05001513 struct iscsi_cls_host *ihost = shost->shost_data;
Mike Christie79706342008-05-21 15:54:12 -05001514 struct iscsi_scan_data scan_data;
Mike Christiebd976f62008-01-31 13:36:46 -06001515
Mike Christie79706342008-05-21 15:54:12 -05001516 scan_data.channel = 0;
1517 scan_data.id = SCAN_WILD_CARD;
1518 scan_data.lun = SCAN_WILD_CARD;
Mike Christiebd976f62008-01-31 13:36:46 -06001519
Mike Christie79706342008-05-21 15:54:12 -05001520 iscsi_user_scan_session(&session->dev, &scan_data);
Mike Christie8aae18a2008-01-31 13:36:48 -06001521 atomic_dec(&ihost->nr_scans);
Mike Christiebd976f62008-01-31 13:36:46 -06001522}
1523
Mike Christiec01be6d2010-07-22 16:59:49 +05301524/**
1525 * iscsi_block_scsi_eh - block scsi eh until session state has transistioned
Randy Dunlape6d4ef42010-08-14 13:05:41 -07001526 * @cmd: scsi cmd passed to scsi eh handler
Mike Christiec01be6d2010-07-22 16:59:49 +05301527 *
1528 * If the session is down this function will wait for the recovery
1529 * timer to fire or for the session to be logged back in. If the
1530 * recovery timer fires then FAST_IO_FAIL is returned. The caller
1531 * should pass this error value to the scsi eh.
1532 */
1533int iscsi_block_scsi_eh(struct scsi_cmnd *cmd)
1534{
1535 struct iscsi_cls_session *session =
1536 starget_to_session(scsi_target(cmd->device));
1537 unsigned long flags;
1538 int ret = 0;
1539
1540 spin_lock_irqsave(&session->lock, flags);
1541 while (session->state != ISCSI_SESSION_LOGGED_IN) {
1542 if (session->state == ISCSI_SESSION_FREE) {
1543 ret = FAST_IO_FAIL;
1544 break;
1545 }
1546 spin_unlock_irqrestore(&session->lock, flags);
1547 msleep(1000);
1548 spin_lock_irqsave(&session->lock, flags);
1549 }
1550 spin_unlock_irqrestore(&session->lock, flags);
1551 return ret;
1552}
1553EXPORT_SYMBOL_GPL(iscsi_block_scsi_eh);
1554
David Howellsc4028952006-11-22 14:57:56 +00001555static void session_recovery_timedout(struct work_struct *work)
Mike Christie30a6c652006-04-06 21:13:39 -05001556{
David Howellsc4028952006-11-22 14:57:56 +00001557 struct iscsi_cls_session *session =
1558 container_of(work, struct iscsi_cls_session,
1559 recovery_work.work);
Mike Christie6eabafb2008-01-31 13:36:43 -06001560 unsigned long flags;
Mike Christie30a6c652006-04-06 21:13:39 -05001561
Mike Christie322d7392008-01-31 13:36:52 -06001562 iscsi_cls_session_printk(KERN_INFO, session,
1563 "session recovery timed out after %d secs\n",
1564 session->recovery_tmo);
Mike Christie30a6c652006-04-06 21:13:39 -05001565
Mike Christie6eabafb2008-01-31 13:36:43 -06001566 spin_lock_irqsave(&session->lock, flags);
1567 switch (session->state) {
1568 case ISCSI_SESSION_FAILED:
1569 session->state = ISCSI_SESSION_FREE;
1570 break;
1571 case ISCSI_SESSION_LOGGED_IN:
1572 case ISCSI_SESSION_FREE:
1573 /* we raced with the unblock's flush */
1574 spin_unlock_irqrestore(&session->lock, flags);
1575 return;
1576 }
1577 spin_unlock_irqrestore(&session->lock, flags);
1578
Mike Christie30a6c652006-04-06 21:13:39 -05001579 if (session->transport->session_recovery_timedout)
1580 session->transport->session_recovery_timedout(session);
1581
Mike Christie632248a2009-08-20 15:11:01 -05001582 ISCSI_DBG_TRANS_SESSION(session, "Unblocking SCSI target\n");
Mike Christie5d9fb5c2012-05-17 23:56:57 -05001583 scsi_target_unblock(&session->dev, SDEV_TRANSPORT_OFFLINE);
Mike Christie632248a2009-08-20 15:11:01 -05001584 ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking SCSI target\n");
Mike Christie30a6c652006-04-06 21:13:39 -05001585}
1586
Mike Christie45ab33b2008-03-04 13:26:55 -06001587static void __iscsi_unblock_session(struct work_struct *work)
Mike Christie30a6c652006-04-06 21:13:39 -05001588{
Mike Christie45ab33b2008-03-04 13:26:55 -06001589 struct iscsi_cls_session *session =
1590 container_of(work, struct iscsi_cls_session,
1591 unblock_work);
Mike Christiebd976f62008-01-31 13:36:46 -06001592 struct Scsi_Host *shost = iscsi_session_to_shost(session);
Mike Christie32c6e1b2008-05-21 15:53:58 -05001593 struct iscsi_cls_host *ihost = shost->shost_data;
Mike Christie6eabafb2008-01-31 13:36:43 -06001594 unsigned long flags;
1595
Mike Christie632248a2009-08-20 15:11:01 -05001596 ISCSI_DBG_TRANS_SESSION(session, "Unblocking session\n");
Mike Christie45ab33b2008-03-04 13:26:55 -06001597 /*
1598 * The recovery and unblock work get run from the same workqueue,
1599 * so try to cancel it if it was going to run after this unblock.
1600 */
1601 cancel_delayed_work(&session->recovery_work);
Mike Christie6eabafb2008-01-31 13:36:43 -06001602 spin_lock_irqsave(&session->lock, flags);
1603 session->state = ISCSI_SESSION_LOGGED_IN;
1604 spin_unlock_irqrestore(&session->lock, flags);
Mike Christie45ab33b2008-03-04 13:26:55 -06001605 /* start IO */
Mike Christie5d9fb5c2012-05-17 23:56:57 -05001606 scsi_target_unblock(&session->dev, SDEV_RUNNING);
Mike Christie8aae18a2008-01-31 13:36:48 -06001607 /*
1608 * Only do kernel scanning if the driver is properly hooked into
1609 * the async scanning code (drivers like iscsi_tcp do login and
1610 * scanning from userspace).
1611 */
1612 if (shost->hostt->scan_finished) {
Mike Christie06d25af2009-03-05 14:46:02 -06001613 if (scsi_queue_work(shost, &session->scan_work))
Mike Christie8aae18a2008-01-31 13:36:48 -06001614 atomic_inc(&ihost->nr_scans);
1615 }
Mike Christie632248a2009-08-20 15:11:01 -05001616 ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking session\n");
Mike Christie6eabafb2008-01-31 13:36:43 -06001617}
Mike Christie45ab33b2008-03-04 13:26:55 -06001618
1619/**
1620 * iscsi_unblock_session - set a session as logged in and start IO.
1621 * @session: iscsi session
1622 *
1623 * Mark a session as ready to accept IO.
1624 */
1625void iscsi_unblock_session(struct iscsi_cls_session *session)
1626{
1627 queue_work(iscsi_eh_timer_workq, &session->unblock_work);
1628 /*
1629 * make sure all the events have completed before tell the driver
1630 * it is safe
1631 */
1632 flush_workqueue(iscsi_eh_timer_workq);
1633}
Mike Christie30a6c652006-04-06 21:13:39 -05001634EXPORT_SYMBOL_GPL(iscsi_unblock_session);
1635
Mike Christie45ab33b2008-03-04 13:26:55 -06001636static void __iscsi_block_session(struct work_struct *work)
Mike Christie30a6c652006-04-06 21:13:39 -05001637{
Mike Christie45ab33b2008-03-04 13:26:55 -06001638 struct iscsi_cls_session *session =
1639 container_of(work, struct iscsi_cls_session,
1640 block_work);
Mike Christie6eabafb2008-01-31 13:36:43 -06001641 unsigned long flags;
1642
Mike Christie632248a2009-08-20 15:11:01 -05001643 ISCSI_DBG_TRANS_SESSION(session, "Blocking session\n");
Mike Christie6eabafb2008-01-31 13:36:43 -06001644 spin_lock_irqsave(&session->lock, flags);
1645 session->state = ISCSI_SESSION_FAILED;
1646 spin_unlock_irqrestore(&session->lock, flags);
Mike Christie30a6c652006-04-06 21:13:39 -05001647 scsi_target_block(&session->dev);
Mike Christie632248a2009-08-20 15:11:01 -05001648 ISCSI_DBG_TRANS_SESSION(session, "Completed SCSI target blocking\n");
Mike Christiefdd46dc2009-11-11 16:34:34 -06001649 if (session->recovery_tmo >= 0)
1650 queue_delayed_work(iscsi_eh_timer_workq,
1651 &session->recovery_work,
1652 session->recovery_tmo * HZ);
Mike Christie30a6c652006-04-06 21:13:39 -05001653}
Mike Christie45ab33b2008-03-04 13:26:55 -06001654
1655void iscsi_block_session(struct iscsi_cls_session *session)
1656{
1657 queue_work(iscsi_eh_timer_workq, &session->block_work);
1658}
Mike Christie30a6c652006-04-06 21:13:39 -05001659EXPORT_SYMBOL_GPL(iscsi_block_session);
1660
Mike Christie26974782007-12-13 12:43:29 -06001661static void __iscsi_unbind_session(struct work_struct *work)
1662{
1663 struct iscsi_cls_session *session =
1664 container_of(work, struct iscsi_cls_session,
1665 unbind_work);
1666 struct Scsi_Host *shost = iscsi_session_to_shost(session);
Mike Christie32c6e1b2008-05-21 15:53:58 -05001667 struct iscsi_cls_host *ihost = shost->shost_data;
Mike Christie79706342008-05-21 15:54:12 -05001668 unsigned long flags;
Mike Christie8d4a6902011-10-06 03:56:57 -05001669 unsigned int target_id;
Mike Christie26974782007-12-13 12:43:29 -06001670
Mike Christie632248a2009-08-20 15:11:01 -05001671 ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n");
1672
Mike Christie26974782007-12-13 12:43:29 -06001673 /* Prevent new scans and make sure scanning is not in progress */
1674 mutex_lock(&ihost->mutex);
Mike Christie79706342008-05-21 15:54:12 -05001675 spin_lock_irqsave(&session->lock, flags);
1676 if (session->target_id == ISCSI_MAX_TARGET) {
1677 spin_unlock_irqrestore(&session->lock, flags);
Mike Christie26974782007-12-13 12:43:29 -06001678 mutex_unlock(&ihost->mutex);
1679 return;
1680 }
Mike Christie8d4a6902011-10-06 03:56:57 -05001681
1682 target_id = session->target_id;
Mike Christie79706342008-05-21 15:54:12 -05001683 session->target_id = ISCSI_MAX_TARGET;
1684 spin_unlock_irqrestore(&session->lock, flags);
Mike Christie26974782007-12-13 12:43:29 -06001685 mutex_unlock(&ihost->mutex);
1686
Mike Christie8d4a6902011-10-06 03:56:57 -05001687 if (session->ida_used)
1688 ida_simple_remove(&iscsi_sess_ida, target_id);
1689
Mike Christie26974782007-12-13 12:43:29 -06001690 scsi_remove_target(&session->dev);
1691 iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
Mike Christie632248a2009-08-20 15:11:01 -05001692 ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n");
Mike Christie26974782007-12-13 12:43:29 -06001693}
1694
Mike Christie7b8631b2006-01-13 18:05:50 -06001695struct iscsi_cls_session *
Mike Christie5d91e202008-05-21 15:54:01 -05001696iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
1697 int dd_size)
Mike Christie7b8631b2006-01-13 18:05:50 -06001698{
1699 struct iscsi_cls_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
Mike Christie5d91e202008-05-21 15:54:01 -05001701 session = kzalloc(sizeof(*session) + dd_size,
Mike Christieb5c7a122006-04-06 21:13:33 -05001702 GFP_KERNEL);
Mike Christie7b8631b2006-01-13 18:05:50 -06001703 if (!session)
Mike Christief53a88d2006-06-28 12:00:27 -05001704 return NULL;
1705
Mike Christie7b8631b2006-01-13 18:05:50 -06001706 session->transport = transport;
Mike Christie0c70d842011-12-05 16:44:01 -06001707 session->creator = -1;
Mike Christie30a6c652006-04-06 21:13:39 -05001708 session->recovery_tmo = 120;
Mike Christie6eabafb2008-01-31 13:36:43 -06001709 session->state = ISCSI_SESSION_FREE;
David Howellsc4028952006-11-22 14:57:56 +00001710 INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
Mike Christie30a6c652006-04-06 21:13:39 -05001711 INIT_LIST_HEAD(&session->sess_list);
Mike Christie45ab33b2008-03-04 13:26:55 -06001712 INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
1713 INIT_WORK(&session->block_work, __iscsi_block_session);
Mike Christie26974782007-12-13 12:43:29 -06001714 INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
Mike Christiebd976f62008-01-31 13:36:46 -06001715 INIT_WORK(&session->scan_work, iscsi_scan_session);
Mike Christie6eabafb2008-01-31 13:36:43 -06001716 spin_lock_init(&session->lock);
Mike Christie7b8631b2006-01-13 18:05:50 -06001717
Mike Christie6a8a0d32006-06-28 12:00:31 -05001718 /* this is released in the dev's release function */
1719 scsi_host_get(shost);
Mike Christie8434aa82006-06-28 12:00:30 -05001720 session->dev.parent = &shost->shost_gendev;
1721 session->dev.release = iscsi_session_release;
1722 device_initialize(&session->dev);
Mike Christie5d91e202008-05-21 15:54:01 -05001723 if (dd_size)
Mike Christieb5c7a122006-04-06 21:13:33 -05001724 session->dd_data = &session[1];
Mike Christie632248a2009-08-20 15:11:01 -05001725
1726 ISCSI_DBG_TRANS_SESSION(session, "Completed session allocation\n");
Mike Christie8434aa82006-06-28 12:00:30 -05001727 return session;
1728}
1729EXPORT_SYMBOL_GPL(iscsi_alloc_session);
1730
Mike Christie6a8a0d32006-06-28 12:00:31 -05001731int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
Mike Christie8434aa82006-06-28 12:00:30 -05001732{
1733 struct Scsi_Host *shost = iscsi_session_to_shost(session);
Mike Christie32c6e1b2008-05-21 15:53:58 -05001734 struct iscsi_cls_host *ihost;
Mike Christie26974782007-12-13 12:43:29 -06001735 unsigned long flags;
Mike Christie8d4a6902011-10-06 03:56:57 -05001736 int id = 0;
Mike Christie8434aa82006-06-28 12:00:30 -05001737 int err;
Mike Christieb5c7a122006-04-06 21:13:33 -05001738
Mike Christie30a6c652006-04-06 21:13:39 -05001739 ihost = shost->shost_data;
Mike Christie41be1442007-02-28 17:32:18 -06001740 session->sid = atomic_add_return(1, &iscsi_session_nr);
Mike Christie79706342008-05-21 15:54:12 -05001741
Mike Christie8d4a6902011-10-06 03:56:57 -05001742 if (target_id == ISCSI_MAX_TARGET) {
1743 id = ida_simple_get(&iscsi_sess_ida, 0, 0, GFP_KERNEL);
Mike Christie79706342008-05-21 15:54:12 -05001744
Mike Christie8d4a6902011-10-06 03:56:57 -05001745 if (id < 0) {
Mike Christie79706342008-05-21 15:54:12 -05001746 iscsi_cls_session_printk(KERN_ERR, session,
Mike Christie8d4a6902011-10-06 03:56:57 -05001747 "Failure in Target ID Allocation\n");
1748 return id;
Mike Christie79706342008-05-21 15:54:12 -05001749 }
Mike Christie8d4a6902011-10-06 03:56:57 -05001750 session->target_id = (unsigned int)id;
1751 session->ida_used = true;
1752 } else
1753 session->target_id = target_id;
Mike Christie30a6c652006-04-06 21:13:39 -05001754
Kay Sievers71610f52008-12-03 22:41:36 +01001755 dev_set_name(&session->dev, "session%u", session->sid);
Mike Christie8434aa82006-06-28 12:00:30 -05001756 err = device_add(&session->dev);
Mike Christie7b8631b2006-01-13 18:05:50 -06001757 if (err) {
Mike Christie322d7392008-01-31 13:36:52 -06001758 iscsi_cls_session_printk(KERN_ERR, session,
1759 "could not register session's dev\n");
Mike Christie8d4a6902011-10-06 03:56:57 -05001760 goto release_ida;
Mike Christie7b8631b2006-01-13 18:05:50 -06001761 }
1762 transport_register_device(&session->dev);
1763
Mike Christie26974782007-12-13 12:43:29 -06001764 spin_lock_irqsave(&sesslock, flags);
1765 list_add(&session->sess_list, &sesslist);
1766 spin_unlock_irqrestore(&sesslock, flags);
1767
Mike Christie26974782007-12-13 12:43:29 -06001768 iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
Mike Christie632248a2009-08-20 15:11:01 -05001769 ISCSI_DBG_TRANS_SESSION(session, "Completed session adding\n");
Mike Christie8434aa82006-06-28 12:00:30 -05001770 return 0;
Mike Christie30a6c652006-04-06 21:13:39 -05001771
Mike Christie8d4a6902011-10-06 03:56:57 -05001772release_ida:
1773 if (session->ida_used)
1774 ida_simple_remove(&iscsi_sess_ida, session->target_id);
1775
Mike Christie8434aa82006-06-28 12:00:30 -05001776 return err;
Mike Christie7b8631b2006-01-13 18:05:50 -06001777}
Mike Christie8434aa82006-06-28 12:00:30 -05001778EXPORT_SYMBOL_GPL(iscsi_add_session);
Mike Christie7b8631b2006-01-13 18:05:50 -06001779
1780/**
Mike Christie8434aa82006-06-28 12:00:30 -05001781 * iscsi_create_session - create iscsi class session
1782 * @shost: scsi host
1783 * @transport: iscsi transport
Mike Christie5d91e202008-05-21 15:54:01 -05001784 * @dd_size: private driver data size
Rob Landleyeb448202007-11-03 13:30:39 -05001785 * @target_id: which target
Mike Christie7b8631b2006-01-13 18:05:50 -06001786 *
Mike Christie8434aa82006-06-28 12:00:30 -05001787 * This can be called from a LLD or iscsi_transport.
Rob Landleyeb448202007-11-03 13:30:39 -05001788 */
Mike Christie8434aa82006-06-28 12:00:30 -05001789struct iscsi_cls_session *
Mike Christie5d91e202008-05-21 15:54:01 -05001790iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
1791 int dd_size, unsigned int target_id)
Mike Christie8434aa82006-06-28 12:00:30 -05001792{
1793 struct iscsi_cls_session *session;
1794
Mike Christie5d91e202008-05-21 15:54:01 -05001795 session = iscsi_alloc_session(shost, transport, dd_size);
Mike Christie8434aa82006-06-28 12:00:30 -05001796 if (!session)
1797 return NULL;
1798
Mike Christie6a8a0d32006-06-28 12:00:31 -05001799 if (iscsi_add_session(session, target_id)) {
Mike Christie8434aa82006-06-28 12:00:30 -05001800 iscsi_free_session(session);
1801 return NULL;
1802 }
1803 return session;
1804}
1805EXPORT_SYMBOL_GPL(iscsi_create_session);
1806
Mike Christie26974782007-12-13 12:43:29 -06001807static void iscsi_conn_release(struct device *dev)
1808{
1809 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
1810 struct device *parent = conn->dev.parent;
1811
Mike Christie632248a2009-08-20 15:11:01 -05001812 ISCSI_DBG_TRANS_CONN(conn, "Releasing conn\n");
Mike Christie26974782007-12-13 12:43:29 -06001813 kfree(conn);
1814 put_device(parent);
1815}
1816
1817static int iscsi_is_conn_dev(const struct device *dev)
1818{
1819 return dev->release == iscsi_conn_release;
1820}
1821
1822static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
1823{
1824 if (!iscsi_is_conn_dev(dev))
1825 return 0;
1826 return iscsi_destroy_conn(iscsi_dev_to_conn(dev));
1827}
1828
Mike Christie8434aa82006-06-28 12:00:30 -05001829void iscsi_remove_session(struct iscsi_cls_session *session)
Mike Christie7b8631b2006-01-13 18:05:50 -06001830{
Mike Christie30a6c652006-04-06 21:13:39 -05001831 struct Scsi_Host *shost = iscsi_session_to_shost(session);
Mike Christie26974782007-12-13 12:43:29 -06001832 unsigned long flags;
1833 int err;
Mike Christie30a6c652006-04-06 21:13:39 -05001834
Mike Christie632248a2009-08-20 15:11:01 -05001835 ISCSI_DBG_TRANS_SESSION(session, "Removing session\n");
1836
Mike Christie26974782007-12-13 12:43:29 -06001837 spin_lock_irqsave(&sesslock, flags);
1838 list_del(&session->sess_list);
1839 spin_unlock_irqrestore(&sesslock, flags);
1840
Mike Christie45ab33b2008-03-04 13:26:55 -06001841 /* make sure there are no blocks/unblocks queued */
1842 flush_workqueue(iscsi_eh_timer_workq);
1843 /* make sure the timedout callout is not running */
1844 if (!cancel_delayed_work(&session->recovery_work))
1845 flush_workqueue(iscsi_eh_timer_workq);
Mike Christie26974782007-12-13 12:43:29 -06001846 /*
1847 * If we are blocked let commands flow again. The lld or iscsi
1848 * layer should set up the queuecommand to fail commands.
Mike Christie45ab33b2008-03-04 13:26:55 -06001849 * We assume that LLD will not be calling block/unblock while
1850 * removing the session.
Mike Christie26974782007-12-13 12:43:29 -06001851 */
Mike Christie6eabafb2008-01-31 13:36:43 -06001852 spin_lock_irqsave(&session->lock, flags);
1853 session->state = ISCSI_SESSION_FREE;
1854 spin_unlock_irqrestore(&session->lock, flags);
Mike Christiebd976f62008-01-31 13:36:46 -06001855
Mike Christie5d9fb5c2012-05-17 23:56:57 -05001856 scsi_target_unblock(&session->dev, SDEV_TRANSPORT_OFFLINE);
Mike Christie45ab33b2008-03-04 13:26:55 -06001857 /* flush running scans then delete devices */
Mike Christie06d25af2009-03-05 14:46:02 -06001858 scsi_flush_work(shost);
Mike Christie45ab33b2008-03-04 13:26:55 -06001859 __iscsi_unbind_session(&session->unbind_work);
Mike Christie30a6c652006-04-06 21:13:39 -05001860
Mike Christie26974782007-12-13 12:43:29 -06001861 /* hw iscsi may not have removed all connections from session */
1862 err = device_for_each_child(&session->dev, NULL,
1863 iscsi_iter_destroy_conn_fn);
1864 if (err)
Mike Christie322d7392008-01-31 13:36:52 -06001865 iscsi_cls_session_printk(KERN_ERR, session,
1866 "Could not delete all connections "
1867 "for session. Error %d.\n", err);
Mike Christie8434aa82006-06-28 12:00:30 -05001868
Mike Christie7b8631b2006-01-13 18:05:50 -06001869 transport_unregister_device(&session->dev);
Mike Christie632248a2009-08-20 15:11:01 -05001870
1871 ISCSI_DBG_TRANS_SESSION(session, "Completing session removal\n");
Mike Christie8434aa82006-06-28 12:00:30 -05001872 device_del(&session->dev);
1873}
1874EXPORT_SYMBOL_GPL(iscsi_remove_session);
1875
1876void iscsi_free_session(struct iscsi_cls_session *session)
1877{
Mike Christie632248a2009-08-20 15:11:01 -05001878 ISCSI_DBG_TRANS_SESSION(session, "Freeing session\n");
Mike Christie26974782007-12-13 12:43:29 -06001879 iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION);
Mike Christie8434aa82006-06-28 12:00:30 -05001880 put_device(&session->dev);
Mike Christie7b8631b2006-01-13 18:05:50 -06001881}
Mike Christie8434aa82006-06-28 12:00:30 -05001882EXPORT_SYMBOL_GPL(iscsi_free_session);
1883
1884/**
1885 * iscsi_destroy_session - destroy iscsi session
1886 * @session: iscsi_session
1887 *
1888 * Can be called by a LLD or iscsi_transport. There must not be
1889 * any running connections.
Rob Landleyeb448202007-11-03 13:30:39 -05001890 */
Mike Christie8434aa82006-06-28 12:00:30 -05001891int iscsi_destroy_session(struct iscsi_cls_session *session)
1892{
1893 iscsi_remove_session(session);
Mike Christie632248a2009-08-20 15:11:01 -05001894 ISCSI_DBG_TRANS_SESSION(session, "Completing session destruction\n");
Mike Christie8434aa82006-06-28 12:00:30 -05001895 iscsi_free_session(session);
1896 return 0;
1897}
Mike Christie7b8631b2006-01-13 18:05:50 -06001898EXPORT_SYMBOL_GPL(iscsi_destroy_session);
1899
Mike Christie7b8631b2006-01-13 18:05:50 -06001900/**
1901 * iscsi_create_conn - create iscsi class connection
1902 * @session: iscsi cls session
Mike Christie5d91e202008-05-21 15:54:01 -05001903 * @dd_size: private driver data size
Mike Christie7b8631b2006-01-13 18:05:50 -06001904 * @cid: connection id
1905 *
1906 * This can be called from a LLD or iscsi_transport. The connection
1907 * is child of the session so cid must be unique for all connections
1908 * on the session.
Mike Christieb5c7a122006-04-06 21:13:33 -05001909 *
1910 * Since we do not support MCS, cid will normally be zero. In some cases
1911 * for software iscsi we could be trying to preallocate a connection struct
1912 * in which case there could be two connection structs and cid would be
1913 * non-zero.
Rob Landleyeb448202007-11-03 13:30:39 -05001914 */
Mike Christie7b8631b2006-01-13 18:05:50 -06001915struct iscsi_cls_conn *
Mike Christie5d91e202008-05-21 15:54:01 -05001916iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
Mike Christie7b8631b2006-01-13 18:05:50 -06001917{
1918 struct iscsi_transport *transport = session->transport;
Mike Christie7b8631b2006-01-13 18:05:50 -06001919 struct iscsi_cls_conn *conn;
Mike Christie26974782007-12-13 12:43:29 -06001920 unsigned long flags;
Mike Christie7b8631b2006-01-13 18:05:50 -06001921 int err;
1922
Mike Christie5d91e202008-05-21 15:54:01 -05001923 conn = kzalloc(sizeof(*conn) + dd_size, GFP_KERNEL);
Mike Christie7b8631b2006-01-13 18:05:50 -06001924 if (!conn)
1925 return NULL;
Mike Christie5d91e202008-05-21 15:54:01 -05001926 if (dd_size)
Mike Christie7b8631b2006-01-13 18:05:50 -06001927 conn->dd_data = &conn[1];
1928
Mike Christie22a39fb2011-02-16 15:04:33 -06001929 mutex_init(&conn->ep_mutex);
Mike Christie7b8631b2006-01-13 18:05:50 -06001930 INIT_LIST_HEAD(&conn->conn_list);
1931 conn->transport = transport;
Mike Christieb5c7a122006-04-06 21:13:33 -05001932 conn->cid = cid;
Mike Christie7b8631b2006-01-13 18:05:50 -06001933
1934 /* this is released in the dev's release function */
1935 if (!get_device(&session->dev))
Mike Christie43a145a2006-10-16 18:09:38 -04001936 goto free_conn;
Mike Christieb5c7a122006-04-06 21:13:33 -05001937
Kay Sievers71610f52008-12-03 22:41:36 +01001938 dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid);
Mike Christie7b8631b2006-01-13 18:05:50 -06001939 conn->dev.parent = &session->dev;
1940 conn->dev.release = iscsi_conn_release;
1941 err = device_register(&conn->dev);
1942 if (err) {
Mike Christie322d7392008-01-31 13:36:52 -06001943 iscsi_cls_session_printk(KERN_ERR, session, "could not "
1944 "register connection's dev\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06001945 goto release_parent_ref;
1946 }
1947 transport_register_device(&conn->dev);
Mike Christie26974782007-12-13 12:43:29 -06001948
1949 spin_lock_irqsave(&connlock, flags);
1950 list_add(&conn->conn_list, &connlist);
Mike Christie26974782007-12-13 12:43:29 -06001951 spin_unlock_irqrestore(&connlock, flags);
Mike Christie632248a2009-08-20 15:11:01 -05001952
1953 ISCSI_DBG_TRANS_CONN(conn, "Completed conn creation\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06001954 return conn;
1955
1956release_parent_ref:
1957 put_device(&session->dev);
1958free_conn:
1959 kfree(conn);
1960 return NULL;
1961}
1962
1963EXPORT_SYMBOL_GPL(iscsi_create_conn);
1964
1965/**
1966 * iscsi_destroy_conn - destroy iscsi class connection
Rob Landleyeb448202007-11-03 13:30:39 -05001967 * @conn: iscsi cls session
Mike Christie7b8631b2006-01-13 18:05:50 -06001968 *
Mike Christie26974782007-12-13 12:43:29 -06001969 * This can be called from a LLD or iscsi_transport.
Rob Landleyeb448202007-11-03 13:30:39 -05001970 */
Mike Christie7b8631b2006-01-13 18:05:50 -06001971int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
1972{
Mike Christie26974782007-12-13 12:43:29 -06001973 unsigned long flags;
1974
1975 spin_lock_irqsave(&connlock, flags);
Mike Christie26974782007-12-13 12:43:29 -06001976 list_del(&conn->conn_list);
1977 spin_unlock_irqrestore(&connlock, flags);
1978
Mike Christie7b8631b2006-01-13 18:05:50 -06001979 transport_unregister_device(&conn->dev);
Mike Christie632248a2009-08-20 15:11:01 -05001980 ISCSI_DBG_TRANS_CONN(conn, "Completing conn destruction\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06001981 device_unregister(&conn->dev);
1982 return 0;
1983}
Mike Christie7b8631b2006-01-13 18:05:50 -06001984EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
1985
1986/*
Mike Christie7b8631b2006-01-13 18:05:50 -06001987 * iscsi interface functions
1988 */
Alex Aizman0896b752005-08-04 19:33:07 -07001989static struct iscsi_internal *
1990iscsi_if_transport_lookup(struct iscsi_transport *tt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991{
Alex Aizman0896b752005-08-04 19:33:07 -07001992 struct iscsi_internal *priv;
1993 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994
Alex Aizman0896b752005-08-04 19:33:07 -07001995 spin_lock_irqsave(&iscsi_transport_lock, flags);
1996 list_for_each_entry(priv, &iscsi_transports, list) {
1997 if (tt == priv->iscsi_transport) {
1998 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
1999 return priv;
2000 }
2001 }
2002 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
2003 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005
Alex Aizman0896b752005-08-04 19:33:07 -07002006static int
Michael Chan43514772009-06-08 18:14:41 -07002007iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp)
Mike Christie53cb8a12006-06-28 12:00:32 -05002008{
Michael Chan43514772009-06-08 18:14:41 -07002009 return nlmsg_multicast(nls, skb, 0, group, gfp);
Alex Aizman0896b752005-08-04 19:33:07 -07002010}
2011
Mike Christie7b7232f2006-02-01 21:06:49 -06002012int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
Alex Aizman0896b752005-08-04 19:33:07 -07002013 char *data, uint32_t data_size)
2014{
2015 struct nlmsghdr *nlh;
2016 struct sk_buff *skb;
2017 struct iscsi_uevent *ev;
Alex Aizman0896b752005-08-04 19:33:07 -07002018 char *pdu;
Mike Christie790f39a2006-05-18 20:31:39 -05002019 struct iscsi_internal *priv;
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002020 int len = nlmsg_total_size(sizeof(*ev) + sizeof(struct iscsi_hdr) +
2021 data_size);
Alex Aizman0896b752005-08-04 19:33:07 -07002022
Mike Christie790f39a2006-05-18 20:31:39 -05002023 priv = iscsi_if_transport_lookup(conn->transport);
2024 if (!priv)
2025 return -EINVAL;
2026
Mike Christie43a145a2006-10-16 18:09:38 -04002027 skb = alloc_skb(len, GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07002028 if (!skb) {
Mike Christiee5bd7b52008-09-24 11:46:10 -05002029 iscsi_conn_error_event(conn, ISCSI_ERR_CONN_FAILED);
Mike Christie322d7392008-01-31 13:36:52 -06002030 iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver "
2031 "control PDU: OOM\n");
Alex Aizman0896b752005-08-04 19:33:07 -07002032 return -ENOMEM;
2033 }
2034
Michael Chan43514772009-06-08 18:14:41 -07002035 nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002036 ev = nlmsg_data(nlh);
Alex Aizman0896b752005-08-04 19:33:07 -07002037 memset(ev, 0, sizeof(*ev));
2038 ev->transport_handle = iscsi_handle(conn->transport);
2039 ev->type = ISCSI_KEVENT_RECV_PDU;
Mike Christieb5c7a122006-04-06 21:13:33 -05002040 ev->r.recv_req.cid = conn->cid;
2041 ev->r.recv_req.sid = iscsi_conn_get_sid(conn);
Alex Aizman0896b752005-08-04 19:33:07 -07002042 pdu = (char*)ev + sizeof(*ev);
2043 memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
2044 memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
2045
Michael Chan43514772009-06-08 18:14:41 -07002046 return iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07002047}
2048EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
2049
Michael Chan43514772009-06-08 18:14:41 -07002050int iscsi_offload_mesg(struct Scsi_Host *shost,
2051 struct iscsi_transport *transport, uint32_t type,
2052 char *data, uint16_t data_size)
2053{
2054 struct nlmsghdr *nlh;
2055 struct sk_buff *skb;
2056 struct iscsi_uevent *ev;
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002057 int len = nlmsg_total_size(sizeof(*ev) + data_size);
Michael Chan43514772009-06-08 18:14:41 -07002058
Michael Chana541f842009-07-29 08:49:52 +00002059 skb = alloc_skb(len, GFP_ATOMIC);
Michael Chan43514772009-06-08 18:14:41 -07002060 if (!skb) {
2061 printk(KERN_ERR "can not deliver iscsi offload message:OOM\n");
2062 return -ENOMEM;
2063 }
2064
2065 nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002066 ev = nlmsg_data(nlh);
Michael Chan43514772009-06-08 18:14:41 -07002067 memset(ev, 0, sizeof(*ev));
2068 ev->type = type;
2069 ev->transport_handle = iscsi_handle(transport);
2070 switch (type) {
2071 case ISCSI_KEVENT_PATH_REQ:
2072 ev->r.req_path.host_no = shost->host_no;
2073 break;
2074 case ISCSI_KEVENT_IF_DOWN:
2075 ev->r.notify_if_down.host_no = shost->host_no;
2076 break;
2077 }
2078
2079 memcpy((char *)ev + sizeof(*ev), data, data_size);
2080
Michael Chana541f842009-07-29 08:49:52 +00002081 return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_ATOMIC);
Michael Chan43514772009-06-08 18:14:41 -07002082}
2083EXPORT_SYMBOL_GPL(iscsi_offload_mesg);
2084
Mike Christiee5bd7b52008-09-24 11:46:10 -05002085void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
Alex Aizman0896b752005-08-04 19:33:07 -07002086{
2087 struct nlmsghdr *nlh;
2088 struct sk_buff *skb;
2089 struct iscsi_uevent *ev;
Mike Christie790f39a2006-05-18 20:31:39 -05002090 struct iscsi_internal *priv;
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002091 int len = nlmsg_total_size(sizeof(*ev));
Alex Aizman0896b752005-08-04 19:33:07 -07002092
Mike Christie790f39a2006-05-18 20:31:39 -05002093 priv = iscsi_if_transport_lookup(conn->transport);
2094 if (!priv)
2095 return;
2096
Mike Christie43a145a2006-10-16 18:09:38 -04002097 skb = alloc_skb(len, GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07002098 if (!skb) {
Mike Christie322d7392008-01-31 13:36:52 -06002099 iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored "
2100 "conn error (%d)\n", error);
Alex Aizman0896b752005-08-04 19:33:07 -07002101 return;
2102 }
2103
Michael Chan43514772009-06-08 18:14:41 -07002104 nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002105 ev = nlmsg_data(nlh);
Alex Aizman0896b752005-08-04 19:33:07 -07002106 ev->transport_handle = iscsi_handle(conn->transport);
2107 ev->type = ISCSI_KEVENT_CONN_ERROR;
Alex Aizman0896b752005-08-04 19:33:07 -07002108 ev->r.connerror.error = error;
Mike Christieb5c7a122006-04-06 21:13:33 -05002109 ev->r.connerror.cid = conn->cid;
2110 ev->r.connerror.sid = iscsi_conn_get_sid(conn);
Alex Aizman0896b752005-08-04 19:33:07 -07002111
Michael Chan43514772009-06-08 18:14:41 -07002112 iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07002113
Mike Christie322d7392008-01-31 13:36:52 -06002114 iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n",
2115 error);
Alex Aizman0896b752005-08-04 19:33:07 -07002116}
Mike Christiee5bd7b52008-09-24 11:46:10 -05002117EXPORT_SYMBOL_GPL(iscsi_conn_error_event);
Alex Aizman0896b752005-08-04 19:33:07 -07002118
Manish Rangankar17fa5752011-07-25 13:48:52 -05002119void iscsi_conn_login_event(struct iscsi_cls_conn *conn,
2120 enum iscsi_conn_state state)
2121{
2122 struct nlmsghdr *nlh;
2123 struct sk_buff *skb;
2124 struct iscsi_uevent *ev;
2125 struct iscsi_internal *priv;
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002126 int len = nlmsg_total_size(sizeof(*ev));
Manish Rangankar17fa5752011-07-25 13:48:52 -05002127
2128 priv = iscsi_if_transport_lookup(conn->transport);
2129 if (!priv)
2130 return;
2131
2132 skb = alloc_skb(len, GFP_ATOMIC);
2133 if (!skb) {
2134 iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored "
2135 "conn login (%d)\n", state);
2136 return;
2137 }
2138
2139 nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002140 ev = nlmsg_data(nlh);
Manish Rangankar17fa5752011-07-25 13:48:52 -05002141 ev->transport_handle = iscsi_handle(conn->transport);
2142 ev->type = ISCSI_KEVENT_CONN_LOGIN_STATE;
2143 ev->r.conn_login.state = state;
2144 ev->r.conn_login.cid = conn->cid;
2145 ev->r.conn_login.sid = iscsi_conn_get_sid(conn);
2146 iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
2147
2148 iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn login (%d)\n",
2149 state);
2150}
2151EXPORT_SYMBOL_GPL(iscsi_conn_login_event);
2152
Vikas Chaudharya11e2542012-02-13 18:30:46 +05302153void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport,
2154 enum iscsi_host_event_code code, uint32_t data_size,
2155 uint8_t *data)
2156{
2157 struct nlmsghdr *nlh;
2158 struct sk_buff *skb;
2159 struct iscsi_uevent *ev;
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002160 int len = nlmsg_total_size(sizeof(*ev) + data_size);
Vikas Chaudharya11e2542012-02-13 18:30:46 +05302161
Mike Christie49d0e642012-03-06 16:09:01 -06002162 skb = alloc_skb(len, GFP_NOIO);
Vikas Chaudharya11e2542012-02-13 18:30:46 +05302163 if (!skb) {
2164 printk(KERN_ERR "gracefully ignored host event (%d):%d OOM\n",
2165 host_no, code);
2166 return;
2167 }
2168
2169 nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002170 ev = nlmsg_data(nlh);
Vikas Chaudharya11e2542012-02-13 18:30:46 +05302171 ev->transport_handle = iscsi_handle(transport);
2172 ev->type = ISCSI_KEVENT_HOST_EVENT;
2173 ev->r.host_event.host_no = host_no;
2174 ev->r.host_event.code = code;
2175 ev->r.host_event.data_size = data_size;
2176
2177 if (data_size)
2178 memcpy((char *)ev + sizeof(*ev), data, data_size);
2179
Mike Christie49d0e642012-03-06 16:09:01 -06002180 iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO);
Vikas Chaudharya11e2542012-02-13 18:30:46 +05302181}
2182EXPORT_SYMBOL_GPL(iscsi_post_host_event);
2183
Vikas Chaudharyac20c7b2012-02-13 18:30:48 +05302184void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
2185 uint32_t status, uint32_t pid, uint32_t data_size,
2186 uint8_t *data)
2187{
2188 struct nlmsghdr *nlh;
2189 struct sk_buff *skb;
2190 struct iscsi_uevent *ev;
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002191 int len = nlmsg_total_size(sizeof(*ev) + data_size);
Vikas Chaudharyac20c7b2012-02-13 18:30:48 +05302192
Mike Christie49d0e642012-03-06 16:09:01 -06002193 skb = alloc_skb(len, GFP_NOIO);
Vikas Chaudharyac20c7b2012-02-13 18:30:48 +05302194 if (!skb) {
2195 printk(KERN_ERR "gracefully ignored ping comp: OOM\n");
2196 return;
2197 }
2198
2199 nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002200 ev = nlmsg_data(nlh);
Vikas Chaudharyac20c7b2012-02-13 18:30:48 +05302201 ev->transport_handle = iscsi_handle(transport);
2202 ev->type = ISCSI_KEVENT_PING_COMP;
2203 ev->r.ping_comp.host_no = host_no;
2204 ev->r.ping_comp.status = status;
2205 ev->r.ping_comp.pid = pid;
2206 ev->r.ping_comp.data_size = data_size;
2207 memcpy((char *)ev + sizeof(*ev), data, data_size);
2208
Mike Christie49d0e642012-03-06 16:09:01 -06002209 iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO);
Vikas Chaudharyac20c7b2012-02-13 18:30:48 +05302210}
2211EXPORT_SYMBOL_GPL(iscsi_ping_comp_event);
2212
Alex Aizman0896b752005-08-04 19:33:07 -07002213static int
Michael Chan43514772009-06-08 18:14:41 -07002214iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
2215 void *payload, int size)
Alex Aizman0896b752005-08-04 19:33:07 -07002216{
2217 struct sk_buff *skb;
2218 struct nlmsghdr *nlh;
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002219 int len = nlmsg_total_size(size);
Alex Aizman0896b752005-08-04 19:33:07 -07002220 int flags = multi ? NLM_F_MULTI : 0;
2221 int t = done ? NLMSG_DONE : type;
2222
Mike Christie43a145a2006-10-16 18:09:38 -04002223 skb = alloc_skb(len, GFP_ATOMIC);
Mike Christie239a7dc2007-05-30 12:57:07 -05002224 if (!skb) {
2225 printk(KERN_ERR "Could not allocate skb to send reply.\n");
2226 return -ENOMEM;
2227 }
Alex Aizman0896b752005-08-04 19:33:07 -07002228
Michael Chan43514772009-06-08 18:14:41 -07002229 nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0);
Alex Aizman0896b752005-08-04 19:33:07 -07002230 nlh->nlmsg_flags = flags;
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002231 memcpy(nlmsg_data(nlh), payload, size);
Michael Chan43514772009-06-08 18:14:41 -07002232 return iscsi_multicast_skb(skb, group, GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07002233}
2234
2235static int
Mike Christie5b940ad2006-02-01 21:06:56 -06002236iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
Alex Aizman0896b752005-08-04 19:33:07 -07002237{
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002238 struct iscsi_uevent *ev = nlmsg_data(nlh);
Alex Aizman0896b752005-08-04 19:33:07 -07002239 struct iscsi_stats *stats;
2240 struct sk_buff *skbstat;
Mike Christie7b8631b2006-01-13 18:05:50 -06002241 struct iscsi_cls_conn *conn;
Alex Aizman0896b752005-08-04 19:33:07 -07002242 struct nlmsghdr *nlhstat;
2243 struct iscsi_uevent *evstat;
Mike Christie790f39a2006-05-18 20:31:39 -05002244 struct iscsi_internal *priv;
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002245 int len = nlmsg_total_size(sizeof(*ev) +
2246 sizeof(struct iscsi_stats) +
2247 sizeof(struct iscsi_stats_custom) *
2248 ISCSI_STATS_CUSTOM_MAX);
Alex Aizman0896b752005-08-04 19:33:07 -07002249 int err = 0;
2250
Mike Christie790f39a2006-05-18 20:31:39 -05002251 priv = iscsi_if_transport_lookup(transport);
2252 if (!priv)
2253 return -EINVAL;
2254
Mike Christieb5c7a122006-04-06 21:13:33 -05002255 conn = iscsi_conn_lookup(ev->u.get_stats.sid, ev->u.get_stats.cid);
Alex Aizman0896b752005-08-04 19:33:07 -07002256 if (!conn)
2257 return -EEXIST;
2258
2259 do {
2260 int actual_size;
2261
Mike Christie43a145a2006-10-16 18:09:38 -04002262 skbstat = alloc_skb(len, GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07002263 if (!skbstat) {
Mike Christie322d7392008-01-31 13:36:52 -06002264 iscsi_cls_conn_printk(KERN_ERR, conn, "can not "
2265 "deliver stats: OOM\n");
Alex Aizman0896b752005-08-04 19:33:07 -07002266 return -ENOMEM;
2267 }
2268
Michael Chan43514772009-06-08 18:14:41 -07002269 nlhstat = __nlmsg_put(skbstat, 0, 0, 0,
Alex Aizman0896b752005-08-04 19:33:07 -07002270 (len - sizeof(*nlhstat)), 0);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002271 evstat = nlmsg_data(nlhstat);
Alex Aizman0896b752005-08-04 19:33:07 -07002272 memset(evstat, 0, sizeof(*evstat));
2273 evstat->transport_handle = iscsi_handle(conn->transport);
2274 evstat->type = nlh->nlmsg_type;
Mike Christieb5c7a122006-04-06 21:13:33 -05002275 evstat->u.get_stats.cid =
2276 ev->u.get_stats.cid;
2277 evstat->u.get_stats.sid =
2278 ev->u.get_stats.sid;
Alex Aizman0896b752005-08-04 19:33:07 -07002279 stats = (struct iscsi_stats *)
2280 ((char*)evstat + sizeof(*evstat));
2281 memset(stats, 0, sizeof(*stats));
2282
Mike Christie7b7232f2006-02-01 21:06:49 -06002283 transport->get_stats(conn, stats);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002284 actual_size = nlmsg_total_size(sizeof(struct iscsi_uevent) +
2285 sizeof(struct iscsi_stats) +
2286 sizeof(struct iscsi_stats_custom) *
2287 stats->custom_length);
Alex Aizman0896b752005-08-04 19:33:07 -07002288 actual_size -= sizeof(*nlhstat);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002289 actual_size = nlmsg_msg_size(actual_size);
Mike Christie5b940ad2006-02-01 21:06:56 -06002290 skb_trim(skbstat, NLMSG_ALIGN(actual_size));
Alex Aizman0896b752005-08-04 19:33:07 -07002291 nlhstat->nlmsg_len = actual_size;
2292
Michael Chan43514772009-06-08 18:14:41 -07002293 err = iscsi_multicast_skb(skbstat, ISCSI_NL_GRP_ISCSID,
2294 GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07002295 } while (err < 0 && err != -ECONNREFUSED);
2296
2297 return err;
2298}
2299
Mike Christie53cb8a12006-06-28 12:00:32 -05002300/**
Mike Christie26974782007-12-13 12:43:29 -06002301 * iscsi_session_event - send session destr. completion event
2302 * @session: iscsi class session
2303 * @event: type of event
Rob Landleyeb448202007-11-03 13:30:39 -05002304 */
Mike Christie26974782007-12-13 12:43:29 -06002305int iscsi_session_event(struct iscsi_cls_session *session,
2306 enum iscsi_uevent_e event)
Mike Christie53cb8a12006-06-28 12:00:32 -05002307{
2308 struct iscsi_internal *priv;
Mike Christie53cb8a12006-06-28 12:00:32 -05002309 struct Scsi_Host *shost;
2310 struct iscsi_uevent *ev;
2311 struct sk_buff *skb;
2312 struct nlmsghdr *nlh;
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002313 int rc, len = nlmsg_total_size(sizeof(*ev));
Mike Christie53cb8a12006-06-28 12:00:32 -05002314
Mike Christie26974782007-12-13 12:43:29 -06002315 priv = iscsi_if_transport_lookup(session->transport);
Mike Christie53cb8a12006-06-28 12:00:32 -05002316 if (!priv)
2317 return -EINVAL;
Mike Christie53cb8a12006-06-28 12:00:32 -05002318 shost = iscsi_session_to_shost(session);
2319
Mike Christie43a145a2006-10-16 18:09:38 -04002320 skb = alloc_skb(len, GFP_KERNEL);
Mike Christie53cb8a12006-06-28 12:00:32 -05002321 if (!skb) {
Mike Christie322d7392008-01-31 13:36:52 -06002322 iscsi_cls_session_printk(KERN_ERR, session,
2323 "Cannot notify userspace of session "
2324 "event %u\n", event);
Mike Christie53cb8a12006-06-28 12:00:32 -05002325 return -ENOMEM;
2326 }
2327
Michael Chan43514772009-06-08 18:14:41 -07002328 nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002329 ev = nlmsg_data(nlh);
Mike Christie26974782007-12-13 12:43:29 -06002330 ev->transport_handle = iscsi_handle(session->transport);
2331
2332 ev->type = event;
2333 switch (event) {
2334 case ISCSI_KEVENT_DESTROY_SESSION:
2335 ev->r.d_session.host_no = shost->host_no;
2336 ev->r.d_session.sid = session->sid;
2337 break;
2338 case ISCSI_KEVENT_CREATE_SESSION:
2339 ev->r.c_session_ret.host_no = shost->host_no;
2340 ev->r.c_session_ret.sid = session->sid;
2341 break;
2342 case ISCSI_KEVENT_UNBIND_SESSION:
2343 ev->r.unbind_session.host_no = shost->host_no;
2344 ev->r.unbind_session.sid = session->sid;
2345 break;
2346 default:
Mike Christie322d7392008-01-31 13:36:52 -06002347 iscsi_cls_session_printk(KERN_ERR, session, "Invalid event "
2348 "%u.\n", event);
Mike Christie26974782007-12-13 12:43:29 -06002349 kfree_skb(skb);
2350 return -EINVAL;
2351 }
Mike Christie53cb8a12006-06-28 12:00:32 -05002352
2353 /*
2354 * this will occur if the daemon is not up, so we just warn
2355 * the user and when the daemon is restarted it will handle it
2356 */
Michael Chan43514772009-06-08 18:14:41 -07002357 rc = iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
Pablo Neira Ayusoff491a72009-02-05 23:56:36 -08002358 if (rc == -ESRCH)
Mike Christie322d7392008-01-31 13:36:52 -06002359 iscsi_cls_session_printk(KERN_ERR, session,
2360 "Cannot notify userspace of session "
2361 "event %u. Check iscsi daemon\n",
2362 event);
Mike Christie632248a2009-08-20 15:11:01 -05002363
2364 ISCSI_DBG_TRANS_SESSION(session, "Completed handling event %d rc %d\n",
2365 event, rc);
Mike Christie53cb8a12006-06-28 12:00:32 -05002366 return rc;
2367}
Mike Christie26974782007-12-13 12:43:29 -06002368EXPORT_SYMBOL_GPL(iscsi_session_event);
Mike Christie53cb8a12006-06-28 12:00:32 -05002369
Alex Aizman0896b752005-08-04 19:33:07 -07002370static int
Mike Christied82ff9be2008-05-21 15:54:13 -05002371iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep,
Mike Christie0c70d842011-12-05 16:44:01 -06002372 struct iscsi_uevent *ev, pid_t pid,
2373 uint32_t initial_cmdsn, uint16_t cmds_max,
2374 uint16_t queue_depth)
Mike Christie7b8631b2006-01-13 18:05:50 -06002375{
2376 struct iscsi_transport *transport = priv->iscsi_transport;
Mike Christie7b7232f2006-02-01 21:06:49 -06002377 struct iscsi_cls_session *session;
Mike Christie5e7facb2009-03-05 14:46:06 -06002378 struct Scsi_Host *shost;
Mike Christie7b8631b2006-01-13 18:05:50 -06002379
Mike Christied82ff9be2008-05-21 15:54:13 -05002380 session = transport->create_session(ep, cmds_max, queue_depth,
Mike Christie5e7facb2009-03-05 14:46:06 -06002381 initial_cmdsn);
Mike Christie7b7232f2006-02-01 21:06:49 -06002382 if (!session)
Mike Christie7b8631b2006-01-13 18:05:50 -06002383 return -ENOMEM;
2384
Mike Christie0c70d842011-12-05 16:44:01 -06002385 session->creator = pid;
Mike Christie5e7facb2009-03-05 14:46:06 -06002386 shost = iscsi_session_to_shost(session);
2387 ev->r.c_session_ret.host_no = shost->host_no;
Mike Christieb5c7a122006-04-06 21:13:33 -05002388 ev->r.c_session_ret.sid = session->sid;
Mike Christie632248a2009-08-20 15:11:01 -05002389 ISCSI_DBG_TRANS_SESSION(session,
2390 "Completed creating transport session\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06002391 return 0;
2392}
2393
2394static int
Mike Christie7b7232f2006-02-01 21:06:49 -06002395iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
Mike Christie7b8631b2006-01-13 18:05:50 -06002396{
Mike Christie7b8631b2006-01-13 18:05:50 -06002397 struct iscsi_cls_conn *conn;
Mike Christie7b7232f2006-02-01 21:06:49 -06002398 struct iscsi_cls_session *session;
Mike Christie7b8631b2006-01-13 18:05:50 -06002399
Mike Christieb5c7a122006-04-06 21:13:33 -05002400 session = iscsi_session_lookup(ev->u.c_conn.sid);
2401 if (!session) {
Mike Christie322d7392008-01-31 13:36:52 -06002402 printk(KERN_ERR "iscsi: invalid session %d.\n",
Mike Christieb5c7a122006-04-06 21:13:33 -05002403 ev->u.c_conn.sid);
Mike Christie7b8631b2006-01-13 18:05:50 -06002404 return -EINVAL;
Mike Christieb5c7a122006-04-06 21:13:33 -05002405 }
Mike Christie7b8631b2006-01-13 18:05:50 -06002406
Mike Christie7b7232f2006-02-01 21:06:49 -06002407 conn = transport->create_conn(session, ev->u.c_conn.cid);
Mike Christieb5c7a122006-04-06 21:13:33 -05002408 if (!conn) {
Mike Christie322d7392008-01-31 13:36:52 -06002409 iscsi_cls_session_printk(KERN_ERR, session,
2410 "couldn't create a new connection.");
Mike Christie7b7232f2006-02-01 21:06:49 -06002411 return -ENOMEM;
Mike Christieb5c7a122006-04-06 21:13:33 -05002412 }
Mike Christie7b8631b2006-01-13 18:05:50 -06002413
Mike Christieb5c7a122006-04-06 21:13:33 -05002414 ev->r.c_conn_ret.sid = session->sid;
2415 ev->r.c_conn_ret.cid = conn->cid;
Mike Christie632248a2009-08-20 15:11:01 -05002416
2417 ISCSI_DBG_TRANS_CONN(conn, "Completed creating transport conn\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06002418 return 0;
Mike Christie7b8631b2006-01-13 18:05:50 -06002419}
2420
2421static int
2422iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
2423{
Mike Christie7b8631b2006-01-13 18:05:50 -06002424 struct iscsi_cls_conn *conn;
Mike Christie7b8631b2006-01-13 18:05:50 -06002425
Mike Christieb5c7a122006-04-06 21:13:33 -05002426 conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
Mike Christie7b8631b2006-01-13 18:05:50 -06002427 if (!conn)
Mike Christie7b8631b2006-01-13 18:05:50 -06002428 return -EINVAL;
Mike Christie7b8631b2006-01-13 18:05:50 -06002429
Mike Christie632248a2009-08-20 15:11:01 -05002430 ISCSI_DBG_TRANS_CONN(conn, "Destroying transport conn\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06002431 if (transport->destroy_conn)
2432 transport->destroy_conn(conn);
Mike Christie632248a2009-08-20 15:11:01 -05002433
Mike Christie7b8631b2006-01-13 18:05:50 -06002434 return 0;
2435}
2436
Mike Christiefd7255f2006-04-06 21:13:36 -05002437static int
2438iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
2439{
2440 char *data = (char*)ev + sizeof(*ev);
2441 struct iscsi_cls_conn *conn;
2442 struct iscsi_cls_session *session;
Mike Christiea54a52c2006-06-28 12:00:23 -05002443 int err = 0, value = 0;
Mike Christiefd7255f2006-04-06 21:13:36 -05002444
2445 session = iscsi_session_lookup(ev->u.set_param.sid);
2446 conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid);
2447 if (!conn || !session)
2448 return -EINVAL;
2449
2450 switch (ev->u.set_param.param) {
Mike Christie30a6c652006-04-06 21:13:39 -05002451 case ISCSI_PARAM_SESS_RECOVERY_TMO:
Mike Christiea54a52c2006-06-28 12:00:23 -05002452 sscanf(data, "%d", &value);
Mike Christiefdd46dc2009-11-11 16:34:34 -06002453 session->recovery_tmo = value;
Mike Christie30a6c652006-04-06 21:13:39 -05002454 break;
Mike Christiefd7255f2006-04-06 21:13:36 -05002455 default:
Mike Christiea54a52c2006-06-28 12:00:23 -05002456 err = transport->set_param(conn, ev->u.set_param.param,
2457 data, ev->u.set_param.len);
Mike Christiefd7255f2006-04-06 21:13:36 -05002458 }
2459
2460 return err;
2461}
2462
Mike Christie10eb0f02009-05-13 17:57:38 -05002463static int iscsi_if_ep_connect(struct iscsi_transport *transport,
2464 struct iscsi_uevent *ev, int msg_type)
2465{
2466 struct iscsi_endpoint *ep;
2467 struct sockaddr *dst_addr;
2468 struct Scsi_Host *shost = NULL;
2469 int non_blocking, err = 0;
2470
2471 if (!transport->ep_connect)
2472 return -EINVAL;
2473
2474 if (msg_type == ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST) {
2475 shost = scsi_host_lookup(ev->u.ep_connect_through_host.host_no);
2476 if (!shost) {
2477 printk(KERN_ERR "ep connect failed. Could not find "
2478 "host no %u\n",
2479 ev->u.ep_connect_through_host.host_no);
2480 return -ENODEV;
2481 }
2482 non_blocking = ev->u.ep_connect_through_host.non_blocking;
2483 } else
2484 non_blocking = ev->u.ep_connect.non_blocking;
2485
2486 dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
2487 ep = transport->ep_connect(shost, dst_addr, non_blocking);
2488 if (IS_ERR(ep)) {
2489 err = PTR_ERR(ep);
2490 goto release_host;
2491 }
2492
2493 ev->r.ep_connect_ret.handle = ep->id;
2494release_host:
2495 if (shost)
2496 scsi_host_put(shost);
2497 return err;
2498}
2499
Mike Christie22a39fb2011-02-16 15:04:33 -06002500static int iscsi_if_ep_disconnect(struct iscsi_transport *transport,
2501 u64 ep_handle)
2502{
2503 struct iscsi_cls_conn *conn;
2504 struct iscsi_endpoint *ep;
2505
2506 if (!transport->ep_disconnect)
2507 return -EINVAL;
2508
2509 ep = iscsi_lookup_endpoint(ep_handle);
2510 if (!ep)
2511 return -EINVAL;
2512 conn = ep->conn;
2513 if (conn) {
2514 mutex_lock(&conn->ep_mutex);
2515 conn->ep = NULL;
2516 mutex_unlock(&conn->ep_mutex);
2517 }
2518
2519 transport->ep_disconnect(ep);
2520 return 0;
2521}
2522
Mike Christie7b8631b2006-01-13 18:05:50 -06002523static int
Or Gerlitz264faaa2006-05-02 19:46:36 -05002524iscsi_if_transport_ep(struct iscsi_transport *transport,
2525 struct iscsi_uevent *ev, int msg_type)
2526{
Mike Christied82ff9be2008-05-21 15:54:13 -05002527 struct iscsi_endpoint *ep;
Or Gerlitz264faaa2006-05-02 19:46:36 -05002528 int rc = 0;
2529
2530 switch (msg_type) {
Mike Christie10eb0f02009-05-13 17:57:38 -05002531 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
Or Gerlitz264faaa2006-05-02 19:46:36 -05002532 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
Mike Christie10eb0f02009-05-13 17:57:38 -05002533 rc = iscsi_if_ep_connect(transport, ev, msg_type);
Or Gerlitz264faaa2006-05-02 19:46:36 -05002534 break;
2535 case ISCSI_UEVENT_TRANSPORT_EP_POLL:
2536 if (!transport->ep_poll)
2537 return -EINVAL;
2538
Mike Christied82ff9be2008-05-21 15:54:13 -05002539 ep = iscsi_lookup_endpoint(ev->u.ep_poll.ep_handle);
2540 if (!ep)
2541 return -EINVAL;
2542
2543 ev->r.retcode = transport->ep_poll(ep,
Or Gerlitz264faaa2006-05-02 19:46:36 -05002544 ev->u.ep_poll.timeout_ms);
2545 break;
2546 case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
Mike Christie22a39fb2011-02-16 15:04:33 -06002547 rc = iscsi_if_ep_disconnect(transport,
2548 ev->u.ep_disconnect.ep_handle);
Or Gerlitz264faaa2006-05-02 19:46:36 -05002549 break;
2550 }
2551 return rc;
2552}
2553
2554static int
Mike Christie01cb2252006-06-28 12:00:22 -05002555iscsi_tgt_dscvr(struct iscsi_transport *transport,
2556 struct iscsi_uevent *ev)
2557{
Mike Christie2174a042007-05-30 12:57:10 -05002558 struct Scsi_Host *shost;
Mike Christie01cb2252006-06-28 12:00:22 -05002559 struct sockaddr *dst_addr;
Mike Christie2174a042007-05-30 12:57:10 -05002560 int err;
Mike Christie01cb2252006-06-28 12:00:22 -05002561
2562 if (!transport->tgt_dscvr)
2563 return -EINVAL;
2564
Mike Christie2174a042007-05-30 12:57:10 -05002565 shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no);
James Smart315cb0a2008-08-07 20:49:30 -04002566 if (!shost) {
Mike Christie2174a042007-05-30 12:57:10 -05002567 printk(KERN_ERR "target discovery could not find host no %u\n",
2568 ev->u.tgt_dscvr.host_no);
2569 return -ENODEV;
2570 }
2571
2572
Mike Christie01cb2252006-06-28 12:00:22 -05002573 dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
Mike Christie2174a042007-05-30 12:57:10 -05002574 err = transport->tgt_dscvr(shost, ev->u.tgt_dscvr.type,
2575 ev->u.tgt_dscvr.enable, dst_addr);
2576 scsi_host_put(shost);
2577 return err;
Mike Christie01cb2252006-06-28 12:00:22 -05002578}
2579
2580static int
Mike Christie1d9bf132007-05-30 12:57:11 -05002581iscsi_set_host_param(struct iscsi_transport *transport,
2582 struct iscsi_uevent *ev)
2583{
2584 char *data = (char*)ev + sizeof(*ev);
2585 struct Scsi_Host *shost;
2586 int err;
2587
2588 if (!transport->set_host_param)
2589 return -ENOSYS;
2590
2591 shost = scsi_host_lookup(ev->u.set_host_param.host_no);
James Smart315cb0a2008-08-07 20:49:30 -04002592 if (!shost) {
Mike Christie1d9bf132007-05-30 12:57:11 -05002593 printk(KERN_ERR "set_host_param could not find host no %u\n",
2594 ev->u.set_host_param.host_no);
2595 return -ENODEV;
2596 }
2597
2598 err = transport->set_host_param(shost, ev->u.set_host_param.param,
2599 data, ev->u.set_host_param.len);
2600 scsi_host_put(shost);
2601 return err;
2602}
2603
2604static int
Michael Chan43514772009-06-08 18:14:41 -07002605iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev)
2606{
2607 struct Scsi_Host *shost;
2608 struct iscsi_path *params;
2609 int err;
2610
2611 if (!transport->set_path)
2612 return -ENOSYS;
2613
2614 shost = scsi_host_lookup(ev->u.set_path.host_no);
2615 if (!shost) {
2616 printk(KERN_ERR "set path could not find host no %u\n",
2617 ev->u.set_path.host_no);
2618 return -ENODEV;
2619 }
2620
2621 params = (struct iscsi_path *)((char *)ev + sizeof(*ev));
2622 err = transport->set_path(shost, params);
2623
2624 scsi_host_put(shost);
2625 return err;
2626}
2627
2628static int
Mike Christie56c155b2011-07-25 13:48:37 -05002629iscsi_set_iface_params(struct iscsi_transport *transport,
Mike Christie00c31882011-10-06 03:56:59 -05002630 struct iscsi_uevent *ev, uint32_t len)
Mike Christie56c155b2011-07-25 13:48:37 -05002631{
2632 char *data = (char *)ev + sizeof(*ev);
2633 struct Scsi_Host *shost;
2634 int err;
2635
2636 if (!transport->set_iface_param)
2637 return -ENOSYS;
2638
2639 shost = scsi_host_lookup(ev->u.set_iface_params.host_no);
2640 if (!shost) {
2641 printk(KERN_ERR "set_iface_params could not find host no %u\n",
2642 ev->u.set_iface_params.host_no);
2643 return -ENODEV;
2644 }
2645
Mike Christie00c31882011-10-06 03:56:59 -05002646 err = transport->set_iface_param(shost, data, len);
Mike Christie56c155b2011-07-25 13:48:37 -05002647 scsi_host_put(shost);
2648 return err;
2649}
2650
2651static int
Vikas Chaudharyac20c7b2012-02-13 18:30:48 +05302652iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev)
2653{
2654 struct Scsi_Host *shost;
2655 struct sockaddr *dst_addr;
2656 int err;
2657
2658 if (!transport->send_ping)
2659 return -ENOSYS;
2660
2661 shost = scsi_host_lookup(ev->u.iscsi_ping.host_no);
2662 if (!shost) {
2663 printk(KERN_ERR "iscsi_ping could not find host no %u\n",
2664 ev->u.iscsi_ping.host_no);
2665 return -ENODEV;
2666 }
2667
2668 dst_addr = (struct sockaddr *)((char *)ev + sizeof(*ev));
2669 err = transport->send_ping(shost, ev->u.iscsi_ping.iface_num,
2670 ev->u.iscsi_ping.iface_type,
2671 ev->u.iscsi_ping.payload_size,
2672 ev->u.iscsi_ping.pid,
2673 dst_addr);
2674 scsi_host_put(shost);
2675 return err;
2676}
2677
2678static int
Nilesh Javali6260a5d2012-02-27 03:08:51 -08002679iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
2680{
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002681 struct iscsi_uevent *ev = nlmsg_data(nlh);
Nilesh Javali6260a5d2012-02-27 03:08:51 -08002682 struct Scsi_Host *shost = NULL;
2683 struct iscsi_chap_rec *chap_rec;
2684 struct iscsi_internal *priv;
2685 struct sk_buff *skbchap;
2686 struct nlmsghdr *nlhchap;
2687 struct iscsi_uevent *evchap;
2688 uint32_t chap_buf_size;
2689 int len, err = 0;
2690 char *buf;
2691
2692 if (!transport->get_chap)
2693 return -EINVAL;
2694
2695 priv = iscsi_if_transport_lookup(transport);
2696 if (!priv)
2697 return -EINVAL;
2698
2699 chap_buf_size = (ev->u.get_chap.num_entries * sizeof(*chap_rec));
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002700 len = nlmsg_total_size(sizeof(*ev) + chap_buf_size);
Nilesh Javali6260a5d2012-02-27 03:08:51 -08002701
2702 shost = scsi_host_lookup(ev->u.get_chap.host_no);
2703 if (!shost) {
2704 printk(KERN_ERR "%s: failed. Cound not find host no %u\n",
2705 __func__, ev->u.get_chap.host_no);
2706 return -ENODEV;
2707 }
2708
2709 do {
2710 int actual_size;
2711
2712 skbchap = alloc_skb(len, GFP_KERNEL);
2713 if (!skbchap) {
2714 printk(KERN_ERR "can not deliver chap: OOM\n");
2715 err = -ENOMEM;
2716 goto exit_get_chap;
2717 }
2718
2719 nlhchap = __nlmsg_put(skbchap, 0, 0, 0,
2720 (len - sizeof(*nlhchap)), 0);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002721 evchap = nlmsg_data(nlhchap);
Nilesh Javali6260a5d2012-02-27 03:08:51 -08002722 memset(evchap, 0, sizeof(*evchap));
2723 evchap->transport_handle = iscsi_handle(transport);
2724 evchap->type = nlh->nlmsg_type;
2725 evchap->u.get_chap.host_no = ev->u.get_chap.host_no;
2726 evchap->u.get_chap.chap_tbl_idx = ev->u.get_chap.chap_tbl_idx;
2727 evchap->u.get_chap.num_entries = ev->u.get_chap.num_entries;
2728 buf = (char *) ((char *)evchap + sizeof(*evchap));
2729 memset(buf, 0, chap_buf_size);
2730
2731 err = transport->get_chap(shost, ev->u.get_chap.chap_tbl_idx,
2732 &evchap->u.get_chap.num_entries, buf);
2733
Hong zhi guoe07ebea2013-03-27 06:53:15 +00002734 actual_size = nlmsg_total_size(sizeof(*ev) + chap_buf_size);
Nilesh Javali6260a5d2012-02-27 03:08:51 -08002735 skb_trim(skbchap, NLMSG_ALIGN(actual_size));
2736 nlhchap->nlmsg_len = actual_size;
2737
2738 err = iscsi_multicast_skb(skbchap, ISCSI_NL_GRP_ISCSID,
2739 GFP_KERNEL);
2740 } while (err < 0 && err != -ECONNREFUSED);
2741
2742exit_get_chap:
2743 scsi_host_put(shost);
2744 return err;
2745}
2746
2747static int iscsi_delete_chap(struct iscsi_transport *transport,
2748 struct iscsi_uevent *ev)
2749{
2750 struct Scsi_Host *shost;
2751 int err = 0;
2752
2753 if (!transport->delete_chap)
2754 return -ENOSYS;
2755
2756 shost = scsi_host_lookup(ev->u.delete_chap.host_no);
2757 if (!shost) {
2758 printk(KERN_ERR "%s could not find host no %u\n",
2759 __func__, ev->u.delete_chap.host_no);
2760 return -ENODEV;
2761 }
2762
2763 err = transport->delete_chap(shost, ev->u.delete_chap.chap_tbl_idx);
2764 scsi_host_put(shost);
2765 return err;
2766}
2767
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002768static const struct {
2769 enum iscsi_discovery_parent_type value;
2770 char *name;
2771} iscsi_discovery_parent_names[] = {
2772 {ISCSI_DISC_PARENT_UNKNOWN, "Unknown" },
2773 {ISCSI_DISC_PARENT_SENDTGT, "Sendtarget" },
2774 {ISCSI_DISC_PARENT_ISNS, "isns" },
2775};
2776
2777char *iscsi_get_discovery_parent_name(int parent_type)
2778{
2779 int i;
2780 char *state = "Unknown!";
2781
2782 for (i = 0; i < ARRAY_SIZE(iscsi_discovery_parent_names); i++) {
2783 if (iscsi_discovery_parent_names[i].value & parent_type) {
2784 state = iscsi_discovery_parent_names[i].name;
2785 break;
2786 }
2787 }
2788 return state;
2789}
2790EXPORT_SYMBOL_GPL(iscsi_get_discovery_parent_name);
2791
2792static int iscsi_set_flashnode_param(struct iscsi_transport *transport,
2793 struct iscsi_uevent *ev, uint32_t len)
2794{
2795 char *data = (char *)ev + sizeof(*ev);
2796 struct Scsi_Host *shost;
2797 struct iscsi_bus_flash_session *fnode_sess;
2798 struct iscsi_bus_flash_conn *fnode_conn;
2799 struct device *dev;
Mike Christie8526cb12013-05-06 12:06:56 -05002800 uint32_t idx;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002801 int err = 0;
2802
2803 if (!transport->set_flashnode_param) {
2804 err = -ENOSYS;
2805 goto exit_set_fnode;
2806 }
2807
2808 shost = scsi_host_lookup(ev->u.set_flashnode.host_no);
2809 if (!shost) {
2810 pr_err("%s could not find host no %u\n",
2811 __func__, ev->u.set_flashnode.host_no);
2812 err = -ENODEV;
2813 goto put_host;
2814 }
2815
Mike Christie8526cb12013-05-06 12:06:56 -05002816 idx = ev->u.set_flashnode.flashnode_idx;
2817 fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002818 if (!fnode_sess) {
2819 pr_err("%s could not find flashnode %u for host no %u\n",
Mike Christie8526cb12013-05-06 12:06:56 -05002820 __func__, idx, ev->u.set_flashnode.host_no);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002821 err = -ENODEV;
2822 goto put_host;
2823 }
2824
Mike Christie8526cb12013-05-06 12:06:56 -05002825 dev = iscsi_find_flashnode_conn(fnode_sess);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002826 if (!dev) {
2827 err = -ENODEV;
Mike Christie8526cb12013-05-06 12:06:56 -05002828 goto put_sess;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002829 }
2830
2831 fnode_conn = iscsi_dev_to_flash_conn(dev);
2832 err = transport->set_flashnode_param(fnode_sess, fnode_conn, data, len);
Mike Christie8526cb12013-05-06 12:06:56 -05002833 put_device(dev);
2834
2835put_sess:
2836 put_device(&fnode_sess->dev);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002837
2838put_host:
2839 scsi_host_put(shost);
2840
2841exit_set_fnode:
2842 return err;
2843}
2844
2845static int iscsi_new_flashnode(struct iscsi_transport *transport,
2846 struct iscsi_uevent *ev, uint32_t len)
2847{
2848 char *data = (char *)ev + sizeof(*ev);
2849 struct Scsi_Host *shost;
2850 int index;
2851 int err = 0;
2852
2853 if (!transport->new_flashnode) {
2854 err = -ENOSYS;
2855 goto exit_new_fnode;
2856 }
2857
2858 shost = scsi_host_lookup(ev->u.new_flashnode.host_no);
2859 if (!shost) {
2860 pr_err("%s could not find host no %u\n",
2861 __func__, ev->u.new_flashnode.host_no);
2862 err = -ENODEV;
2863 goto put_host;
2864 }
2865
2866 index = transport->new_flashnode(shost, data, len);
2867
2868 if (index >= 0)
2869 ev->r.new_flashnode_ret.flashnode_idx = index;
2870 else
2871 err = -EIO;
2872
2873put_host:
2874 scsi_host_put(shost);
2875
2876exit_new_fnode:
2877 return err;
2878}
2879
2880static int iscsi_del_flashnode(struct iscsi_transport *transport,
2881 struct iscsi_uevent *ev)
2882{
2883 struct Scsi_Host *shost;
2884 struct iscsi_bus_flash_session *fnode_sess;
Mike Christie8526cb12013-05-06 12:06:56 -05002885 uint32_t idx;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002886 int err = 0;
2887
2888 if (!transport->del_flashnode) {
2889 err = -ENOSYS;
2890 goto exit_del_fnode;
2891 }
2892
2893 shost = scsi_host_lookup(ev->u.del_flashnode.host_no);
2894 if (!shost) {
2895 pr_err("%s could not find host no %u\n",
2896 __func__, ev->u.del_flashnode.host_no);
2897 err = -ENODEV;
2898 goto put_host;
2899 }
2900
Mike Christie8526cb12013-05-06 12:06:56 -05002901 idx = ev->u.del_flashnode.flashnode_idx;
2902 fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002903 if (!fnode_sess) {
2904 pr_err("%s could not find flashnode %u for host no %u\n",
Mike Christie8526cb12013-05-06 12:06:56 -05002905 __func__, idx, ev->u.del_flashnode.host_no);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002906 err = -ENODEV;
2907 goto put_host;
2908 }
2909
2910 err = transport->del_flashnode(fnode_sess);
Mike Christie8526cb12013-05-06 12:06:56 -05002911 put_device(&fnode_sess->dev);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002912
2913put_host:
2914 scsi_host_put(shost);
2915
2916exit_del_fnode:
2917 return err;
2918}
2919
2920static int iscsi_login_flashnode(struct iscsi_transport *transport,
2921 struct iscsi_uevent *ev)
2922{
2923 struct Scsi_Host *shost;
2924 struct iscsi_bus_flash_session *fnode_sess;
2925 struct iscsi_bus_flash_conn *fnode_conn;
2926 struct device *dev;
Mike Christie8526cb12013-05-06 12:06:56 -05002927 uint32_t idx;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002928 int err = 0;
2929
2930 if (!transport->login_flashnode) {
2931 err = -ENOSYS;
2932 goto exit_login_fnode;
2933 }
2934
2935 shost = scsi_host_lookup(ev->u.login_flashnode.host_no);
2936 if (!shost) {
2937 pr_err("%s could not find host no %u\n",
2938 __func__, ev->u.login_flashnode.host_no);
2939 err = -ENODEV;
2940 goto put_host;
2941 }
2942
Mike Christie8526cb12013-05-06 12:06:56 -05002943 idx = ev->u.login_flashnode.flashnode_idx;
2944 fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002945 if (!fnode_sess) {
2946 pr_err("%s could not find flashnode %u for host no %u\n",
Mike Christie8526cb12013-05-06 12:06:56 -05002947 __func__, idx, ev->u.login_flashnode.host_no);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002948 err = -ENODEV;
2949 goto put_host;
2950 }
2951
Mike Christie8526cb12013-05-06 12:06:56 -05002952 dev = iscsi_find_flashnode_conn(fnode_sess);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002953 if (!dev) {
2954 err = -ENODEV;
Mike Christie8526cb12013-05-06 12:06:56 -05002955 goto put_sess;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002956 }
2957
2958 fnode_conn = iscsi_dev_to_flash_conn(dev);
2959 err = transport->login_flashnode(fnode_sess, fnode_conn);
Mike Christie8526cb12013-05-06 12:06:56 -05002960 put_device(dev);
2961
2962put_sess:
2963 put_device(&fnode_sess->dev);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002964
2965put_host:
2966 scsi_host_put(shost);
2967
2968exit_login_fnode:
2969 return err;
2970}
2971
2972static int iscsi_logout_flashnode(struct iscsi_transport *transport,
2973 struct iscsi_uevent *ev)
2974{
2975 struct Scsi_Host *shost;
2976 struct iscsi_bus_flash_session *fnode_sess;
2977 struct iscsi_bus_flash_conn *fnode_conn;
2978 struct device *dev;
Mike Christie8526cb12013-05-06 12:06:56 -05002979 uint32_t idx;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002980 int err = 0;
2981
2982 if (!transport->logout_flashnode) {
2983 err = -ENOSYS;
2984 goto exit_logout_fnode;
2985 }
2986
2987 shost = scsi_host_lookup(ev->u.logout_flashnode.host_no);
2988 if (!shost) {
2989 pr_err("%s could not find host no %u\n",
2990 __func__, ev->u.logout_flashnode.host_no);
2991 err = -ENODEV;
2992 goto put_host;
2993 }
2994
Mike Christie8526cb12013-05-06 12:06:56 -05002995 idx = ev->u.logout_flashnode.flashnode_idx;
2996 fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002997 if (!fnode_sess) {
2998 pr_err("%s could not find flashnode %u for host no %u\n",
Mike Christie8526cb12013-05-06 12:06:56 -05002999 __func__, idx, ev->u.logout_flashnode.host_no);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04003000 err = -ENODEV;
3001 goto put_host;
3002 }
3003
Mike Christie8526cb12013-05-06 12:06:56 -05003004 dev = iscsi_find_flashnode_conn(fnode_sess);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04003005 if (!dev) {
3006 err = -ENODEV;
Mike Christie8526cb12013-05-06 12:06:56 -05003007 goto put_sess;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04003008 }
3009
3010 fnode_conn = iscsi_dev_to_flash_conn(dev);
3011
3012 err = transport->logout_flashnode(fnode_sess, fnode_conn);
Mike Christie8526cb12013-05-06 12:06:56 -05003013 put_device(dev);
3014
3015put_sess:
3016 put_device(&fnode_sess->dev);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04003017
3018put_host:
3019 scsi_host_put(shost);
3020
3021exit_logout_fnode:
3022 return err;
3023}
3024
3025static int iscsi_logout_flashnode_sid(struct iscsi_transport *transport,
3026 struct iscsi_uevent *ev)
3027{
3028 struct Scsi_Host *shost;
3029 struct iscsi_cls_session *session;
3030 int err = 0;
3031
3032 if (!transport->logout_flashnode_sid) {
3033 err = -ENOSYS;
3034 goto exit_logout_sid;
3035 }
3036
3037 shost = scsi_host_lookup(ev->u.logout_flashnode_sid.host_no);
3038 if (!shost) {
3039 pr_err("%s could not find host no %u\n",
3040 __func__, ev->u.logout_flashnode.host_no);
3041 err = -ENODEV;
3042 goto put_host;
3043 }
3044
3045 session = iscsi_session_lookup(ev->u.logout_flashnode_sid.sid);
3046 if (!session) {
3047 pr_err("%s could not find session id %u\n",
3048 __func__, ev->u.logout_flashnode_sid.sid);
3049 err = -EINVAL;
3050 goto put_host;
3051 }
3052
3053 err = transport->logout_flashnode_sid(session);
3054
3055put_host:
3056 scsi_host_put(shost);
3057
3058exit_logout_sid:
3059 return err;
3060}
3061
Nilesh Javali6260a5d2012-02-27 03:08:51 -08003062static int
Michael Chan43514772009-06-08 18:14:41 -07003063iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
Alex Aizman0896b752005-08-04 19:33:07 -07003064{
3065 int err = 0;
Hong zhi guoe07ebea2013-03-27 06:53:15 +00003066 struct iscsi_uevent *ev = nlmsg_data(nlh);
Alex Aizman0896b752005-08-04 19:33:07 -07003067 struct iscsi_transport *transport = NULL;
3068 struct iscsi_internal *priv;
Mike Christie7b7232f2006-02-01 21:06:49 -06003069 struct iscsi_cls_session *session;
3070 struct iscsi_cls_conn *conn;
Mike Christied82ff9be2008-05-21 15:54:13 -05003071 struct iscsi_endpoint *ep = NULL;
Alex Aizman0896b752005-08-04 19:33:07 -07003072
Michael Chan43514772009-06-08 18:14:41 -07003073 if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE)
3074 *group = ISCSI_NL_GRP_UIP;
3075 else
3076 *group = ISCSI_NL_GRP_ISCSID;
3077
Alex Aizman0896b752005-08-04 19:33:07 -07003078 priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
3079 if (!priv)
3080 return -EINVAL;
3081 transport = priv->iscsi_transport;
3082
Mike Christie7b7232f2006-02-01 21:06:49 -06003083 if (!try_module_get(transport->owner))
3084 return -EINVAL;
3085
Alex Aizman0896b752005-08-04 19:33:07 -07003086 switch (nlh->nlmsg_type) {
3087 case ISCSI_UEVENT_CREATE_SESSION:
Mike Christied82ff9be2008-05-21 15:54:13 -05003088 err = iscsi_if_create_session(priv, ep, ev,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003089 NETLINK_CB(skb).portid,
Mike Christie40753ca2008-05-21 15:53:56 -05003090 ev->u.c_session.initial_cmdsn,
3091 ev->u.c_session.cmds_max,
3092 ev->u.c_session.queue_depth);
3093 break;
3094 case ISCSI_UEVENT_CREATE_BOUND_SESSION:
Mike Christied82ff9be2008-05-21 15:54:13 -05003095 ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
Mike Christiec95fddc2008-06-16 10:11:32 -05003096 if (!ep) {
3097 err = -EINVAL;
3098 break;
3099 }
Mike Christied82ff9be2008-05-21 15:54:13 -05003100
3101 err = iscsi_if_create_session(priv, ep, ev,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003102 NETLINK_CB(skb).portid,
Mike Christie40753ca2008-05-21 15:53:56 -05003103 ev->u.c_bound_session.initial_cmdsn,
3104 ev->u.c_bound_session.cmds_max,
3105 ev->u.c_bound_session.queue_depth);
Alex Aizman0896b752005-08-04 19:33:07 -07003106 break;
3107 case ISCSI_UEVENT_DESTROY_SESSION:
Mike Christieb5c7a122006-04-06 21:13:33 -05003108 session = iscsi_session_lookup(ev->u.d_session.sid);
Mike Christie26974782007-12-13 12:43:29 -06003109 if (session)
Mike Christie7b7232f2006-02-01 21:06:49 -06003110 transport->destroy_session(session);
Mike Christie26974782007-12-13 12:43:29 -06003111 else
3112 err = -EINVAL;
3113 break;
3114 case ISCSI_UEVENT_UNBIND_SESSION:
3115 session = iscsi_session_lookup(ev->u.d_session.sid);
3116 if (session)
Mike Christie06d25af2009-03-05 14:46:02 -06003117 scsi_queue_work(iscsi_session_to_shost(session),
3118 &session->unbind_work);
Mike Christie26974782007-12-13 12:43:29 -06003119 else
Mike Christie7b7232f2006-02-01 21:06:49 -06003120 err = -EINVAL;
Alex Aizman0896b752005-08-04 19:33:07 -07003121 break;
3122 case ISCSI_UEVENT_CREATE_CONN:
3123 err = iscsi_if_create_conn(transport, ev);
3124 break;
3125 case ISCSI_UEVENT_DESTROY_CONN:
3126 err = iscsi_if_destroy_conn(transport, ev);
3127 break;
3128 case ISCSI_UEVENT_BIND_CONN:
Mike Christieb5c7a122006-04-06 21:13:33 -05003129 session = iscsi_session_lookup(ev->u.b_conn.sid);
3130 conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid);
Mike Christie7b7232f2006-02-01 21:06:49 -06003131
Mike Christie22a39fb2011-02-16 15:04:33 -06003132 if (conn && conn->ep)
3133 iscsi_if_ep_disconnect(transport, conn->ep->id);
3134
3135 if (!session || !conn) {
Mike Christie7b7232f2006-02-01 21:06:49 -06003136 err = -EINVAL;
Mike Christie22a39fb2011-02-16 15:04:33 -06003137 break;
3138 }
3139
3140 ev->r.retcode = transport->bind_conn(session, conn,
3141 ev->u.b_conn.transport_eph,
3142 ev->u.b_conn.is_leading);
3143 if (ev->r.retcode || !transport->ep_connect)
3144 break;
3145
3146 ep = iscsi_lookup_endpoint(ev->u.b_conn.transport_eph);
3147 if (ep) {
3148 ep->conn = conn;
3149
3150 mutex_lock(&conn->ep_mutex);
3151 conn->ep = ep;
3152 mutex_unlock(&conn->ep_mutex);
3153 } else
3154 iscsi_cls_conn_printk(KERN_ERR, conn,
3155 "Could not set ep conn "
3156 "binding\n");
Alex Aizman0896b752005-08-04 19:33:07 -07003157 break;
3158 case ISCSI_UEVENT_SET_PARAM:
Mike Christiefd7255f2006-04-06 21:13:36 -05003159 err = iscsi_set_param(transport, ev);
Alex Aizman0896b752005-08-04 19:33:07 -07003160 break;
3161 case ISCSI_UEVENT_START_CONN:
Mike Christieb5c7a122006-04-06 21:13:33 -05003162 conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid);
Mike Christie7b7232f2006-02-01 21:06:49 -06003163 if (conn)
3164 ev->r.retcode = transport->start_conn(conn);
3165 else
3166 err = -EINVAL;
Alex Aizman0896b752005-08-04 19:33:07 -07003167 break;
3168 case ISCSI_UEVENT_STOP_CONN:
Mike Christieb5c7a122006-04-06 21:13:33 -05003169 conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid);
Mike Christie7b7232f2006-02-01 21:06:49 -06003170 if (conn)
3171 transport->stop_conn(conn, ev->u.stop_conn.flag);
3172 else
3173 err = -EINVAL;
Alex Aizman0896b752005-08-04 19:33:07 -07003174 break;
3175 case ISCSI_UEVENT_SEND_PDU:
Mike Christieb5c7a122006-04-06 21:13:33 -05003176 conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid);
Mike Christie7b7232f2006-02-01 21:06:49 -06003177 if (conn)
3178 ev->r.retcode = transport->send_pdu(conn,
3179 (struct iscsi_hdr*)((char*)ev + sizeof(*ev)),
3180 (char*)ev + sizeof(*ev) + ev->u.send_pdu.hdr_size,
3181 ev->u.send_pdu.data_size);
3182 else
3183 err = -EINVAL;
Alex Aizman0896b752005-08-04 19:33:07 -07003184 break;
3185 case ISCSI_UEVENT_GET_STATS:
Mike Christie5b940ad2006-02-01 21:06:56 -06003186 err = iscsi_if_get_stats(transport, nlh);
Alex Aizman0896b752005-08-04 19:33:07 -07003187 break;
Or Gerlitz264faaa2006-05-02 19:46:36 -05003188 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
3189 case ISCSI_UEVENT_TRANSPORT_EP_POLL:
3190 case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
Mike Christie10eb0f02009-05-13 17:57:38 -05003191 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
Or Gerlitz264faaa2006-05-02 19:46:36 -05003192 err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
3193 break;
Mike Christie01cb2252006-06-28 12:00:22 -05003194 case ISCSI_UEVENT_TGT_DSCVR:
3195 err = iscsi_tgt_dscvr(transport, ev);
3196 break;
Mike Christie1d9bf132007-05-30 12:57:11 -05003197 case ISCSI_UEVENT_SET_HOST_PARAM:
3198 err = iscsi_set_host_param(transport, ev);
3199 break;
Michael Chan43514772009-06-08 18:14:41 -07003200 case ISCSI_UEVENT_PATH_UPDATE:
3201 err = iscsi_set_path(transport, ev);
3202 break;
Mike Christie56c155b2011-07-25 13:48:37 -05003203 case ISCSI_UEVENT_SET_IFACE_PARAMS:
Mike Christie00c31882011-10-06 03:56:59 -05003204 err = iscsi_set_iface_params(transport, ev,
3205 nlmsg_attrlen(nlh, sizeof(*ev)));
Mike Christie56c155b2011-07-25 13:48:37 -05003206 break;
Vikas Chaudharyac20c7b2012-02-13 18:30:48 +05303207 case ISCSI_UEVENT_PING:
3208 err = iscsi_send_ping(transport, ev);
3209 break;
Nilesh Javali6260a5d2012-02-27 03:08:51 -08003210 case ISCSI_UEVENT_GET_CHAP:
3211 err = iscsi_get_chap(transport, nlh);
3212 break;
3213 case ISCSI_UEVENT_DELETE_CHAP:
3214 err = iscsi_delete_chap(transport, ev);
3215 break;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04003216 case ISCSI_UEVENT_SET_FLASHNODE_PARAMS:
3217 err = iscsi_set_flashnode_param(transport, ev,
3218 nlmsg_attrlen(nlh,
3219 sizeof(*ev)));
3220 break;
3221 case ISCSI_UEVENT_NEW_FLASHNODE:
3222 err = iscsi_new_flashnode(transport, ev,
3223 nlmsg_attrlen(nlh, sizeof(*ev)));
3224 break;
3225 case ISCSI_UEVENT_DEL_FLASHNODE:
3226 err = iscsi_del_flashnode(transport, ev);
3227 break;
3228 case ISCSI_UEVENT_LOGIN_FLASHNODE:
3229 err = iscsi_login_flashnode(transport, ev);
3230 break;
3231 case ISCSI_UEVENT_LOGOUT_FLASHNODE:
3232 err = iscsi_logout_flashnode(transport, ev);
3233 break;
3234 case ISCSI_UEVENT_LOGOUT_FLASHNODE_SID:
3235 err = iscsi_logout_flashnode_sid(transport, ev);
3236 break;
Alex Aizman0896b752005-08-04 19:33:07 -07003237 default:
Mike Christie1d9bf132007-05-30 12:57:11 -05003238 err = -ENOSYS;
Alex Aizman0896b752005-08-04 19:33:07 -07003239 break;
3240 }
3241
Mike Christie7b7232f2006-02-01 21:06:49 -06003242 module_put(transport->owner);
Alex Aizman0896b752005-08-04 19:33:07 -07003243 return err;
3244}
3245
Mike Christieb5c7a122006-04-06 21:13:33 -05003246/*
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003247 * Get message from skb. Each message is processed by iscsi_if_recv_msg.
3248 * Malformed skbs with wrong lengths or invalid creds are not processed.
Mike Christieb5c7a122006-04-06 21:13:33 -05003249 */
Alex Aizman0896b752005-08-04 19:33:07 -07003250static void
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003251iscsi_if_rx(struct sk_buff *skb)
Alex Aizman0896b752005-08-04 19:33:07 -07003252{
Arjan van de Ven0b950672006-01-11 13:16:10 +01003253 mutex_lock(&rx_queue_mutex);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00003254 while (skb->len >= NLMSG_HDRLEN) {
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003255 int err;
3256 uint32_t rlen;
3257 struct nlmsghdr *nlh;
3258 struct iscsi_uevent *ev;
Michael Chan43514772009-06-08 18:14:41 -07003259 uint32_t group;
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003260
3261 nlh = nlmsg_hdr(skb);
3262 if (nlh->nlmsg_len < sizeof(*nlh) ||
3263 skb->len < nlh->nlmsg_len) {
3264 break;
Mike Christieee7f8e42006-02-01 21:07:01 -06003265 }
Mike Christieee7f8e42006-02-01 21:07:01 -06003266
Hong zhi guoe07ebea2013-03-27 06:53:15 +00003267 ev = nlmsg_data(nlh);
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003268 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
3269 if (rlen > skb->len)
3270 rlen = skb->len;
Alex Aizman0896b752005-08-04 19:33:07 -07003271
Michael Chan43514772009-06-08 18:14:41 -07003272 err = iscsi_if_recv_msg(skb, nlh, &group);
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003273 if (err) {
3274 ev->type = ISCSI_KEVENT_IF_ERROR;
3275 ev->iferror = err;
3276 }
3277 do {
3278 /*
3279 * special case for GET_STATS:
3280 * on success - sending reply and stats from
3281 * inside of if_recv_msg(),
3282 * on error - fall through.
3283 */
3284 if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
Alex Aizman0896b752005-08-04 19:33:07 -07003285 break;
Nilesh Javali6260a5d2012-02-27 03:08:51 -08003286 if (ev->type == ISCSI_UEVENT_GET_CHAP && !err)
3287 break;
Michael Chan43514772009-06-08 18:14:41 -07003288 err = iscsi_if_send_reply(group, nlh->nlmsg_seq,
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003289 nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
Sasha Levin46a7c172012-01-25 22:16:16 -05003290 } while (err < 0 && err != -ECONNREFUSED && err != -ESRCH);
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003291 skb_pull(skb, rlen);
Alex Aizman0896b752005-08-04 19:33:07 -07003292 }
Arjan van de Ven0b950672006-01-11 13:16:10 +01003293 mutex_unlock(&rx_queue_mutex);
Alex Aizman0896b752005-08-04 19:33:07 -07003294}
3295
Mike Christiefd7255f2006-04-06 21:13:36 -05003296#define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \
Tony Jonesee959b02008-02-22 00:13:36 +01003297struct device_attribute dev_attr_##_prefix##_##_name = \
Mike Christiefd7255f2006-04-06 21:13:36 -05003298 __ATTR(_name,_mode,_show,_store)
3299
Alex Aizman0896b752005-08-04 19:33:07 -07003300/*
3301 * iSCSI connection attrs
3302 */
Mike Christiea54a52c2006-06-28 12:00:23 -05003303#define iscsi_conn_attr_show(param) \
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01003305show_conn_param_##param(struct device *dev, \
3306 struct device_attribute *attr, char *buf) \
Mike Christiefd7255f2006-04-06 21:13:36 -05003307{ \
Tony Jonesee959b02008-02-22 00:13:36 +01003308 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
Mike Christiefd7255f2006-04-06 21:13:36 -05003309 struct iscsi_transport *t = conn->transport; \
Mike Christiea54a52c2006-06-28 12:00:23 -05003310 return t->get_conn_param(conn, param, buf); \
Mike Christiefd7255f2006-04-06 21:13:36 -05003311}
3312
Mike Christiea54a52c2006-06-28 12:00:23 -05003313#define iscsi_conn_attr(field, param) \
3314 iscsi_conn_attr_show(param) \
3315static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_param_##param, \
Mike Christiefd7255f2006-04-06 21:13:36 -05003316 NULL);
3317
Mike Christiea54a52c2006-06-28 12:00:23 -05003318iscsi_conn_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH);
3319iscsi_conn_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH);
3320iscsi_conn_attr(header_digest, ISCSI_PARAM_HDRDGST_EN);
3321iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN);
3322iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN);
3323iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN);
3324iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT);
Mike Christiea54a52c2006-06-28 12:00:23 -05003325iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
3326iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
Mike Christief6d51802007-12-13 12:43:30 -06003327iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
3328iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
Adheer Chandravanshiae542ed2013-07-01 05:54:11 -04003329iscsi_conn_attr(local_port, ISCSI_PARAM_LOCAL_PORT);
3330iscsi_conn_attr(statsn, ISCSI_PARAM_STATSN);
3331iscsi_conn_attr(keepalive_tmo, ISCSI_PARAM_KEEPALIVE_TMO);
3332iscsi_conn_attr(max_segment_size, ISCSI_PARAM_MAX_SEGMENT_SIZE);
3333iscsi_conn_attr(tcp_timestamp_stat, ISCSI_PARAM_TCP_TIMESTAMP_STAT);
3334iscsi_conn_attr(tcp_wsf_disable, ISCSI_PARAM_TCP_WSF_DISABLE);
3335iscsi_conn_attr(tcp_nagle_disable, ISCSI_PARAM_TCP_NAGLE_DISABLE);
3336iscsi_conn_attr(tcp_timer_scale, ISCSI_PARAM_TCP_TIMER_SCALE);
3337iscsi_conn_attr(tcp_timestamp_enable, ISCSI_PARAM_TCP_TIMESTAMP_EN);
3338iscsi_conn_attr(fragment_disable, ISCSI_PARAM_IP_FRAGMENT_DISABLE);
3339iscsi_conn_attr(ipv4_tos, ISCSI_PARAM_IPV4_TOS);
3340iscsi_conn_attr(ipv6_traffic_class, ISCSI_PARAM_IPV6_TC);
3341iscsi_conn_attr(ipv6_flow_label, ISCSI_PARAM_IPV6_FLOW_LABEL);
3342iscsi_conn_attr(is_fw_assigned_ipv6, ISCSI_PARAM_IS_FW_ASSIGNED_IPV6);
3343iscsi_conn_attr(tcp_xmit_wsf, ISCSI_PARAM_TCP_XMIT_WSF);
3344iscsi_conn_attr(tcp_recv_wsf, ISCSI_PARAM_TCP_RECV_WSF);
3345
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
Mike Christie289324b2011-02-16 15:04:37 -06003347#define iscsi_conn_ep_attr_show(param) \
3348static ssize_t show_conn_ep_param_##param(struct device *dev, \
3349 struct device_attribute *attr,\
3350 char *buf) \
3351{ \
3352 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
3353 struct iscsi_transport *t = conn->transport; \
3354 struct iscsi_endpoint *ep; \
3355 ssize_t rc; \
3356 \
3357 /* \
3358 * Need to make sure ep_disconnect does not free the LLD's \
3359 * interconnect resources while we are trying to read them. \
3360 */ \
3361 mutex_lock(&conn->ep_mutex); \
3362 ep = conn->ep; \
3363 if (!ep && t->ep_connect) { \
3364 mutex_unlock(&conn->ep_mutex); \
3365 return -ENOTCONN; \
3366 } \
3367 \
3368 if (ep) \
3369 rc = t->get_ep_param(ep, param, buf); \
3370 else \
3371 rc = t->get_conn_param(conn, param, buf); \
3372 mutex_unlock(&conn->ep_mutex); \
3373 return rc; \
3374}
3375
3376#define iscsi_conn_ep_attr(field, param) \
3377 iscsi_conn_ep_attr_show(param) \
3378static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, \
3379 show_conn_ep_param_##param, NULL);
3380
3381iscsi_conn_ep_attr(address, ISCSI_PARAM_CONN_ADDRESS);
3382iscsi_conn_ep_attr(port, ISCSI_PARAM_CONN_PORT);
3383
Mike Christie3128c6c2011-07-25 13:48:42 -05003384static struct attribute *iscsi_conn_attrs[] = {
3385 &dev_attr_conn_max_recv_dlength.attr,
3386 &dev_attr_conn_max_xmit_dlength.attr,
3387 &dev_attr_conn_header_digest.attr,
3388 &dev_attr_conn_data_digest.attr,
3389 &dev_attr_conn_ifmarker.attr,
3390 &dev_attr_conn_ofmarker.attr,
3391 &dev_attr_conn_address.attr,
3392 &dev_attr_conn_port.attr,
3393 &dev_attr_conn_exp_statsn.attr,
3394 &dev_attr_conn_persistent_address.attr,
3395 &dev_attr_conn_persistent_port.attr,
3396 &dev_attr_conn_ping_tmo.attr,
3397 &dev_attr_conn_recv_tmo.attr,
Adheer Chandravanshiae542ed2013-07-01 05:54:11 -04003398 &dev_attr_conn_local_port.attr,
3399 &dev_attr_conn_statsn.attr,
3400 &dev_attr_conn_keepalive_tmo.attr,
3401 &dev_attr_conn_max_segment_size.attr,
3402 &dev_attr_conn_tcp_timestamp_stat.attr,
3403 &dev_attr_conn_tcp_wsf_disable.attr,
3404 &dev_attr_conn_tcp_nagle_disable.attr,
3405 &dev_attr_conn_tcp_timer_scale.attr,
3406 &dev_attr_conn_tcp_timestamp_enable.attr,
3407 &dev_attr_conn_fragment_disable.attr,
3408 &dev_attr_conn_ipv4_tos.attr,
3409 &dev_attr_conn_ipv6_traffic_class.attr,
3410 &dev_attr_conn_ipv6_flow_label.attr,
3411 &dev_attr_conn_is_fw_assigned_ipv6.attr,
3412 &dev_attr_conn_tcp_xmit_wsf.attr,
3413 &dev_attr_conn_tcp_recv_wsf.attr,
Mike Christie3128c6c2011-07-25 13:48:42 -05003414 NULL,
3415};
3416
Al Viro587a1f12011-07-23 23:11:19 -04003417static umode_t iscsi_conn_attr_is_visible(struct kobject *kobj,
Mike Christie3128c6c2011-07-25 13:48:42 -05003418 struct attribute *attr, int i)
3419{
3420 struct device *cdev = container_of(kobj, struct device, kobj);
3421 struct iscsi_cls_conn *conn = transport_class_to_conn(cdev);
3422 struct iscsi_transport *t = conn->transport;
3423 int param;
3424
3425 if (attr == &dev_attr_conn_max_recv_dlength.attr)
3426 param = ISCSI_PARAM_MAX_RECV_DLENGTH;
3427 else if (attr == &dev_attr_conn_max_xmit_dlength.attr)
3428 param = ISCSI_PARAM_MAX_XMIT_DLENGTH;
3429 else if (attr == &dev_attr_conn_header_digest.attr)
3430 param = ISCSI_PARAM_HDRDGST_EN;
3431 else if (attr == &dev_attr_conn_data_digest.attr)
3432 param = ISCSI_PARAM_DATADGST_EN;
3433 else if (attr == &dev_attr_conn_ifmarker.attr)
3434 param = ISCSI_PARAM_IFMARKER_EN;
3435 else if (attr == &dev_attr_conn_ofmarker.attr)
3436 param = ISCSI_PARAM_OFMARKER_EN;
3437 else if (attr == &dev_attr_conn_address.attr)
3438 param = ISCSI_PARAM_CONN_ADDRESS;
3439 else if (attr == &dev_attr_conn_port.attr)
3440 param = ISCSI_PARAM_CONN_PORT;
3441 else if (attr == &dev_attr_conn_exp_statsn.attr)
3442 param = ISCSI_PARAM_EXP_STATSN;
3443 else if (attr == &dev_attr_conn_persistent_address.attr)
3444 param = ISCSI_PARAM_PERSISTENT_ADDRESS;
3445 else if (attr == &dev_attr_conn_persistent_port.attr)
3446 param = ISCSI_PARAM_PERSISTENT_PORT;
3447 else if (attr == &dev_attr_conn_ping_tmo.attr)
3448 param = ISCSI_PARAM_PING_TMO;
3449 else if (attr == &dev_attr_conn_recv_tmo.attr)
3450 param = ISCSI_PARAM_RECV_TMO;
Adheer Chandravanshiae542ed2013-07-01 05:54:11 -04003451 else if (attr == &dev_attr_conn_local_port.attr)
3452 param = ISCSI_PARAM_LOCAL_PORT;
3453 else if (attr == &dev_attr_conn_statsn.attr)
3454 param = ISCSI_PARAM_STATSN;
3455 else if (attr == &dev_attr_conn_keepalive_tmo.attr)
3456 param = ISCSI_PARAM_KEEPALIVE_TMO;
3457 else if (attr == &dev_attr_conn_max_segment_size.attr)
3458 param = ISCSI_PARAM_MAX_SEGMENT_SIZE;
3459 else if (attr == &dev_attr_conn_tcp_timestamp_stat.attr)
3460 param = ISCSI_PARAM_TCP_TIMESTAMP_STAT;
3461 else if (attr == &dev_attr_conn_tcp_wsf_disable.attr)
3462 param = ISCSI_PARAM_TCP_WSF_DISABLE;
3463 else if (attr == &dev_attr_conn_tcp_nagle_disable.attr)
3464 param = ISCSI_PARAM_TCP_NAGLE_DISABLE;
3465 else if (attr == &dev_attr_conn_tcp_timer_scale.attr)
3466 param = ISCSI_PARAM_TCP_TIMER_SCALE;
3467 else if (attr == &dev_attr_conn_tcp_timestamp_enable.attr)
3468 param = ISCSI_PARAM_TCP_TIMESTAMP_EN;
3469 else if (attr == &dev_attr_conn_fragment_disable.attr)
3470 param = ISCSI_PARAM_IP_FRAGMENT_DISABLE;
3471 else if (attr == &dev_attr_conn_ipv4_tos.attr)
3472 param = ISCSI_PARAM_IPV4_TOS;
3473 else if (attr == &dev_attr_conn_ipv6_traffic_class.attr)
3474 param = ISCSI_PARAM_IPV6_TC;
3475 else if (attr == &dev_attr_conn_ipv6_flow_label.attr)
3476 param = ISCSI_PARAM_IPV6_FLOW_LABEL;
3477 else if (attr == &dev_attr_conn_is_fw_assigned_ipv6.attr)
3478 param = ISCSI_PARAM_IS_FW_ASSIGNED_IPV6;
3479 else if (attr == &dev_attr_conn_tcp_xmit_wsf.attr)
3480 param = ISCSI_PARAM_TCP_XMIT_WSF;
3481 else if (attr == &dev_attr_conn_tcp_recv_wsf.attr)
3482 param = ISCSI_PARAM_TCP_RECV_WSF;
Mike Christie3128c6c2011-07-25 13:48:42 -05003483 else {
3484 WARN_ONCE(1, "Invalid conn attr");
3485 return 0;
3486 }
3487
3488 return t->attr_is_visible(ISCSI_PARAM, param);
3489}
3490
3491static struct attribute_group iscsi_conn_group = {
3492 .attrs = iscsi_conn_attrs,
3493 .is_visible = iscsi_conn_attr_is_visible,
3494};
3495
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496/*
Alex Aizman0896b752005-08-04 19:33:07 -07003497 * iSCSI session attrs
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 */
Mike Christieb2c64162007-05-30 12:57:16 -05003499#define iscsi_session_attr_show(param, perm) \
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01003501show_session_param_##param(struct device *dev, \
3502 struct device_attribute *attr, char *buf) \
Mike Christiefd7255f2006-04-06 21:13:36 -05003503{ \
Tony Jonesee959b02008-02-22 00:13:36 +01003504 struct iscsi_cls_session *session = \
3505 iscsi_dev_to_session(dev->parent); \
Mike Christiefd7255f2006-04-06 21:13:36 -05003506 struct iscsi_transport *t = session->transport; \
Mike Christieb2c64162007-05-30 12:57:16 -05003507 \
3508 if (perm && !capable(CAP_SYS_ADMIN)) \
3509 return -EACCES; \
Mike Christiea54a52c2006-06-28 12:00:23 -05003510 return t->get_session_param(session, param, buf); \
Mike Christiefd7255f2006-04-06 21:13:36 -05003511}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512
Mike Christieb2c64162007-05-30 12:57:16 -05003513#define iscsi_session_attr(field, param, perm) \
3514 iscsi_session_attr_show(param, perm) \
Mike Christiea54a52c2006-06-28 12:00:23 -05003515static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \
Mike Christiefd7255f2006-04-06 21:13:36 -05003516 NULL);
Mike Christieb2c64162007-05-30 12:57:16 -05003517iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME, 0);
3518iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, 0);
3519iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, 0);
3520iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, 0);
3521iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, 0);
3522iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, 0);
3523iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, 0);
3524iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, 0);
3525iscsi_session_attr(erl, ISCSI_PARAM_ERL, 0);
3526iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT, 0);
3527iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1);
3528iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
3529iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
3530iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
Mike Christie30534952012-02-27 03:08:53 -08003531iscsi_session_attr(chap_out_idx, ISCSI_PARAM_CHAP_OUT_IDX, 1);
3532iscsi_session_attr(chap_in_idx, ISCSI_PARAM_CHAP_IN_IDX, 1);
Mike Christie4cd49ea2007-12-13 12:43:38 -06003533iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
3534iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
3535iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
Mike Christie3fe5ae82009-11-11 16:34:33 -06003536iscsi_session_attr(tgt_reset_tmo, ISCSI_PARAM_TGT_RESET_TMO, 0);
Mike Christie88dfd342008-05-21 15:54:16 -05003537iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
Vikas Chaudhary3b2bef12010-07-10 14:51:30 +05303538iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0);
3539iscsi_session_attr(targetalias, ISCSI_PARAM_TARGET_ALIAS, 0);
Eddie Wai3b9373e2013-06-20 10:21:26 -07003540iscsi_session_attr(boot_root, ISCSI_PARAM_BOOT_ROOT, 0);
3541iscsi_session_attr(boot_nic, ISCSI_PARAM_BOOT_NIC, 0);
3542iscsi_session_attr(boot_target, ISCSI_PARAM_BOOT_TARGET, 0);
Adheer Chandravanshiae542ed2013-07-01 05:54:11 -04003543iscsi_session_attr(auto_snd_tgt_disable, ISCSI_PARAM_AUTO_SND_TGT_DISABLE, 0);
3544iscsi_session_attr(discovery_session, ISCSI_PARAM_DISCOVERY_SESS, 0);
3545iscsi_session_attr(portal_type, ISCSI_PARAM_PORTAL_TYPE, 0);
3546iscsi_session_attr(chap_auth, ISCSI_PARAM_CHAP_AUTH_EN, 0);
3547iscsi_session_attr(discovery_logout, ISCSI_PARAM_DISCOVERY_LOGOUT_EN, 0);
3548iscsi_session_attr(bidi_chap, ISCSI_PARAM_BIDI_CHAP_EN, 0);
3549iscsi_session_attr(discovery_auth_optional,
3550 ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL, 0);
3551iscsi_session_attr(def_time2wait, ISCSI_PARAM_DEF_TIME2WAIT, 0);
3552iscsi_session_attr(def_time2retain, ISCSI_PARAM_DEF_TIME2RETAIN, 0);
3553iscsi_session_attr(isid, ISCSI_PARAM_ISID, 0);
3554iscsi_session_attr(tsid, ISCSI_PARAM_TSID, 0);
3555iscsi_session_attr(def_taskmgmt_tmo, ISCSI_PARAM_DEF_TASKMGMT_TMO, 0);
3556iscsi_session_attr(discovery_parent_idx, ISCSI_PARAM_DISCOVERY_PARENT_IDX, 0);
3557iscsi_session_attr(discovery_parent_type, ISCSI_PARAM_DISCOVERY_PARENT_TYPE, 0);
Mike Christiefd7255f2006-04-06 21:13:36 -05003558
Mike Christie6eabafb2008-01-31 13:36:43 -06003559static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003560show_priv_session_state(struct device *dev, struct device_attribute *attr,
3561 char *buf)
Mike Christie6eabafb2008-01-31 13:36:43 -06003562{
Tony Jonesee959b02008-02-22 00:13:36 +01003563 struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
Mike Christie6eabafb2008-01-31 13:36:43 -06003564 return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
3565}
3566static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
3567 NULL);
Mike Christie0c70d842011-12-05 16:44:01 -06003568static ssize_t
3569show_priv_session_creator(struct device *dev, struct device_attribute *attr,
3570 char *buf)
3571{
3572 struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
3573 return sprintf(buf, "%d\n", session->creator);
3574}
3575static ISCSI_CLASS_ATTR(priv_sess, creator, S_IRUGO, show_priv_session_creator,
3576 NULL);
Manish Rangankar930a9f02012-11-23 06:58:41 -05003577static ssize_t
3578show_priv_session_target_id(struct device *dev, struct device_attribute *attr,
3579 char *buf)
3580{
3581 struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
3582 return sprintf(buf, "%d\n", session->target_id);
3583}
3584static ISCSI_CLASS_ATTR(priv_sess, target_id, S_IRUGO,
3585 show_priv_session_target_id, NULL);
Mike Christie6eabafb2008-01-31 13:36:43 -06003586
Mike Christiefd7255f2006-04-06 21:13:36 -05003587#define iscsi_priv_session_attr_show(field, format) \
3588static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01003589show_priv_session_##field(struct device *dev, \
3590 struct device_attribute *attr, char *buf) \
Mike Christiefd7255f2006-04-06 21:13:36 -05003591{ \
Tony Jonesee959b02008-02-22 00:13:36 +01003592 struct iscsi_cls_session *session = \
3593 iscsi_dev_to_session(dev->parent); \
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05303594 if (session->field == -1) \
3595 return sprintf(buf, "off\n"); \
Mike Christiefd7255f2006-04-06 21:13:36 -05003596 return sprintf(buf, format"\n", session->field); \
3597}
3598
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05303599#define iscsi_priv_session_attr_store(field) \
3600static ssize_t \
3601store_priv_session_##field(struct device *dev, \
3602 struct device_attribute *attr, \
3603 const char *buf, size_t count) \
3604{ \
3605 int val; \
3606 char *cp; \
3607 struct iscsi_cls_session *session = \
3608 iscsi_dev_to_session(dev->parent); \
3609 if ((session->state == ISCSI_SESSION_FREE) || \
3610 (session->state == ISCSI_SESSION_FAILED)) \
3611 return -EBUSY; \
3612 if (strncmp(buf, "off", 3) == 0) \
3613 session->field = -1; \
3614 else { \
3615 val = simple_strtoul(buf, &cp, 0); \
3616 if (*cp != '\0' && *cp != '\n') \
3617 return -EINVAL; \
3618 session->field = val; \
3619 } \
3620 return count; \
3621}
3622
3623#define iscsi_priv_session_rw_attr(field, format) \
Mike Christiefd7255f2006-04-06 21:13:36 -05003624 iscsi_priv_session_attr_show(field, format) \
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05303625 iscsi_priv_session_attr_store(field) \
Vasiliy Kulikov523f3c82011-02-04 15:24:14 +03003626static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUSR, \
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05303627 show_priv_session_##field, \
3628 store_priv_session_##field)
3629iscsi_priv_session_rw_attr(recovery_tmo, "%d");
Mike Christiefd7255f2006-04-06 21:13:36 -05003630
Mike Christie1d063c12011-07-25 13:48:43 -05003631static struct attribute *iscsi_session_attrs[] = {
3632 &dev_attr_sess_initial_r2t.attr,
3633 &dev_attr_sess_max_outstanding_r2t.attr,
3634 &dev_attr_sess_immediate_data.attr,
3635 &dev_attr_sess_first_burst_len.attr,
3636 &dev_attr_sess_max_burst_len.attr,
3637 &dev_attr_sess_data_pdu_in_order.attr,
3638 &dev_attr_sess_data_seq_in_order.attr,
3639 &dev_attr_sess_erl.attr,
3640 &dev_attr_sess_targetname.attr,
3641 &dev_attr_sess_tpgt.attr,
3642 &dev_attr_sess_password.attr,
3643 &dev_attr_sess_password_in.attr,
3644 &dev_attr_sess_username.attr,
3645 &dev_attr_sess_username_in.attr,
3646 &dev_attr_sess_fast_abort.attr,
3647 &dev_attr_sess_abort_tmo.attr,
3648 &dev_attr_sess_lu_reset_tmo.attr,
3649 &dev_attr_sess_tgt_reset_tmo.attr,
3650 &dev_attr_sess_ifacename.attr,
3651 &dev_attr_sess_initiatorname.attr,
3652 &dev_attr_sess_targetalias.attr,
Eddie Wai3b9373e2013-06-20 10:21:26 -07003653 &dev_attr_sess_boot_root.attr,
3654 &dev_attr_sess_boot_nic.attr,
3655 &dev_attr_sess_boot_target.attr,
Mike Christie1d063c12011-07-25 13:48:43 -05003656 &dev_attr_priv_sess_recovery_tmo.attr,
3657 &dev_attr_priv_sess_state.attr,
Mike Christie0c70d842011-12-05 16:44:01 -06003658 &dev_attr_priv_sess_creator.attr,
Mike Christie30534952012-02-27 03:08:53 -08003659 &dev_attr_sess_chap_out_idx.attr,
3660 &dev_attr_sess_chap_in_idx.attr,
Manish Rangankar930a9f02012-11-23 06:58:41 -05003661 &dev_attr_priv_sess_target_id.attr,
Adheer Chandravanshiae542ed2013-07-01 05:54:11 -04003662 &dev_attr_sess_auto_snd_tgt_disable.attr,
3663 &dev_attr_sess_discovery_session.attr,
3664 &dev_attr_sess_portal_type.attr,
3665 &dev_attr_sess_chap_auth.attr,
3666 &dev_attr_sess_discovery_logout.attr,
3667 &dev_attr_sess_bidi_chap.attr,
3668 &dev_attr_sess_discovery_auth_optional.attr,
3669 &dev_attr_sess_def_time2wait.attr,
3670 &dev_attr_sess_def_time2retain.attr,
3671 &dev_attr_sess_isid.attr,
3672 &dev_attr_sess_tsid.attr,
3673 &dev_attr_sess_def_taskmgmt_tmo.attr,
3674 &dev_attr_sess_discovery_parent_idx.attr,
3675 &dev_attr_sess_discovery_parent_type.attr,
Mike Christie1d063c12011-07-25 13:48:43 -05003676 NULL,
3677};
3678
Al Viro587a1f12011-07-23 23:11:19 -04003679static umode_t iscsi_session_attr_is_visible(struct kobject *kobj,
Mike Christie1d063c12011-07-25 13:48:43 -05003680 struct attribute *attr, int i)
3681{
3682 struct device *cdev = container_of(kobj, struct device, kobj);
3683 struct iscsi_cls_session *session = transport_class_to_session(cdev);
3684 struct iscsi_transport *t = session->transport;
3685 int param;
3686
3687 if (attr == &dev_attr_sess_initial_r2t.attr)
3688 param = ISCSI_PARAM_INITIAL_R2T_EN;
3689 else if (attr == &dev_attr_sess_max_outstanding_r2t.attr)
3690 param = ISCSI_PARAM_MAX_R2T;
3691 else if (attr == &dev_attr_sess_immediate_data.attr)
3692 param = ISCSI_PARAM_IMM_DATA_EN;
3693 else if (attr == &dev_attr_sess_first_burst_len.attr)
3694 param = ISCSI_PARAM_FIRST_BURST;
3695 else if (attr == &dev_attr_sess_max_burst_len.attr)
3696 param = ISCSI_PARAM_MAX_BURST;
3697 else if (attr == &dev_attr_sess_data_pdu_in_order.attr)
3698 param = ISCSI_PARAM_PDU_INORDER_EN;
3699 else if (attr == &dev_attr_sess_data_seq_in_order.attr)
3700 param = ISCSI_PARAM_DATASEQ_INORDER_EN;
3701 else if (attr == &dev_attr_sess_erl.attr)
3702 param = ISCSI_PARAM_ERL;
3703 else if (attr == &dev_attr_sess_targetname.attr)
3704 param = ISCSI_PARAM_TARGET_NAME;
3705 else if (attr == &dev_attr_sess_tpgt.attr)
3706 param = ISCSI_PARAM_TPGT;
Mike Christie30534952012-02-27 03:08:53 -08003707 else if (attr == &dev_attr_sess_chap_in_idx.attr)
3708 param = ISCSI_PARAM_CHAP_IN_IDX;
3709 else if (attr == &dev_attr_sess_chap_out_idx.attr)
3710 param = ISCSI_PARAM_CHAP_OUT_IDX;
Mike Christie1d063c12011-07-25 13:48:43 -05003711 else if (attr == &dev_attr_sess_password.attr)
3712 param = ISCSI_PARAM_USERNAME;
3713 else if (attr == &dev_attr_sess_password_in.attr)
3714 param = ISCSI_PARAM_USERNAME_IN;
3715 else if (attr == &dev_attr_sess_username.attr)
3716 param = ISCSI_PARAM_PASSWORD;
3717 else if (attr == &dev_attr_sess_username_in.attr)
3718 param = ISCSI_PARAM_PASSWORD_IN;
3719 else if (attr == &dev_attr_sess_fast_abort.attr)
3720 param = ISCSI_PARAM_FAST_ABORT;
3721 else if (attr == &dev_attr_sess_abort_tmo.attr)
3722 param = ISCSI_PARAM_ABORT_TMO;
3723 else if (attr == &dev_attr_sess_lu_reset_tmo.attr)
3724 param = ISCSI_PARAM_LU_RESET_TMO;
3725 else if (attr == &dev_attr_sess_tgt_reset_tmo.attr)
3726 param = ISCSI_PARAM_TGT_RESET_TMO;
3727 else if (attr == &dev_attr_sess_ifacename.attr)
3728 param = ISCSI_PARAM_IFACE_NAME;
3729 else if (attr == &dev_attr_sess_initiatorname.attr)
3730 param = ISCSI_PARAM_INITIATOR_NAME;
3731 else if (attr == &dev_attr_sess_targetalias.attr)
3732 param = ISCSI_PARAM_TARGET_ALIAS;
Eddie Wai3b9373e2013-06-20 10:21:26 -07003733 else if (attr == &dev_attr_sess_boot_root.attr)
3734 param = ISCSI_PARAM_BOOT_ROOT;
3735 else if (attr == &dev_attr_sess_boot_nic.attr)
3736 param = ISCSI_PARAM_BOOT_NIC;
3737 else if (attr == &dev_attr_sess_boot_target.attr)
3738 param = ISCSI_PARAM_BOOT_TARGET;
Adheer Chandravanshiae542ed2013-07-01 05:54:11 -04003739 else if (attr == &dev_attr_sess_auto_snd_tgt_disable.attr)
3740 param = ISCSI_PARAM_AUTO_SND_TGT_DISABLE;
3741 else if (attr == &dev_attr_sess_discovery_session.attr)
3742 param = ISCSI_PARAM_DISCOVERY_SESS;
3743 else if (attr == &dev_attr_sess_portal_type.attr)
3744 param = ISCSI_PARAM_PORTAL_TYPE;
3745 else if (attr == &dev_attr_sess_chap_auth.attr)
3746 param = ISCSI_PARAM_CHAP_AUTH_EN;
3747 else if (attr == &dev_attr_sess_discovery_logout.attr)
3748 param = ISCSI_PARAM_DISCOVERY_LOGOUT_EN;
3749 else if (attr == &dev_attr_sess_bidi_chap.attr)
3750 param = ISCSI_PARAM_BIDI_CHAP_EN;
3751 else if (attr == &dev_attr_sess_discovery_auth_optional.attr)
3752 param = ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL;
3753 else if (attr == &dev_attr_sess_def_time2wait.attr)
3754 param = ISCSI_PARAM_DEF_TIME2WAIT;
3755 else if (attr == &dev_attr_sess_def_time2retain.attr)
3756 param = ISCSI_PARAM_DEF_TIME2RETAIN;
3757 else if (attr == &dev_attr_sess_isid.attr)
3758 param = ISCSI_PARAM_ISID;
3759 else if (attr == &dev_attr_sess_tsid.attr)
3760 param = ISCSI_PARAM_TSID;
3761 else if (attr == &dev_attr_sess_def_taskmgmt_tmo.attr)
3762 param = ISCSI_PARAM_DEF_TASKMGMT_TMO;
3763 else if (attr == &dev_attr_sess_discovery_parent_idx.attr)
3764 param = ISCSI_PARAM_DISCOVERY_PARENT_IDX;
3765 else if (attr == &dev_attr_sess_discovery_parent_type.attr)
3766 param = ISCSI_PARAM_DISCOVERY_PARENT_TYPE;
Mike Christie1d063c12011-07-25 13:48:43 -05003767 else if (attr == &dev_attr_priv_sess_recovery_tmo.attr)
3768 return S_IRUGO | S_IWUSR;
3769 else if (attr == &dev_attr_priv_sess_state.attr)
3770 return S_IRUGO;
Mike Christie0c70d842011-12-05 16:44:01 -06003771 else if (attr == &dev_attr_priv_sess_creator.attr)
3772 return S_IRUGO;
Manish Rangankar930a9f02012-11-23 06:58:41 -05003773 else if (attr == &dev_attr_priv_sess_target_id.attr)
3774 return S_IRUGO;
Mike Christie1d063c12011-07-25 13:48:43 -05003775 else {
3776 WARN_ONCE(1, "Invalid session attr");
3777 return 0;
3778 }
3779
3780 return t->attr_is_visible(ISCSI_PARAM, param);
3781}
3782
3783static struct attribute_group iscsi_session_group = {
3784 .attrs = iscsi_session_attrs,
3785 .is_visible = iscsi_session_attr_is_visible,
3786};
3787
Mike Christie1819dc82007-05-30 12:57:08 -05003788/*
3789 * iSCSI host attrs
3790 */
3791#define iscsi_host_attr_show(param) \
3792static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01003793show_host_param_##param(struct device *dev, \
3794 struct device_attribute *attr, char *buf) \
Mike Christie1819dc82007-05-30 12:57:08 -05003795{ \
Tony Jonesee959b02008-02-22 00:13:36 +01003796 struct Scsi_Host *shost = transport_class_to_shost(dev); \
Mike Christie1819dc82007-05-30 12:57:08 -05003797 struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
3798 return priv->iscsi_transport->get_host_param(shost, param, buf); \
3799}
3800
3801#define iscsi_host_attr(field, param) \
3802 iscsi_host_attr_show(param) \
3803static ISCSI_CLASS_ATTR(host, field, S_IRUGO, show_host_param_##param, \
3804 NULL);
3805
Mike Christied8196ed2007-05-30 12:57:25 -05003806iscsi_host_attr(netdev, ISCSI_HOST_PARAM_NETDEV_NAME);
Mike Christie1819dc82007-05-30 12:57:08 -05003807iscsi_host_attr(hwaddress, ISCSI_HOST_PARAM_HWADDRESS);
Mike Christied8196ed2007-05-30 12:57:25 -05003808iscsi_host_attr(ipaddress, ISCSI_HOST_PARAM_IPADDRESS);
Mike Christie8ad57812007-05-30 12:57:13 -05003809iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
Vikas Chaudharyaeddde22012-01-19 03:06:55 -08003810iscsi_host_attr(port_state, ISCSI_HOST_PARAM_PORT_STATE);
3811iscsi_host_attr(port_speed, ISCSI_HOST_PARAM_PORT_SPEED);
Mike Christie1819dc82007-05-30 12:57:08 -05003812
Mike Christief27fb2e2011-07-25 13:48:45 -05003813static struct attribute *iscsi_host_attrs[] = {
3814 &dev_attr_host_netdev.attr,
3815 &dev_attr_host_hwaddress.attr,
3816 &dev_attr_host_ipaddress.attr,
3817 &dev_attr_host_initiatorname.attr,
Vikas Chaudharyaeddde22012-01-19 03:06:55 -08003818 &dev_attr_host_port_state.attr,
3819 &dev_attr_host_port_speed.attr,
Mike Christief27fb2e2011-07-25 13:48:45 -05003820 NULL,
3821};
3822
Al Viro587a1f12011-07-23 23:11:19 -04003823static umode_t iscsi_host_attr_is_visible(struct kobject *kobj,
Mike Christief27fb2e2011-07-25 13:48:45 -05003824 struct attribute *attr, int i)
3825{
3826 struct device *cdev = container_of(kobj, struct device, kobj);
3827 struct Scsi_Host *shost = transport_class_to_shost(cdev);
3828 struct iscsi_internal *priv = to_iscsi_internal(shost->transportt);
3829 int param;
3830
3831 if (attr == &dev_attr_host_netdev.attr)
3832 param = ISCSI_HOST_PARAM_NETDEV_NAME;
3833 else if (attr == &dev_attr_host_hwaddress.attr)
3834 param = ISCSI_HOST_PARAM_HWADDRESS;
3835 else if (attr == &dev_attr_host_ipaddress.attr)
3836 param = ISCSI_HOST_PARAM_IPADDRESS;
3837 else if (attr == &dev_attr_host_initiatorname.attr)
3838 param = ISCSI_HOST_PARAM_INITIATOR_NAME;
Vikas Chaudharyaeddde22012-01-19 03:06:55 -08003839 else if (attr == &dev_attr_host_port_state.attr)
3840 param = ISCSI_HOST_PARAM_PORT_STATE;
3841 else if (attr == &dev_attr_host_port_speed.attr)
3842 param = ISCSI_HOST_PARAM_PORT_SPEED;
Mike Christief27fb2e2011-07-25 13:48:45 -05003843 else {
3844 WARN_ONCE(1, "Invalid host attr");
3845 return 0;
3846 }
3847
3848 return priv->iscsi_transport->attr_is_visible(ISCSI_HOST_PARAM, param);
3849}
3850
3851static struct attribute_group iscsi_host_group = {
3852 .attrs = iscsi_host_attrs,
3853 .is_visible = iscsi_host_attr_is_visible,
3854};
Mike Christie1819dc82007-05-30 12:57:08 -05003855
Vikas Chaudharyaeddde22012-01-19 03:06:55 -08003856/* convert iscsi_port_speed values to ascii string name */
3857static const struct {
3858 enum iscsi_port_speed value;
3859 char *name;
3860} iscsi_port_speed_names[] = {
3861 {ISCSI_PORT_SPEED_UNKNOWN, "Unknown" },
3862 {ISCSI_PORT_SPEED_10MBPS, "10 Mbps" },
3863 {ISCSI_PORT_SPEED_100MBPS, "100 Mbps" },
3864 {ISCSI_PORT_SPEED_1GBPS, "1 Gbps" },
3865 {ISCSI_PORT_SPEED_10GBPS, "10 Gbps" },
3866};
3867
3868char *iscsi_get_port_speed_name(struct Scsi_Host *shost)
3869{
3870 int i;
3871 char *speed = "Unknown!";
3872 struct iscsi_cls_host *ihost = shost->shost_data;
3873 uint32_t port_speed = ihost->port_speed;
3874
3875 for (i = 0; i < ARRAY_SIZE(iscsi_port_speed_names); i++) {
3876 if (iscsi_port_speed_names[i].value & port_speed) {
3877 speed = iscsi_port_speed_names[i].name;
3878 break;
3879 }
3880 }
3881 return speed;
3882}
3883EXPORT_SYMBOL_GPL(iscsi_get_port_speed_name);
3884
3885/* convert iscsi_port_state values to ascii string name */
3886static const struct {
3887 enum iscsi_port_state value;
3888 char *name;
3889} iscsi_port_state_names[] = {
3890 {ISCSI_PORT_STATE_DOWN, "LINK DOWN" },
3891 {ISCSI_PORT_STATE_UP, "LINK UP" },
3892};
3893
3894char *iscsi_get_port_state_name(struct Scsi_Host *shost)
3895{
3896 int i;
3897 char *state = "Unknown!";
3898 struct iscsi_cls_host *ihost = shost->shost_data;
3899 uint32_t port_state = ihost->port_state;
3900
3901 for (i = 0; i < ARRAY_SIZE(iscsi_port_state_names); i++) {
3902 if (iscsi_port_state_names[i].value & port_state) {
3903 state = iscsi_port_state_names[i].name;
3904 break;
3905 }
3906 }
3907 return state;
3908}
3909EXPORT_SYMBOL_GPL(iscsi_get_port_state_name);
3910
Alex Aizman0896b752005-08-04 19:33:07 -07003911static int iscsi_session_match(struct attribute_container *cont,
3912 struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913{
Mike Christie7b8631b2006-01-13 18:05:50 -06003914 struct iscsi_cls_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 struct Scsi_Host *shost;
Alex Aizman0896b752005-08-04 19:33:07 -07003916 struct iscsi_internal *priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917
Alex Aizman0896b752005-08-04 19:33:07 -07003918 if (!iscsi_is_session_dev(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 return 0;
3920
Mike Christie7b8631b2006-01-13 18:05:50 -06003921 session = iscsi_dev_to_session(dev);
3922 shost = iscsi_session_to_shost(session);
Alex Aizman0896b752005-08-04 19:33:07 -07003923 if (!shost->transportt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 return 0;
3925
Alex Aizman0896b752005-08-04 19:33:07 -07003926 priv = to_iscsi_internal(shost->transportt);
3927 if (priv->session_cont.ac.class != &iscsi_session_class.class)
3928 return 0;
3929
3930 return &priv->session_cont.ac == cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931}
3932
Alex Aizman0896b752005-08-04 19:33:07 -07003933static int iscsi_conn_match(struct attribute_container *cont,
3934 struct device *dev)
3935{
Mike Christie7b8631b2006-01-13 18:05:50 -06003936 struct iscsi_cls_session *session;
3937 struct iscsi_cls_conn *conn;
Alex Aizman0896b752005-08-04 19:33:07 -07003938 struct Scsi_Host *shost;
3939 struct iscsi_internal *priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940
Alex Aizman0896b752005-08-04 19:33:07 -07003941 if (!iscsi_is_conn_dev(dev))
3942 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943
Mike Christie7b8631b2006-01-13 18:05:50 -06003944 conn = iscsi_dev_to_conn(dev);
3945 session = iscsi_dev_to_session(conn->dev.parent);
3946 shost = iscsi_session_to_shost(session);
3947
Alex Aizman0896b752005-08-04 19:33:07 -07003948 if (!shost->transportt)
3949 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950
Alex Aizman0896b752005-08-04 19:33:07 -07003951 priv = to_iscsi_internal(shost->transportt);
3952 if (priv->conn_cont.ac.class != &iscsi_connection_class.class)
3953 return 0;
3954
3955 return &priv->conn_cont.ac == cont;
3956}
3957
Mike Christie30a6c652006-04-06 21:13:39 -05003958static int iscsi_host_match(struct attribute_container *cont,
3959 struct device *dev)
3960{
3961 struct Scsi_Host *shost;
3962 struct iscsi_internal *priv;
3963
3964 if (!scsi_is_host_device(dev))
3965 return 0;
3966
3967 shost = dev_to_shost(dev);
3968 if (!shost->transportt ||
3969 shost->transportt->host_attrs.ac.class != &iscsi_host_class.class)
3970 return 0;
3971
3972 priv = to_iscsi_internal(shost->transportt);
3973 return &priv->t.host_attrs.ac == cont;
3974}
3975
Mike Christie7b8631b2006-01-13 18:05:50 -06003976struct scsi_transport_template *
3977iscsi_register_transport(struct iscsi_transport *tt)
Alex Aizman0896b752005-08-04 19:33:07 -07003978{
3979 struct iscsi_internal *priv;
3980 unsigned long flags;
Mike Christief27fb2e2011-07-25 13:48:45 -05003981 int err;
Alex Aizman0896b752005-08-04 19:33:07 -07003982
3983 BUG_ON(!tt);
3984
3985 priv = iscsi_if_transport_lookup(tt);
3986 if (priv)
Mike Christie7b8631b2006-01-13 18:05:50 -06003987 return NULL;
Alex Aizman0896b752005-08-04 19:33:07 -07003988
Jes Sorensen24669f752006-01-16 10:31:18 -05003989 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
Alex Aizman0896b752005-08-04 19:33:07 -07003990 if (!priv)
Mike Christie7b8631b2006-01-13 18:05:50 -06003991 return NULL;
Alex Aizman0896b752005-08-04 19:33:07 -07003992 INIT_LIST_HEAD(&priv->list);
Alex Aizman0896b752005-08-04 19:33:07 -07003993 priv->iscsi_transport = tt;
Mike Christie30a6c652006-04-06 21:13:39 -05003994 priv->t.user_scan = iscsi_user_scan;
Mike Christie06d25af2009-03-05 14:46:02 -06003995 priv->t.create_work_queue = 1;
Alex Aizman0896b752005-08-04 19:33:07 -07003996
Tony Jonesee959b02008-02-22 00:13:36 +01003997 priv->dev.class = &iscsi_transport_class;
Kay Sievers71610f52008-12-03 22:41:36 +01003998 dev_set_name(&priv->dev, "%s", tt->name);
Tony Jonesee959b02008-02-22 00:13:36 +01003999 err = device_register(&priv->dev);
Alex Aizman0896b752005-08-04 19:33:07 -07004000 if (err)
4001 goto free_priv;
4002
Tony Jonesee959b02008-02-22 00:13:36 +01004003 err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
Alex Aizman0896b752005-08-04 19:33:07 -07004004 if (err)
Tony Jonesee959b02008-02-22 00:13:36 +01004005 goto unregister_dev;
Alex Aizman0896b752005-08-04 19:33:07 -07004006
Mike Christie30a6c652006-04-06 21:13:39 -05004007 /* host parameters */
Mike Christie30a6c652006-04-06 21:13:39 -05004008 priv->t.host_attrs.ac.class = &iscsi_host_class.class;
4009 priv->t.host_attrs.ac.match = iscsi_host_match;
Mike Christief27fb2e2011-07-25 13:48:45 -05004010 priv->t.host_attrs.ac.grp = &iscsi_host_group;
Mike Christie32c6e1b2008-05-21 15:53:58 -05004011 priv->t.host_size = sizeof(struct iscsi_cls_host);
Mike Christie30a6c652006-04-06 21:13:39 -05004012 transport_container_register(&priv->t.host_attrs);
4013
Alex Aizman0896b752005-08-04 19:33:07 -07004014 /* connection parameters */
Alex Aizman0896b752005-08-04 19:33:07 -07004015 priv->conn_cont.ac.class = &iscsi_connection_class.class;
4016 priv->conn_cont.ac.match = iscsi_conn_match;
Mike Christie3128c6c2011-07-25 13:48:42 -05004017 priv->conn_cont.ac.grp = &iscsi_conn_group;
Alex Aizman0896b752005-08-04 19:33:07 -07004018 transport_container_register(&priv->conn_cont);
4019
Alex Aizman0896b752005-08-04 19:33:07 -07004020 /* session parameters */
Alex Aizman0896b752005-08-04 19:33:07 -07004021 priv->session_cont.ac.class = &iscsi_session_class.class;
4022 priv->session_cont.ac.match = iscsi_session_match;
Mike Christie1d063c12011-07-25 13:48:43 -05004023 priv->session_cont.ac.grp = &iscsi_session_group;
Alex Aizman0896b752005-08-04 19:33:07 -07004024 transport_container_register(&priv->session_cont);
4025
Alex Aizman0896b752005-08-04 19:33:07 -07004026 spin_lock_irqsave(&iscsi_transport_lock, flags);
4027 list_add(&priv->list, &iscsi_transports);
4028 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029
Alex Aizman0896b752005-08-04 19:33:07 -07004030 printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
Mike Christie7b8631b2006-01-13 18:05:50 -06004031 return &priv->t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032
Tony Jonesee959b02008-02-22 00:13:36 +01004033unregister_dev:
4034 device_unregister(&priv->dev);
Mike Christied82ff9be2008-05-21 15:54:13 -05004035 return NULL;
Alex Aizman0896b752005-08-04 19:33:07 -07004036free_priv:
4037 kfree(priv);
Mike Christie7b8631b2006-01-13 18:05:50 -06004038 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039}
Alex Aizman0896b752005-08-04 19:33:07 -07004040EXPORT_SYMBOL_GPL(iscsi_register_transport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041
Alex Aizman0896b752005-08-04 19:33:07 -07004042int iscsi_unregister_transport(struct iscsi_transport *tt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043{
Alex Aizman0896b752005-08-04 19:33:07 -07004044 struct iscsi_internal *priv;
4045 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046
Alex Aizman0896b752005-08-04 19:33:07 -07004047 BUG_ON(!tt);
4048
Arjan van de Ven0b950672006-01-11 13:16:10 +01004049 mutex_lock(&rx_queue_mutex);
Alex Aizman0896b752005-08-04 19:33:07 -07004050
4051 priv = iscsi_if_transport_lookup(tt);
4052 BUG_ON (!priv);
4053
Alex Aizman0896b752005-08-04 19:33:07 -07004054 spin_lock_irqsave(&iscsi_transport_lock, flags);
4055 list_del(&priv->list);
4056 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
4057
4058 transport_container_unregister(&priv->conn_cont);
4059 transport_container_unregister(&priv->session_cont);
Mike Christie30a6c652006-04-06 21:13:39 -05004060 transport_container_unregister(&priv->t.host_attrs);
Alex Aizman0896b752005-08-04 19:33:07 -07004061
Tony Jonesee959b02008-02-22 00:13:36 +01004062 sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
4063 device_unregister(&priv->dev);
Arjan van de Ven0b950672006-01-11 13:16:10 +01004064 mutex_unlock(&rx_queue_mutex);
Alex Aizman0896b752005-08-04 19:33:07 -07004065
4066 return 0;
4067}
4068EXPORT_SYMBOL_GPL(iscsi_unregister_transport);
4069
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070static __init int iscsi_transport_init(void)
4071{
Alex Aizman0896b752005-08-04 19:33:07 -07004072 int err;
Pablo Neira Ayusoa31f2d12012-06-29 06:15:21 +00004073 struct netlink_kernel_cfg cfg = {
4074 .groups = 1,
4075 .input = iscsi_if_rx,
4076 };
Meelis Roos09492602006-12-17 12:10:26 -06004077 printk(KERN_INFO "Loading iSCSI transport class v%s.\n",
Mike Christief4246b32006-07-24 15:47:54 -05004078 ISCSI_TRANSPORT_VERSION);
4079
Mike Christie41be1442007-02-28 17:32:18 -06004080 atomic_set(&iscsi_session_nr, 0);
4081
Alex Aizman0896b752005-08-04 19:33:07 -07004082 err = class_register(&iscsi_transport_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 if (err)
4084 return err;
Alex Aizman0896b752005-08-04 19:33:07 -07004085
Mike Christied82ff9be2008-05-21 15:54:13 -05004086 err = class_register(&iscsi_endpoint_class);
Alex Aizman0896b752005-08-04 19:33:07 -07004087 if (err)
4088 goto unregister_transport_class;
4089
Mike Christie8d079132011-07-25 13:48:40 -05004090 err = class_register(&iscsi_iface_class);
Mike Christied82ff9be2008-05-21 15:54:13 -05004091 if (err)
4092 goto unregister_endpoint_class;
4093
Mike Christie8d079132011-07-25 13:48:40 -05004094 err = transport_class_register(&iscsi_host_class);
4095 if (err)
4096 goto unregister_iface_class;
4097
Mike Christie30a6c652006-04-06 21:13:39 -05004098 err = transport_class_register(&iscsi_connection_class);
4099 if (err)
4100 goto unregister_host_class;
4101
Alex Aizman0896b752005-08-04 19:33:07 -07004102 err = transport_class_register(&iscsi_session_class);
4103 if (err)
4104 goto unregister_conn_class;
4105
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04004106 err = bus_register(&iscsi_flashnode_bus);
4107 if (err)
4108 goto unregister_session_class;
4109
Pablo Neira Ayuso9f00d972012-09-08 02:53:54 +00004110 nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, &cfg);
Alex Aizman0896b752005-08-04 19:33:07 -07004111 if (!nls) {
4112 err = -ENOBUFS;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04004113 goto unregister_flashnode_bus;
Alex Aizman0896b752005-08-04 19:33:07 -07004114 }
4115
Mike Christied8bf5412007-12-13 12:43:27 -06004116 iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh");
Wei Yongjunbcab2cc2013-04-19 09:23:28 +08004117 if (!iscsi_eh_timer_workq) {
4118 err = -ENOMEM;
Mike Christied8bf5412007-12-13 12:43:27 -06004119 goto release_nls;
Wei Yongjunbcab2cc2013-04-19 09:23:28 +08004120 }
Mike Christied8bf5412007-12-13 12:43:27 -06004121
Mike Christie43a145a2006-10-16 18:09:38 -04004122 return 0;
Alex Aizman0896b752005-08-04 19:33:07 -07004123
Mike Christied8bf5412007-12-13 12:43:27 -06004124release_nls:
Denis V. Lunevb7c6ba62008-01-28 14:41:19 -08004125 netlink_kernel_release(nls);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04004126unregister_flashnode_bus:
4127 bus_unregister(&iscsi_flashnode_bus);
Alex Aizman0896b752005-08-04 19:33:07 -07004128unregister_session_class:
4129 transport_class_unregister(&iscsi_session_class);
4130unregister_conn_class:
4131 transport_class_unregister(&iscsi_connection_class);
Mike Christie30a6c652006-04-06 21:13:39 -05004132unregister_host_class:
4133 transport_class_unregister(&iscsi_host_class);
Mike Christie8d079132011-07-25 13:48:40 -05004134unregister_iface_class:
4135 class_unregister(&iscsi_iface_class);
Mike Christied82ff9be2008-05-21 15:54:13 -05004136unregister_endpoint_class:
4137 class_unregister(&iscsi_endpoint_class);
Alex Aizman0896b752005-08-04 19:33:07 -07004138unregister_transport_class:
4139 class_unregister(&iscsi_transport_class);
4140 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141}
4142
4143static void __exit iscsi_transport_exit(void)
4144{
Mike Christied8bf5412007-12-13 12:43:27 -06004145 destroy_workqueue(iscsi_eh_timer_workq);
Denis V. Lunevb7c6ba62008-01-28 14:41:19 -08004146 netlink_kernel_release(nls);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04004147 bus_unregister(&iscsi_flashnode_bus);
Alex Aizman0896b752005-08-04 19:33:07 -07004148 transport_class_unregister(&iscsi_connection_class);
4149 transport_class_unregister(&iscsi_session_class);
Mike Christie30a6c652006-04-06 21:13:39 -05004150 transport_class_unregister(&iscsi_host_class);
Mike Christied82ff9be2008-05-21 15:54:13 -05004151 class_unregister(&iscsi_endpoint_class);
Mike Christie8d079132011-07-25 13:48:40 -05004152 class_unregister(&iscsi_iface_class);
Alex Aizman0896b752005-08-04 19:33:07 -07004153 class_unregister(&iscsi_transport_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154}
4155
4156module_init(iscsi_transport_init);
4157module_exit(iscsi_transport_exit);
4158
Alex Aizman0896b752005-08-04 19:33:07 -07004159MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
4160 "Dmitry Yusupov <dmitry_yus@yahoo.com>, "
4161 "Alex Aizman <itn780@yahoo.com>");
4162MODULE_DESCRIPTION("iSCSI Transport Interface");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163MODULE_LICENSE("GPL");
Mike Christief4246b32006-07-24 15:47:54 -05004164MODULE_VERSION(ISCSI_TRANSPORT_VERSION);
Stephen Hemminger058548a2010-12-09 09:37:56 -08004165MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_ISCSI);