blob: 63a6ca49d4e5e8d1b0f53c592943c279bcffcb60 [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
Adheer Chandravanshi3af142f2013-09-17 07:54:48 -04002747static int iscsi_set_chap(struct iscsi_transport *transport,
2748 struct iscsi_uevent *ev, uint32_t len)
2749{
2750 char *data = (char *)ev + sizeof(*ev);
2751 struct Scsi_Host *shost;
2752 int err = 0;
2753
2754 if (!transport->set_chap)
2755 return -ENOSYS;
2756
2757 shost = scsi_host_lookup(ev->u.set_path.host_no);
2758 if (!shost) {
2759 pr_err("%s could not find host no %u\n",
2760 __func__, ev->u.set_path.host_no);
2761 return -ENODEV;
2762 }
2763
2764 err = transport->set_chap(shost, data, len);
2765 scsi_host_put(shost);
2766 return err;
2767}
2768
Nilesh Javali6260a5d2012-02-27 03:08:51 -08002769static int iscsi_delete_chap(struct iscsi_transport *transport,
2770 struct iscsi_uevent *ev)
2771{
2772 struct Scsi_Host *shost;
2773 int err = 0;
2774
2775 if (!transport->delete_chap)
2776 return -ENOSYS;
2777
2778 shost = scsi_host_lookup(ev->u.delete_chap.host_no);
2779 if (!shost) {
2780 printk(KERN_ERR "%s could not find host no %u\n",
2781 __func__, ev->u.delete_chap.host_no);
2782 return -ENODEV;
2783 }
2784
2785 err = transport->delete_chap(shost, ev->u.delete_chap.chap_tbl_idx);
2786 scsi_host_put(shost);
2787 return err;
2788}
2789
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002790static const struct {
2791 enum iscsi_discovery_parent_type value;
2792 char *name;
2793} iscsi_discovery_parent_names[] = {
2794 {ISCSI_DISC_PARENT_UNKNOWN, "Unknown" },
2795 {ISCSI_DISC_PARENT_SENDTGT, "Sendtarget" },
2796 {ISCSI_DISC_PARENT_ISNS, "isns" },
2797};
2798
2799char *iscsi_get_discovery_parent_name(int parent_type)
2800{
2801 int i;
2802 char *state = "Unknown!";
2803
2804 for (i = 0; i < ARRAY_SIZE(iscsi_discovery_parent_names); i++) {
2805 if (iscsi_discovery_parent_names[i].value & parent_type) {
2806 state = iscsi_discovery_parent_names[i].name;
2807 break;
2808 }
2809 }
2810 return state;
2811}
2812EXPORT_SYMBOL_GPL(iscsi_get_discovery_parent_name);
2813
2814static int iscsi_set_flashnode_param(struct iscsi_transport *transport,
2815 struct iscsi_uevent *ev, uint32_t len)
2816{
2817 char *data = (char *)ev + sizeof(*ev);
2818 struct Scsi_Host *shost;
2819 struct iscsi_bus_flash_session *fnode_sess;
2820 struct iscsi_bus_flash_conn *fnode_conn;
2821 struct device *dev;
Mike Christie8526cb12013-05-06 12:06:56 -05002822 uint32_t idx;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002823 int err = 0;
2824
2825 if (!transport->set_flashnode_param) {
2826 err = -ENOSYS;
2827 goto exit_set_fnode;
2828 }
2829
2830 shost = scsi_host_lookup(ev->u.set_flashnode.host_no);
2831 if (!shost) {
2832 pr_err("%s could not find host no %u\n",
2833 __func__, ev->u.set_flashnode.host_no);
2834 err = -ENODEV;
2835 goto put_host;
2836 }
2837
Mike Christie8526cb12013-05-06 12:06:56 -05002838 idx = ev->u.set_flashnode.flashnode_idx;
2839 fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002840 if (!fnode_sess) {
2841 pr_err("%s could not find flashnode %u for host no %u\n",
Mike Christie8526cb12013-05-06 12:06:56 -05002842 __func__, idx, ev->u.set_flashnode.host_no);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002843 err = -ENODEV;
2844 goto put_host;
2845 }
2846
Mike Christie8526cb12013-05-06 12:06:56 -05002847 dev = iscsi_find_flashnode_conn(fnode_sess);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002848 if (!dev) {
2849 err = -ENODEV;
Mike Christie8526cb12013-05-06 12:06:56 -05002850 goto put_sess;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002851 }
2852
2853 fnode_conn = iscsi_dev_to_flash_conn(dev);
2854 err = transport->set_flashnode_param(fnode_sess, fnode_conn, data, len);
Mike Christie8526cb12013-05-06 12:06:56 -05002855 put_device(dev);
2856
2857put_sess:
2858 put_device(&fnode_sess->dev);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002859
2860put_host:
2861 scsi_host_put(shost);
2862
2863exit_set_fnode:
2864 return err;
2865}
2866
2867static int iscsi_new_flashnode(struct iscsi_transport *transport,
2868 struct iscsi_uevent *ev, uint32_t len)
2869{
2870 char *data = (char *)ev + sizeof(*ev);
2871 struct Scsi_Host *shost;
2872 int index;
2873 int err = 0;
2874
2875 if (!transport->new_flashnode) {
2876 err = -ENOSYS;
2877 goto exit_new_fnode;
2878 }
2879
2880 shost = scsi_host_lookup(ev->u.new_flashnode.host_no);
2881 if (!shost) {
2882 pr_err("%s could not find host no %u\n",
2883 __func__, ev->u.new_flashnode.host_no);
2884 err = -ENODEV;
2885 goto put_host;
2886 }
2887
2888 index = transport->new_flashnode(shost, data, len);
2889
2890 if (index >= 0)
2891 ev->r.new_flashnode_ret.flashnode_idx = index;
2892 else
2893 err = -EIO;
2894
2895put_host:
2896 scsi_host_put(shost);
2897
2898exit_new_fnode:
2899 return err;
2900}
2901
2902static int iscsi_del_flashnode(struct iscsi_transport *transport,
2903 struct iscsi_uevent *ev)
2904{
2905 struct Scsi_Host *shost;
2906 struct iscsi_bus_flash_session *fnode_sess;
Mike Christie8526cb12013-05-06 12:06:56 -05002907 uint32_t idx;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002908 int err = 0;
2909
2910 if (!transport->del_flashnode) {
2911 err = -ENOSYS;
2912 goto exit_del_fnode;
2913 }
2914
2915 shost = scsi_host_lookup(ev->u.del_flashnode.host_no);
2916 if (!shost) {
2917 pr_err("%s could not find host no %u\n",
2918 __func__, ev->u.del_flashnode.host_no);
2919 err = -ENODEV;
2920 goto put_host;
2921 }
2922
Mike Christie8526cb12013-05-06 12:06:56 -05002923 idx = ev->u.del_flashnode.flashnode_idx;
2924 fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002925 if (!fnode_sess) {
2926 pr_err("%s could not find flashnode %u for host no %u\n",
Mike Christie8526cb12013-05-06 12:06:56 -05002927 __func__, idx, ev->u.del_flashnode.host_no);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002928 err = -ENODEV;
2929 goto put_host;
2930 }
2931
2932 err = transport->del_flashnode(fnode_sess);
Mike Christie8526cb12013-05-06 12:06:56 -05002933 put_device(&fnode_sess->dev);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002934
2935put_host:
2936 scsi_host_put(shost);
2937
2938exit_del_fnode:
2939 return err;
2940}
2941
2942static int iscsi_login_flashnode(struct iscsi_transport *transport,
2943 struct iscsi_uevent *ev)
2944{
2945 struct Scsi_Host *shost;
2946 struct iscsi_bus_flash_session *fnode_sess;
2947 struct iscsi_bus_flash_conn *fnode_conn;
2948 struct device *dev;
Mike Christie8526cb12013-05-06 12:06:56 -05002949 uint32_t idx;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002950 int err = 0;
2951
2952 if (!transport->login_flashnode) {
2953 err = -ENOSYS;
2954 goto exit_login_fnode;
2955 }
2956
2957 shost = scsi_host_lookup(ev->u.login_flashnode.host_no);
2958 if (!shost) {
2959 pr_err("%s could not find host no %u\n",
2960 __func__, ev->u.login_flashnode.host_no);
2961 err = -ENODEV;
2962 goto put_host;
2963 }
2964
Mike Christie8526cb12013-05-06 12:06:56 -05002965 idx = ev->u.login_flashnode.flashnode_idx;
2966 fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002967 if (!fnode_sess) {
2968 pr_err("%s could not find flashnode %u for host no %u\n",
Mike Christie8526cb12013-05-06 12:06:56 -05002969 __func__, idx, ev->u.login_flashnode.host_no);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002970 err = -ENODEV;
2971 goto put_host;
2972 }
2973
Mike Christie8526cb12013-05-06 12:06:56 -05002974 dev = iscsi_find_flashnode_conn(fnode_sess);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002975 if (!dev) {
2976 err = -ENODEV;
Mike Christie8526cb12013-05-06 12:06:56 -05002977 goto put_sess;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002978 }
2979
2980 fnode_conn = iscsi_dev_to_flash_conn(dev);
2981 err = transport->login_flashnode(fnode_sess, fnode_conn);
Mike Christie8526cb12013-05-06 12:06:56 -05002982 put_device(dev);
2983
2984put_sess:
2985 put_device(&fnode_sess->dev);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04002986
2987put_host:
2988 scsi_host_put(shost);
2989
2990exit_login_fnode:
2991 return err;
2992}
2993
2994static int iscsi_logout_flashnode(struct iscsi_transport *transport,
2995 struct iscsi_uevent *ev)
2996{
2997 struct Scsi_Host *shost;
2998 struct iscsi_bus_flash_session *fnode_sess;
2999 struct iscsi_bus_flash_conn *fnode_conn;
3000 struct device *dev;
Mike Christie8526cb12013-05-06 12:06:56 -05003001 uint32_t idx;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04003002 int err = 0;
3003
3004 if (!transport->logout_flashnode) {
3005 err = -ENOSYS;
3006 goto exit_logout_fnode;
3007 }
3008
3009 shost = scsi_host_lookup(ev->u.logout_flashnode.host_no);
3010 if (!shost) {
3011 pr_err("%s could not find host no %u\n",
3012 __func__, ev->u.logout_flashnode.host_no);
3013 err = -ENODEV;
3014 goto put_host;
3015 }
3016
Mike Christie8526cb12013-05-06 12:06:56 -05003017 idx = ev->u.logout_flashnode.flashnode_idx;
3018 fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04003019 if (!fnode_sess) {
3020 pr_err("%s could not find flashnode %u for host no %u\n",
Mike Christie8526cb12013-05-06 12:06:56 -05003021 __func__, idx, ev->u.logout_flashnode.host_no);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04003022 err = -ENODEV;
3023 goto put_host;
3024 }
3025
Mike Christie8526cb12013-05-06 12:06:56 -05003026 dev = iscsi_find_flashnode_conn(fnode_sess);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04003027 if (!dev) {
3028 err = -ENODEV;
Mike Christie8526cb12013-05-06 12:06:56 -05003029 goto put_sess;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04003030 }
3031
3032 fnode_conn = iscsi_dev_to_flash_conn(dev);
3033
3034 err = transport->logout_flashnode(fnode_sess, fnode_conn);
Mike Christie8526cb12013-05-06 12:06:56 -05003035 put_device(dev);
3036
3037put_sess:
3038 put_device(&fnode_sess->dev);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04003039
3040put_host:
3041 scsi_host_put(shost);
3042
3043exit_logout_fnode:
3044 return err;
3045}
3046
3047static int iscsi_logout_flashnode_sid(struct iscsi_transport *transport,
3048 struct iscsi_uevent *ev)
3049{
3050 struct Scsi_Host *shost;
3051 struct iscsi_cls_session *session;
3052 int err = 0;
3053
3054 if (!transport->logout_flashnode_sid) {
3055 err = -ENOSYS;
3056 goto exit_logout_sid;
3057 }
3058
3059 shost = scsi_host_lookup(ev->u.logout_flashnode_sid.host_no);
3060 if (!shost) {
3061 pr_err("%s could not find host no %u\n",
3062 __func__, ev->u.logout_flashnode.host_no);
3063 err = -ENODEV;
3064 goto put_host;
3065 }
3066
3067 session = iscsi_session_lookup(ev->u.logout_flashnode_sid.sid);
3068 if (!session) {
3069 pr_err("%s could not find session id %u\n",
3070 __func__, ev->u.logout_flashnode_sid.sid);
3071 err = -EINVAL;
3072 goto put_host;
3073 }
3074
3075 err = transport->logout_flashnode_sid(session);
3076
3077put_host:
3078 scsi_host_put(shost);
3079
3080exit_logout_sid:
3081 return err;
3082}
3083
Nilesh Javali6260a5d2012-02-27 03:08:51 -08003084static int
Michael Chan43514772009-06-08 18:14:41 -07003085iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
Alex Aizman0896b752005-08-04 19:33:07 -07003086{
3087 int err = 0;
Hong zhi guoe07ebea2013-03-27 06:53:15 +00003088 struct iscsi_uevent *ev = nlmsg_data(nlh);
Alex Aizman0896b752005-08-04 19:33:07 -07003089 struct iscsi_transport *transport = NULL;
3090 struct iscsi_internal *priv;
Mike Christie7b7232f2006-02-01 21:06:49 -06003091 struct iscsi_cls_session *session;
3092 struct iscsi_cls_conn *conn;
Mike Christied82ff9be2008-05-21 15:54:13 -05003093 struct iscsi_endpoint *ep = NULL;
Alex Aizman0896b752005-08-04 19:33:07 -07003094
Michael Chan43514772009-06-08 18:14:41 -07003095 if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE)
3096 *group = ISCSI_NL_GRP_UIP;
3097 else
3098 *group = ISCSI_NL_GRP_ISCSID;
3099
Alex Aizman0896b752005-08-04 19:33:07 -07003100 priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
3101 if (!priv)
3102 return -EINVAL;
3103 transport = priv->iscsi_transport;
3104
Mike Christie7b7232f2006-02-01 21:06:49 -06003105 if (!try_module_get(transport->owner))
3106 return -EINVAL;
3107
Alex Aizman0896b752005-08-04 19:33:07 -07003108 switch (nlh->nlmsg_type) {
3109 case ISCSI_UEVENT_CREATE_SESSION:
Mike Christied82ff9be2008-05-21 15:54:13 -05003110 err = iscsi_if_create_session(priv, ep, ev,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003111 NETLINK_CB(skb).portid,
Mike Christie40753ca2008-05-21 15:53:56 -05003112 ev->u.c_session.initial_cmdsn,
3113 ev->u.c_session.cmds_max,
3114 ev->u.c_session.queue_depth);
3115 break;
3116 case ISCSI_UEVENT_CREATE_BOUND_SESSION:
Mike Christied82ff9be2008-05-21 15:54:13 -05003117 ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
Mike Christiec95fddc2008-06-16 10:11:32 -05003118 if (!ep) {
3119 err = -EINVAL;
3120 break;
3121 }
Mike Christied82ff9be2008-05-21 15:54:13 -05003122
3123 err = iscsi_if_create_session(priv, ep, ev,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003124 NETLINK_CB(skb).portid,
Mike Christie40753ca2008-05-21 15:53:56 -05003125 ev->u.c_bound_session.initial_cmdsn,
3126 ev->u.c_bound_session.cmds_max,
3127 ev->u.c_bound_session.queue_depth);
Alex Aizman0896b752005-08-04 19:33:07 -07003128 break;
3129 case ISCSI_UEVENT_DESTROY_SESSION:
Mike Christieb5c7a122006-04-06 21:13:33 -05003130 session = iscsi_session_lookup(ev->u.d_session.sid);
Mike Christie26974782007-12-13 12:43:29 -06003131 if (session)
Mike Christie7b7232f2006-02-01 21:06:49 -06003132 transport->destroy_session(session);
Mike Christie26974782007-12-13 12:43:29 -06003133 else
3134 err = -EINVAL;
3135 break;
3136 case ISCSI_UEVENT_UNBIND_SESSION:
3137 session = iscsi_session_lookup(ev->u.d_session.sid);
3138 if (session)
Mike Christie06d25af2009-03-05 14:46:02 -06003139 scsi_queue_work(iscsi_session_to_shost(session),
3140 &session->unbind_work);
Mike Christie26974782007-12-13 12:43:29 -06003141 else
Mike Christie7b7232f2006-02-01 21:06:49 -06003142 err = -EINVAL;
Alex Aizman0896b752005-08-04 19:33:07 -07003143 break;
3144 case ISCSI_UEVENT_CREATE_CONN:
3145 err = iscsi_if_create_conn(transport, ev);
3146 break;
3147 case ISCSI_UEVENT_DESTROY_CONN:
3148 err = iscsi_if_destroy_conn(transport, ev);
3149 break;
3150 case ISCSI_UEVENT_BIND_CONN:
Mike Christieb5c7a122006-04-06 21:13:33 -05003151 session = iscsi_session_lookup(ev->u.b_conn.sid);
3152 conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid);
Mike Christie7b7232f2006-02-01 21:06:49 -06003153
Mike Christie22a39fb2011-02-16 15:04:33 -06003154 if (conn && conn->ep)
3155 iscsi_if_ep_disconnect(transport, conn->ep->id);
3156
3157 if (!session || !conn) {
Mike Christie7b7232f2006-02-01 21:06:49 -06003158 err = -EINVAL;
Mike Christie22a39fb2011-02-16 15:04:33 -06003159 break;
3160 }
3161
3162 ev->r.retcode = transport->bind_conn(session, conn,
3163 ev->u.b_conn.transport_eph,
3164 ev->u.b_conn.is_leading);
3165 if (ev->r.retcode || !transport->ep_connect)
3166 break;
3167
3168 ep = iscsi_lookup_endpoint(ev->u.b_conn.transport_eph);
3169 if (ep) {
3170 ep->conn = conn;
3171
3172 mutex_lock(&conn->ep_mutex);
3173 conn->ep = ep;
3174 mutex_unlock(&conn->ep_mutex);
3175 } else
3176 iscsi_cls_conn_printk(KERN_ERR, conn,
3177 "Could not set ep conn "
3178 "binding\n");
Alex Aizman0896b752005-08-04 19:33:07 -07003179 break;
3180 case ISCSI_UEVENT_SET_PARAM:
Mike Christiefd7255f2006-04-06 21:13:36 -05003181 err = iscsi_set_param(transport, ev);
Alex Aizman0896b752005-08-04 19:33:07 -07003182 break;
3183 case ISCSI_UEVENT_START_CONN:
Mike Christieb5c7a122006-04-06 21:13:33 -05003184 conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid);
Mike Christie7b7232f2006-02-01 21:06:49 -06003185 if (conn)
3186 ev->r.retcode = transport->start_conn(conn);
3187 else
3188 err = -EINVAL;
Alex Aizman0896b752005-08-04 19:33:07 -07003189 break;
3190 case ISCSI_UEVENT_STOP_CONN:
Mike Christieb5c7a122006-04-06 21:13:33 -05003191 conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid);
Mike Christie7b7232f2006-02-01 21:06:49 -06003192 if (conn)
3193 transport->stop_conn(conn, ev->u.stop_conn.flag);
3194 else
3195 err = -EINVAL;
Alex Aizman0896b752005-08-04 19:33:07 -07003196 break;
3197 case ISCSI_UEVENT_SEND_PDU:
Mike Christieb5c7a122006-04-06 21:13:33 -05003198 conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid);
Mike Christie7b7232f2006-02-01 21:06:49 -06003199 if (conn)
3200 ev->r.retcode = transport->send_pdu(conn,
3201 (struct iscsi_hdr*)((char*)ev + sizeof(*ev)),
3202 (char*)ev + sizeof(*ev) + ev->u.send_pdu.hdr_size,
3203 ev->u.send_pdu.data_size);
3204 else
3205 err = -EINVAL;
Alex Aizman0896b752005-08-04 19:33:07 -07003206 break;
3207 case ISCSI_UEVENT_GET_STATS:
Mike Christie5b940ad2006-02-01 21:06:56 -06003208 err = iscsi_if_get_stats(transport, nlh);
Alex Aizman0896b752005-08-04 19:33:07 -07003209 break;
Or Gerlitz264faaa2006-05-02 19:46:36 -05003210 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
3211 case ISCSI_UEVENT_TRANSPORT_EP_POLL:
3212 case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
Mike Christie10eb0f02009-05-13 17:57:38 -05003213 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
Or Gerlitz264faaa2006-05-02 19:46:36 -05003214 err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
3215 break;
Mike Christie01cb2252006-06-28 12:00:22 -05003216 case ISCSI_UEVENT_TGT_DSCVR:
3217 err = iscsi_tgt_dscvr(transport, ev);
3218 break;
Mike Christie1d9bf132007-05-30 12:57:11 -05003219 case ISCSI_UEVENT_SET_HOST_PARAM:
3220 err = iscsi_set_host_param(transport, ev);
3221 break;
Michael Chan43514772009-06-08 18:14:41 -07003222 case ISCSI_UEVENT_PATH_UPDATE:
3223 err = iscsi_set_path(transport, ev);
3224 break;
Mike Christie56c155b2011-07-25 13:48:37 -05003225 case ISCSI_UEVENT_SET_IFACE_PARAMS:
Mike Christie00c31882011-10-06 03:56:59 -05003226 err = iscsi_set_iface_params(transport, ev,
3227 nlmsg_attrlen(nlh, sizeof(*ev)));
Mike Christie56c155b2011-07-25 13:48:37 -05003228 break;
Vikas Chaudharyac20c7b2012-02-13 18:30:48 +05303229 case ISCSI_UEVENT_PING:
3230 err = iscsi_send_ping(transport, ev);
3231 break;
Nilesh Javali6260a5d2012-02-27 03:08:51 -08003232 case ISCSI_UEVENT_GET_CHAP:
3233 err = iscsi_get_chap(transport, nlh);
3234 break;
3235 case ISCSI_UEVENT_DELETE_CHAP:
3236 err = iscsi_delete_chap(transport, ev);
3237 break;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04003238 case ISCSI_UEVENT_SET_FLASHNODE_PARAMS:
3239 err = iscsi_set_flashnode_param(transport, ev,
3240 nlmsg_attrlen(nlh,
3241 sizeof(*ev)));
3242 break;
3243 case ISCSI_UEVENT_NEW_FLASHNODE:
3244 err = iscsi_new_flashnode(transport, ev,
3245 nlmsg_attrlen(nlh, sizeof(*ev)));
3246 break;
3247 case ISCSI_UEVENT_DEL_FLASHNODE:
3248 err = iscsi_del_flashnode(transport, ev);
3249 break;
3250 case ISCSI_UEVENT_LOGIN_FLASHNODE:
3251 err = iscsi_login_flashnode(transport, ev);
3252 break;
3253 case ISCSI_UEVENT_LOGOUT_FLASHNODE:
3254 err = iscsi_logout_flashnode(transport, ev);
3255 break;
3256 case ISCSI_UEVENT_LOGOUT_FLASHNODE_SID:
3257 err = iscsi_logout_flashnode_sid(transport, ev);
3258 break;
Adheer Chandravanshi3af142f2013-09-17 07:54:48 -04003259 case ISCSI_UEVENT_SET_CHAP:
3260 err = iscsi_set_chap(transport, ev,
3261 nlmsg_attrlen(nlh, sizeof(*ev)));
3262 break;
Alex Aizman0896b752005-08-04 19:33:07 -07003263 default:
Mike Christie1d9bf132007-05-30 12:57:11 -05003264 err = -ENOSYS;
Alex Aizman0896b752005-08-04 19:33:07 -07003265 break;
3266 }
3267
Mike Christie7b7232f2006-02-01 21:06:49 -06003268 module_put(transport->owner);
Alex Aizman0896b752005-08-04 19:33:07 -07003269 return err;
3270}
3271
Mike Christieb5c7a122006-04-06 21:13:33 -05003272/*
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003273 * Get message from skb. Each message is processed by iscsi_if_recv_msg.
3274 * Malformed skbs with wrong lengths or invalid creds are not processed.
Mike Christieb5c7a122006-04-06 21:13:33 -05003275 */
Alex Aizman0896b752005-08-04 19:33:07 -07003276static void
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003277iscsi_if_rx(struct sk_buff *skb)
Alex Aizman0896b752005-08-04 19:33:07 -07003278{
Arjan van de Ven0b950672006-01-11 13:16:10 +01003279 mutex_lock(&rx_queue_mutex);
Hong zhi guoe07ebea2013-03-27 06:53:15 +00003280 while (skb->len >= NLMSG_HDRLEN) {
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003281 int err;
3282 uint32_t rlen;
3283 struct nlmsghdr *nlh;
3284 struct iscsi_uevent *ev;
Michael Chan43514772009-06-08 18:14:41 -07003285 uint32_t group;
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003286
3287 nlh = nlmsg_hdr(skb);
3288 if (nlh->nlmsg_len < sizeof(*nlh) ||
3289 skb->len < nlh->nlmsg_len) {
3290 break;
Mike Christieee7f8e42006-02-01 21:07:01 -06003291 }
Mike Christieee7f8e42006-02-01 21:07:01 -06003292
Hong zhi guoe07ebea2013-03-27 06:53:15 +00003293 ev = nlmsg_data(nlh);
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003294 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
3295 if (rlen > skb->len)
3296 rlen = skb->len;
Alex Aizman0896b752005-08-04 19:33:07 -07003297
Michael Chan43514772009-06-08 18:14:41 -07003298 err = iscsi_if_recv_msg(skb, nlh, &group);
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003299 if (err) {
3300 ev->type = ISCSI_KEVENT_IF_ERROR;
3301 ev->iferror = err;
3302 }
3303 do {
3304 /*
3305 * special case for GET_STATS:
3306 * on success - sending reply and stats from
3307 * inside of if_recv_msg(),
3308 * on error - fall through.
3309 */
3310 if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
Alex Aizman0896b752005-08-04 19:33:07 -07003311 break;
Nilesh Javali6260a5d2012-02-27 03:08:51 -08003312 if (ev->type == ISCSI_UEVENT_GET_CHAP && !err)
3313 break;
Michael Chan43514772009-06-08 18:14:41 -07003314 err = iscsi_if_send_reply(group, nlh->nlmsg_seq,
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003315 nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
Sasha Levin46a7c172012-01-25 22:16:16 -05003316 } while (err < 0 && err != -ECONNREFUSED && err != -ESRCH);
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07003317 skb_pull(skb, rlen);
Alex Aizman0896b752005-08-04 19:33:07 -07003318 }
Arjan van de Ven0b950672006-01-11 13:16:10 +01003319 mutex_unlock(&rx_queue_mutex);
Alex Aizman0896b752005-08-04 19:33:07 -07003320}
3321
Mike Christiefd7255f2006-04-06 21:13:36 -05003322#define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \
Tony Jonesee959b02008-02-22 00:13:36 +01003323struct device_attribute dev_attr_##_prefix##_##_name = \
Mike Christiefd7255f2006-04-06 21:13:36 -05003324 __ATTR(_name,_mode,_show,_store)
3325
Alex Aizman0896b752005-08-04 19:33:07 -07003326/*
3327 * iSCSI connection attrs
3328 */
Mike Christiea54a52c2006-06-28 12:00:23 -05003329#define iscsi_conn_attr_show(param) \
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01003331show_conn_param_##param(struct device *dev, \
3332 struct device_attribute *attr, char *buf) \
Mike Christiefd7255f2006-04-06 21:13:36 -05003333{ \
Tony Jonesee959b02008-02-22 00:13:36 +01003334 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
Mike Christiefd7255f2006-04-06 21:13:36 -05003335 struct iscsi_transport *t = conn->transport; \
Mike Christiea54a52c2006-06-28 12:00:23 -05003336 return t->get_conn_param(conn, param, buf); \
Mike Christiefd7255f2006-04-06 21:13:36 -05003337}
3338
Mike Christiea54a52c2006-06-28 12:00:23 -05003339#define iscsi_conn_attr(field, param) \
3340 iscsi_conn_attr_show(param) \
3341static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_param_##param, \
Mike Christiefd7255f2006-04-06 21:13:36 -05003342 NULL);
3343
Mike Christiea54a52c2006-06-28 12:00:23 -05003344iscsi_conn_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH);
3345iscsi_conn_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH);
3346iscsi_conn_attr(header_digest, ISCSI_PARAM_HDRDGST_EN);
3347iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN);
3348iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN);
3349iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN);
3350iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT);
Mike Christiea54a52c2006-06-28 12:00:23 -05003351iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
3352iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
Mike Christief6d51802007-12-13 12:43:30 -06003353iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
3354iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
Adheer Chandravanshiae542ed2013-07-01 05:54:11 -04003355iscsi_conn_attr(local_port, ISCSI_PARAM_LOCAL_PORT);
3356iscsi_conn_attr(statsn, ISCSI_PARAM_STATSN);
3357iscsi_conn_attr(keepalive_tmo, ISCSI_PARAM_KEEPALIVE_TMO);
3358iscsi_conn_attr(max_segment_size, ISCSI_PARAM_MAX_SEGMENT_SIZE);
3359iscsi_conn_attr(tcp_timestamp_stat, ISCSI_PARAM_TCP_TIMESTAMP_STAT);
3360iscsi_conn_attr(tcp_wsf_disable, ISCSI_PARAM_TCP_WSF_DISABLE);
3361iscsi_conn_attr(tcp_nagle_disable, ISCSI_PARAM_TCP_NAGLE_DISABLE);
3362iscsi_conn_attr(tcp_timer_scale, ISCSI_PARAM_TCP_TIMER_SCALE);
3363iscsi_conn_attr(tcp_timestamp_enable, ISCSI_PARAM_TCP_TIMESTAMP_EN);
3364iscsi_conn_attr(fragment_disable, ISCSI_PARAM_IP_FRAGMENT_DISABLE);
3365iscsi_conn_attr(ipv4_tos, ISCSI_PARAM_IPV4_TOS);
3366iscsi_conn_attr(ipv6_traffic_class, ISCSI_PARAM_IPV6_TC);
3367iscsi_conn_attr(ipv6_flow_label, ISCSI_PARAM_IPV6_FLOW_LABEL);
3368iscsi_conn_attr(is_fw_assigned_ipv6, ISCSI_PARAM_IS_FW_ASSIGNED_IPV6);
3369iscsi_conn_attr(tcp_xmit_wsf, ISCSI_PARAM_TCP_XMIT_WSF);
3370iscsi_conn_attr(tcp_recv_wsf, ISCSI_PARAM_TCP_RECV_WSF);
3371
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372
Mike Christie289324b2011-02-16 15:04:37 -06003373#define iscsi_conn_ep_attr_show(param) \
3374static ssize_t show_conn_ep_param_##param(struct device *dev, \
3375 struct device_attribute *attr,\
3376 char *buf) \
3377{ \
3378 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
3379 struct iscsi_transport *t = conn->transport; \
3380 struct iscsi_endpoint *ep; \
3381 ssize_t rc; \
3382 \
3383 /* \
3384 * Need to make sure ep_disconnect does not free the LLD's \
3385 * interconnect resources while we are trying to read them. \
3386 */ \
3387 mutex_lock(&conn->ep_mutex); \
3388 ep = conn->ep; \
3389 if (!ep && t->ep_connect) { \
3390 mutex_unlock(&conn->ep_mutex); \
3391 return -ENOTCONN; \
3392 } \
3393 \
3394 if (ep) \
3395 rc = t->get_ep_param(ep, param, buf); \
3396 else \
3397 rc = t->get_conn_param(conn, param, buf); \
3398 mutex_unlock(&conn->ep_mutex); \
3399 return rc; \
3400}
3401
3402#define iscsi_conn_ep_attr(field, param) \
3403 iscsi_conn_ep_attr_show(param) \
3404static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, \
3405 show_conn_ep_param_##param, NULL);
3406
3407iscsi_conn_ep_attr(address, ISCSI_PARAM_CONN_ADDRESS);
3408iscsi_conn_ep_attr(port, ISCSI_PARAM_CONN_PORT);
3409
Mike Christie3128c6c2011-07-25 13:48:42 -05003410static struct attribute *iscsi_conn_attrs[] = {
3411 &dev_attr_conn_max_recv_dlength.attr,
3412 &dev_attr_conn_max_xmit_dlength.attr,
3413 &dev_attr_conn_header_digest.attr,
3414 &dev_attr_conn_data_digest.attr,
3415 &dev_attr_conn_ifmarker.attr,
3416 &dev_attr_conn_ofmarker.attr,
3417 &dev_attr_conn_address.attr,
3418 &dev_attr_conn_port.attr,
3419 &dev_attr_conn_exp_statsn.attr,
3420 &dev_attr_conn_persistent_address.attr,
3421 &dev_attr_conn_persistent_port.attr,
3422 &dev_attr_conn_ping_tmo.attr,
3423 &dev_attr_conn_recv_tmo.attr,
Adheer Chandravanshiae542ed2013-07-01 05:54:11 -04003424 &dev_attr_conn_local_port.attr,
3425 &dev_attr_conn_statsn.attr,
3426 &dev_attr_conn_keepalive_tmo.attr,
3427 &dev_attr_conn_max_segment_size.attr,
3428 &dev_attr_conn_tcp_timestamp_stat.attr,
3429 &dev_attr_conn_tcp_wsf_disable.attr,
3430 &dev_attr_conn_tcp_nagle_disable.attr,
3431 &dev_attr_conn_tcp_timer_scale.attr,
3432 &dev_attr_conn_tcp_timestamp_enable.attr,
3433 &dev_attr_conn_fragment_disable.attr,
3434 &dev_attr_conn_ipv4_tos.attr,
3435 &dev_attr_conn_ipv6_traffic_class.attr,
3436 &dev_attr_conn_ipv6_flow_label.attr,
3437 &dev_attr_conn_is_fw_assigned_ipv6.attr,
3438 &dev_attr_conn_tcp_xmit_wsf.attr,
3439 &dev_attr_conn_tcp_recv_wsf.attr,
Mike Christie3128c6c2011-07-25 13:48:42 -05003440 NULL,
3441};
3442
Al Viro587a1f12011-07-23 23:11:19 -04003443static umode_t iscsi_conn_attr_is_visible(struct kobject *kobj,
Mike Christie3128c6c2011-07-25 13:48:42 -05003444 struct attribute *attr, int i)
3445{
3446 struct device *cdev = container_of(kobj, struct device, kobj);
3447 struct iscsi_cls_conn *conn = transport_class_to_conn(cdev);
3448 struct iscsi_transport *t = conn->transport;
3449 int param;
3450
3451 if (attr == &dev_attr_conn_max_recv_dlength.attr)
3452 param = ISCSI_PARAM_MAX_RECV_DLENGTH;
3453 else if (attr == &dev_attr_conn_max_xmit_dlength.attr)
3454 param = ISCSI_PARAM_MAX_XMIT_DLENGTH;
3455 else if (attr == &dev_attr_conn_header_digest.attr)
3456 param = ISCSI_PARAM_HDRDGST_EN;
3457 else if (attr == &dev_attr_conn_data_digest.attr)
3458 param = ISCSI_PARAM_DATADGST_EN;
3459 else if (attr == &dev_attr_conn_ifmarker.attr)
3460 param = ISCSI_PARAM_IFMARKER_EN;
3461 else if (attr == &dev_attr_conn_ofmarker.attr)
3462 param = ISCSI_PARAM_OFMARKER_EN;
3463 else if (attr == &dev_attr_conn_address.attr)
3464 param = ISCSI_PARAM_CONN_ADDRESS;
3465 else if (attr == &dev_attr_conn_port.attr)
3466 param = ISCSI_PARAM_CONN_PORT;
3467 else if (attr == &dev_attr_conn_exp_statsn.attr)
3468 param = ISCSI_PARAM_EXP_STATSN;
3469 else if (attr == &dev_attr_conn_persistent_address.attr)
3470 param = ISCSI_PARAM_PERSISTENT_ADDRESS;
3471 else if (attr == &dev_attr_conn_persistent_port.attr)
3472 param = ISCSI_PARAM_PERSISTENT_PORT;
3473 else if (attr == &dev_attr_conn_ping_tmo.attr)
3474 param = ISCSI_PARAM_PING_TMO;
3475 else if (attr == &dev_attr_conn_recv_tmo.attr)
3476 param = ISCSI_PARAM_RECV_TMO;
Adheer Chandravanshiae542ed2013-07-01 05:54:11 -04003477 else if (attr == &dev_attr_conn_local_port.attr)
3478 param = ISCSI_PARAM_LOCAL_PORT;
3479 else if (attr == &dev_attr_conn_statsn.attr)
3480 param = ISCSI_PARAM_STATSN;
3481 else if (attr == &dev_attr_conn_keepalive_tmo.attr)
3482 param = ISCSI_PARAM_KEEPALIVE_TMO;
3483 else if (attr == &dev_attr_conn_max_segment_size.attr)
3484 param = ISCSI_PARAM_MAX_SEGMENT_SIZE;
3485 else if (attr == &dev_attr_conn_tcp_timestamp_stat.attr)
3486 param = ISCSI_PARAM_TCP_TIMESTAMP_STAT;
3487 else if (attr == &dev_attr_conn_tcp_wsf_disable.attr)
3488 param = ISCSI_PARAM_TCP_WSF_DISABLE;
3489 else if (attr == &dev_attr_conn_tcp_nagle_disable.attr)
3490 param = ISCSI_PARAM_TCP_NAGLE_DISABLE;
3491 else if (attr == &dev_attr_conn_tcp_timer_scale.attr)
3492 param = ISCSI_PARAM_TCP_TIMER_SCALE;
3493 else if (attr == &dev_attr_conn_tcp_timestamp_enable.attr)
3494 param = ISCSI_PARAM_TCP_TIMESTAMP_EN;
3495 else if (attr == &dev_attr_conn_fragment_disable.attr)
3496 param = ISCSI_PARAM_IP_FRAGMENT_DISABLE;
3497 else if (attr == &dev_attr_conn_ipv4_tos.attr)
3498 param = ISCSI_PARAM_IPV4_TOS;
3499 else if (attr == &dev_attr_conn_ipv6_traffic_class.attr)
3500 param = ISCSI_PARAM_IPV6_TC;
3501 else if (attr == &dev_attr_conn_ipv6_flow_label.attr)
3502 param = ISCSI_PARAM_IPV6_FLOW_LABEL;
3503 else if (attr == &dev_attr_conn_is_fw_assigned_ipv6.attr)
3504 param = ISCSI_PARAM_IS_FW_ASSIGNED_IPV6;
3505 else if (attr == &dev_attr_conn_tcp_xmit_wsf.attr)
3506 param = ISCSI_PARAM_TCP_XMIT_WSF;
3507 else if (attr == &dev_attr_conn_tcp_recv_wsf.attr)
3508 param = ISCSI_PARAM_TCP_RECV_WSF;
Mike Christie3128c6c2011-07-25 13:48:42 -05003509 else {
3510 WARN_ONCE(1, "Invalid conn attr");
3511 return 0;
3512 }
3513
3514 return t->attr_is_visible(ISCSI_PARAM, param);
3515}
3516
3517static struct attribute_group iscsi_conn_group = {
3518 .attrs = iscsi_conn_attrs,
3519 .is_visible = iscsi_conn_attr_is_visible,
3520};
3521
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522/*
Alex Aizman0896b752005-08-04 19:33:07 -07003523 * iSCSI session attrs
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 */
Mike Christieb2c64162007-05-30 12:57:16 -05003525#define iscsi_session_attr_show(param, perm) \
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01003527show_session_param_##param(struct device *dev, \
3528 struct device_attribute *attr, char *buf) \
Mike Christiefd7255f2006-04-06 21:13:36 -05003529{ \
Tony Jonesee959b02008-02-22 00:13:36 +01003530 struct iscsi_cls_session *session = \
3531 iscsi_dev_to_session(dev->parent); \
Mike Christiefd7255f2006-04-06 21:13:36 -05003532 struct iscsi_transport *t = session->transport; \
Mike Christieb2c64162007-05-30 12:57:16 -05003533 \
3534 if (perm && !capable(CAP_SYS_ADMIN)) \
3535 return -EACCES; \
Mike Christiea54a52c2006-06-28 12:00:23 -05003536 return t->get_session_param(session, param, buf); \
Mike Christiefd7255f2006-04-06 21:13:36 -05003537}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538
Mike Christieb2c64162007-05-30 12:57:16 -05003539#define iscsi_session_attr(field, param, perm) \
3540 iscsi_session_attr_show(param, perm) \
Mike Christiea54a52c2006-06-28 12:00:23 -05003541static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \
Mike Christiefd7255f2006-04-06 21:13:36 -05003542 NULL);
Mike Christieb2c64162007-05-30 12:57:16 -05003543iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME, 0);
3544iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, 0);
3545iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, 0);
3546iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, 0);
3547iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, 0);
3548iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, 0);
3549iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, 0);
3550iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, 0);
3551iscsi_session_attr(erl, ISCSI_PARAM_ERL, 0);
3552iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT, 0);
3553iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1);
3554iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
3555iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
3556iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
Mike Christie30534952012-02-27 03:08:53 -08003557iscsi_session_attr(chap_out_idx, ISCSI_PARAM_CHAP_OUT_IDX, 1);
3558iscsi_session_attr(chap_in_idx, ISCSI_PARAM_CHAP_IN_IDX, 1);
Mike Christie4cd49ea2007-12-13 12:43:38 -06003559iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
3560iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
3561iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
Mike Christie3fe5ae82009-11-11 16:34:33 -06003562iscsi_session_attr(tgt_reset_tmo, ISCSI_PARAM_TGT_RESET_TMO, 0);
Mike Christie88dfd342008-05-21 15:54:16 -05003563iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
Vikas Chaudhary3b2bef12010-07-10 14:51:30 +05303564iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0);
3565iscsi_session_attr(targetalias, ISCSI_PARAM_TARGET_ALIAS, 0);
Eddie Wai3b9373e2013-06-20 10:21:26 -07003566iscsi_session_attr(boot_root, ISCSI_PARAM_BOOT_ROOT, 0);
3567iscsi_session_attr(boot_nic, ISCSI_PARAM_BOOT_NIC, 0);
3568iscsi_session_attr(boot_target, ISCSI_PARAM_BOOT_TARGET, 0);
Adheer Chandravanshiae542ed2013-07-01 05:54:11 -04003569iscsi_session_attr(auto_snd_tgt_disable, ISCSI_PARAM_AUTO_SND_TGT_DISABLE, 0);
3570iscsi_session_attr(discovery_session, ISCSI_PARAM_DISCOVERY_SESS, 0);
3571iscsi_session_attr(portal_type, ISCSI_PARAM_PORTAL_TYPE, 0);
3572iscsi_session_attr(chap_auth, ISCSI_PARAM_CHAP_AUTH_EN, 0);
3573iscsi_session_attr(discovery_logout, ISCSI_PARAM_DISCOVERY_LOGOUT_EN, 0);
3574iscsi_session_attr(bidi_chap, ISCSI_PARAM_BIDI_CHAP_EN, 0);
3575iscsi_session_attr(discovery_auth_optional,
3576 ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL, 0);
3577iscsi_session_attr(def_time2wait, ISCSI_PARAM_DEF_TIME2WAIT, 0);
3578iscsi_session_attr(def_time2retain, ISCSI_PARAM_DEF_TIME2RETAIN, 0);
3579iscsi_session_attr(isid, ISCSI_PARAM_ISID, 0);
3580iscsi_session_attr(tsid, ISCSI_PARAM_TSID, 0);
3581iscsi_session_attr(def_taskmgmt_tmo, ISCSI_PARAM_DEF_TASKMGMT_TMO, 0);
3582iscsi_session_attr(discovery_parent_idx, ISCSI_PARAM_DISCOVERY_PARENT_IDX, 0);
3583iscsi_session_attr(discovery_parent_type, ISCSI_PARAM_DISCOVERY_PARENT_TYPE, 0);
Mike Christiefd7255f2006-04-06 21:13:36 -05003584
Mike Christie6eabafb2008-01-31 13:36:43 -06003585static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01003586show_priv_session_state(struct device *dev, struct device_attribute *attr,
3587 char *buf)
Mike Christie6eabafb2008-01-31 13:36:43 -06003588{
Tony Jonesee959b02008-02-22 00:13:36 +01003589 struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
Mike Christie6eabafb2008-01-31 13:36:43 -06003590 return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
3591}
3592static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
3593 NULL);
Mike Christie0c70d842011-12-05 16:44:01 -06003594static ssize_t
3595show_priv_session_creator(struct device *dev, struct device_attribute *attr,
3596 char *buf)
3597{
3598 struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
3599 return sprintf(buf, "%d\n", session->creator);
3600}
3601static ISCSI_CLASS_ATTR(priv_sess, creator, S_IRUGO, show_priv_session_creator,
3602 NULL);
Manish Rangankar930a9f02012-11-23 06:58:41 -05003603static ssize_t
3604show_priv_session_target_id(struct device *dev, struct device_attribute *attr,
3605 char *buf)
3606{
3607 struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
3608 return sprintf(buf, "%d\n", session->target_id);
3609}
3610static ISCSI_CLASS_ATTR(priv_sess, target_id, S_IRUGO,
3611 show_priv_session_target_id, NULL);
Mike Christie6eabafb2008-01-31 13:36:43 -06003612
Mike Christiefd7255f2006-04-06 21:13:36 -05003613#define iscsi_priv_session_attr_show(field, format) \
3614static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01003615show_priv_session_##field(struct device *dev, \
3616 struct device_attribute *attr, char *buf) \
Mike Christiefd7255f2006-04-06 21:13:36 -05003617{ \
Tony Jonesee959b02008-02-22 00:13:36 +01003618 struct iscsi_cls_session *session = \
3619 iscsi_dev_to_session(dev->parent); \
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05303620 if (session->field == -1) \
3621 return sprintf(buf, "off\n"); \
Mike Christiefd7255f2006-04-06 21:13:36 -05003622 return sprintf(buf, format"\n", session->field); \
3623}
3624
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05303625#define iscsi_priv_session_attr_store(field) \
3626static ssize_t \
3627store_priv_session_##field(struct device *dev, \
3628 struct device_attribute *attr, \
3629 const char *buf, size_t count) \
3630{ \
3631 int val; \
3632 char *cp; \
3633 struct iscsi_cls_session *session = \
3634 iscsi_dev_to_session(dev->parent); \
3635 if ((session->state == ISCSI_SESSION_FREE) || \
3636 (session->state == ISCSI_SESSION_FAILED)) \
3637 return -EBUSY; \
3638 if (strncmp(buf, "off", 3) == 0) \
3639 session->field = -1; \
3640 else { \
3641 val = simple_strtoul(buf, &cp, 0); \
3642 if (*cp != '\0' && *cp != '\n') \
3643 return -EINVAL; \
3644 session->field = val; \
3645 } \
3646 return count; \
3647}
3648
3649#define iscsi_priv_session_rw_attr(field, format) \
Mike Christiefd7255f2006-04-06 21:13:36 -05003650 iscsi_priv_session_attr_show(field, format) \
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05303651 iscsi_priv_session_attr_store(field) \
Vasiliy Kulikov523f3c82011-02-04 15:24:14 +03003652static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUSR, \
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05303653 show_priv_session_##field, \
3654 store_priv_session_##field)
3655iscsi_priv_session_rw_attr(recovery_tmo, "%d");
Mike Christiefd7255f2006-04-06 21:13:36 -05003656
Mike Christie1d063c12011-07-25 13:48:43 -05003657static struct attribute *iscsi_session_attrs[] = {
3658 &dev_attr_sess_initial_r2t.attr,
3659 &dev_attr_sess_max_outstanding_r2t.attr,
3660 &dev_attr_sess_immediate_data.attr,
3661 &dev_attr_sess_first_burst_len.attr,
3662 &dev_attr_sess_max_burst_len.attr,
3663 &dev_attr_sess_data_pdu_in_order.attr,
3664 &dev_attr_sess_data_seq_in_order.attr,
3665 &dev_attr_sess_erl.attr,
3666 &dev_attr_sess_targetname.attr,
3667 &dev_attr_sess_tpgt.attr,
3668 &dev_attr_sess_password.attr,
3669 &dev_attr_sess_password_in.attr,
3670 &dev_attr_sess_username.attr,
3671 &dev_attr_sess_username_in.attr,
3672 &dev_attr_sess_fast_abort.attr,
3673 &dev_attr_sess_abort_tmo.attr,
3674 &dev_attr_sess_lu_reset_tmo.attr,
3675 &dev_attr_sess_tgt_reset_tmo.attr,
3676 &dev_attr_sess_ifacename.attr,
3677 &dev_attr_sess_initiatorname.attr,
3678 &dev_attr_sess_targetalias.attr,
Eddie Wai3b9373e2013-06-20 10:21:26 -07003679 &dev_attr_sess_boot_root.attr,
3680 &dev_attr_sess_boot_nic.attr,
3681 &dev_attr_sess_boot_target.attr,
Mike Christie1d063c12011-07-25 13:48:43 -05003682 &dev_attr_priv_sess_recovery_tmo.attr,
3683 &dev_attr_priv_sess_state.attr,
Mike Christie0c70d842011-12-05 16:44:01 -06003684 &dev_attr_priv_sess_creator.attr,
Mike Christie30534952012-02-27 03:08:53 -08003685 &dev_attr_sess_chap_out_idx.attr,
3686 &dev_attr_sess_chap_in_idx.attr,
Manish Rangankar930a9f02012-11-23 06:58:41 -05003687 &dev_attr_priv_sess_target_id.attr,
Adheer Chandravanshiae542ed2013-07-01 05:54:11 -04003688 &dev_attr_sess_auto_snd_tgt_disable.attr,
3689 &dev_attr_sess_discovery_session.attr,
3690 &dev_attr_sess_portal_type.attr,
3691 &dev_attr_sess_chap_auth.attr,
3692 &dev_attr_sess_discovery_logout.attr,
3693 &dev_attr_sess_bidi_chap.attr,
3694 &dev_attr_sess_discovery_auth_optional.attr,
3695 &dev_attr_sess_def_time2wait.attr,
3696 &dev_attr_sess_def_time2retain.attr,
3697 &dev_attr_sess_isid.attr,
3698 &dev_attr_sess_tsid.attr,
3699 &dev_attr_sess_def_taskmgmt_tmo.attr,
3700 &dev_attr_sess_discovery_parent_idx.attr,
3701 &dev_attr_sess_discovery_parent_type.attr,
Mike Christie1d063c12011-07-25 13:48:43 -05003702 NULL,
3703};
3704
Al Viro587a1f12011-07-23 23:11:19 -04003705static umode_t iscsi_session_attr_is_visible(struct kobject *kobj,
Mike Christie1d063c12011-07-25 13:48:43 -05003706 struct attribute *attr, int i)
3707{
3708 struct device *cdev = container_of(kobj, struct device, kobj);
3709 struct iscsi_cls_session *session = transport_class_to_session(cdev);
3710 struct iscsi_transport *t = session->transport;
3711 int param;
3712
3713 if (attr == &dev_attr_sess_initial_r2t.attr)
3714 param = ISCSI_PARAM_INITIAL_R2T_EN;
3715 else if (attr == &dev_attr_sess_max_outstanding_r2t.attr)
3716 param = ISCSI_PARAM_MAX_R2T;
3717 else if (attr == &dev_attr_sess_immediate_data.attr)
3718 param = ISCSI_PARAM_IMM_DATA_EN;
3719 else if (attr == &dev_attr_sess_first_burst_len.attr)
3720 param = ISCSI_PARAM_FIRST_BURST;
3721 else if (attr == &dev_attr_sess_max_burst_len.attr)
3722 param = ISCSI_PARAM_MAX_BURST;
3723 else if (attr == &dev_attr_sess_data_pdu_in_order.attr)
3724 param = ISCSI_PARAM_PDU_INORDER_EN;
3725 else if (attr == &dev_attr_sess_data_seq_in_order.attr)
3726 param = ISCSI_PARAM_DATASEQ_INORDER_EN;
3727 else if (attr == &dev_attr_sess_erl.attr)
3728 param = ISCSI_PARAM_ERL;
3729 else if (attr == &dev_attr_sess_targetname.attr)
3730 param = ISCSI_PARAM_TARGET_NAME;
3731 else if (attr == &dev_attr_sess_tpgt.attr)
3732 param = ISCSI_PARAM_TPGT;
Mike Christie30534952012-02-27 03:08:53 -08003733 else if (attr == &dev_attr_sess_chap_in_idx.attr)
3734 param = ISCSI_PARAM_CHAP_IN_IDX;
3735 else if (attr == &dev_attr_sess_chap_out_idx.attr)
3736 param = ISCSI_PARAM_CHAP_OUT_IDX;
Mike Christie1d063c12011-07-25 13:48:43 -05003737 else if (attr == &dev_attr_sess_password.attr)
3738 param = ISCSI_PARAM_USERNAME;
3739 else if (attr == &dev_attr_sess_password_in.attr)
3740 param = ISCSI_PARAM_USERNAME_IN;
3741 else if (attr == &dev_attr_sess_username.attr)
3742 param = ISCSI_PARAM_PASSWORD;
3743 else if (attr == &dev_attr_sess_username_in.attr)
3744 param = ISCSI_PARAM_PASSWORD_IN;
3745 else if (attr == &dev_attr_sess_fast_abort.attr)
3746 param = ISCSI_PARAM_FAST_ABORT;
3747 else if (attr == &dev_attr_sess_abort_tmo.attr)
3748 param = ISCSI_PARAM_ABORT_TMO;
3749 else if (attr == &dev_attr_sess_lu_reset_tmo.attr)
3750 param = ISCSI_PARAM_LU_RESET_TMO;
3751 else if (attr == &dev_attr_sess_tgt_reset_tmo.attr)
3752 param = ISCSI_PARAM_TGT_RESET_TMO;
3753 else if (attr == &dev_attr_sess_ifacename.attr)
3754 param = ISCSI_PARAM_IFACE_NAME;
3755 else if (attr == &dev_attr_sess_initiatorname.attr)
3756 param = ISCSI_PARAM_INITIATOR_NAME;
3757 else if (attr == &dev_attr_sess_targetalias.attr)
3758 param = ISCSI_PARAM_TARGET_ALIAS;
Eddie Wai3b9373e2013-06-20 10:21:26 -07003759 else if (attr == &dev_attr_sess_boot_root.attr)
3760 param = ISCSI_PARAM_BOOT_ROOT;
3761 else if (attr == &dev_attr_sess_boot_nic.attr)
3762 param = ISCSI_PARAM_BOOT_NIC;
3763 else if (attr == &dev_attr_sess_boot_target.attr)
3764 param = ISCSI_PARAM_BOOT_TARGET;
Adheer Chandravanshiae542ed2013-07-01 05:54:11 -04003765 else if (attr == &dev_attr_sess_auto_snd_tgt_disable.attr)
3766 param = ISCSI_PARAM_AUTO_SND_TGT_DISABLE;
3767 else if (attr == &dev_attr_sess_discovery_session.attr)
3768 param = ISCSI_PARAM_DISCOVERY_SESS;
3769 else if (attr == &dev_attr_sess_portal_type.attr)
3770 param = ISCSI_PARAM_PORTAL_TYPE;
3771 else if (attr == &dev_attr_sess_chap_auth.attr)
3772 param = ISCSI_PARAM_CHAP_AUTH_EN;
3773 else if (attr == &dev_attr_sess_discovery_logout.attr)
3774 param = ISCSI_PARAM_DISCOVERY_LOGOUT_EN;
3775 else if (attr == &dev_attr_sess_bidi_chap.attr)
3776 param = ISCSI_PARAM_BIDI_CHAP_EN;
3777 else if (attr == &dev_attr_sess_discovery_auth_optional.attr)
3778 param = ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL;
3779 else if (attr == &dev_attr_sess_def_time2wait.attr)
3780 param = ISCSI_PARAM_DEF_TIME2WAIT;
3781 else if (attr == &dev_attr_sess_def_time2retain.attr)
3782 param = ISCSI_PARAM_DEF_TIME2RETAIN;
3783 else if (attr == &dev_attr_sess_isid.attr)
3784 param = ISCSI_PARAM_ISID;
3785 else if (attr == &dev_attr_sess_tsid.attr)
3786 param = ISCSI_PARAM_TSID;
3787 else if (attr == &dev_attr_sess_def_taskmgmt_tmo.attr)
3788 param = ISCSI_PARAM_DEF_TASKMGMT_TMO;
3789 else if (attr == &dev_attr_sess_discovery_parent_idx.attr)
3790 param = ISCSI_PARAM_DISCOVERY_PARENT_IDX;
3791 else if (attr == &dev_attr_sess_discovery_parent_type.attr)
3792 param = ISCSI_PARAM_DISCOVERY_PARENT_TYPE;
Mike Christie1d063c12011-07-25 13:48:43 -05003793 else if (attr == &dev_attr_priv_sess_recovery_tmo.attr)
3794 return S_IRUGO | S_IWUSR;
3795 else if (attr == &dev_attr_priv_sess_state.attr)
3796 return S_IRUGO;
Mike Christie0c70d842011-12-05 16:44:01 -06003797 else if (attr == &dev_attr_priv_sess_creator.attr)
3798 return S_IRUGO;
Manish Rangankar930a9f02012-11-23 06:58:41 -05003799 else if (attr == &dev_attr_priv_sess_target_id.attr)
3800 return S_IRUGO;
Mike Christie1d063c12011-07-25 13:48:43 -05003801 else {
3802 WARN_ONCE(1, "Invalid session attr");
3803 return 0;
3804 }
3805
3806 return t->attr_is_visible(ISCSI_PARAM, param);
3807}
3808
3809static struct attribute_group iscsi_session_group = {
3810 .attrs = iscsi_session_attrs,
3811 .is_visible = iscsi_session_attr_is_visible,
3812};
3813
Mike Christie1819dc82007-05-30 12:57:08 -05003814/*
3815 * iSCSI host attrs
3816 */
3817#define iscsi_host_attr_show(param) \
3818static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01003819show_host_param_##param(struct device *dev, \
3820 struct device_attribute *attr, char *buf) \
Mike Christie1819dc82007-05-30 12:57:08 -05003821{ \
Tony Jonesee959b02008-02-22 00:13:36 +01003822 struct Scsi_Host *shost = transport_class_to_shost(dev); \
Mike Christie1819dc82007-05-30 12:57:08 -05003823 struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
3824 return priv->iscsi_transport->get_host_param(shost, param, buf); \
3825}
3826
3827#define iscsi_host_attr(field, param) \
3828 iscsi_host_attr_show(param) \
3829static ISCSI_CLASS_ATTR(host, field, S_IRUGO, show_host_param_##param, \
3830 NULL);
3831
Mike Christied8196ed2007-05-30 12:57:25 -05003832iscsi_host_attr(netdev, ISCSI_HOST_PARAM_NETDEV_NAME);
Mike Christie1819dc82007-05-30 12:57:08 -05003833iscsi_host_attr(hwaddress, ISCSI_HOST_PARAM_HWADDRESS);
Mike Christied8196ed2007-05-30 12:57:25 -05003834iscsi_host_attr(ipaddress, ISCSI_HOST_PARAM_IPADDRESS);
Mike Christie8ad57812007-05-30 12:57:13 -05003835iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
Vikas Chaudharyaeddde22012-01-19 03:06:55 -08003836iscsi_host_attr(port_state, ISCSI_HOST_PARAM_PORT_STATE);
3837iscsi_host_attr(port_speed, ISCSI_HOST_PARAM_PORT_SPEED);
Mike Christie1819dc82007-05-30 12:57:08 -05003838
Mike Christief27fb2e2011-07-25 13:48:45 -05003839static struct attribute *iscsi_host_attrs[] = {
3840 &dev_attr_host_netdev.attr,
3841 &dev_attr_host_hwaddress.attr,
3842 &dev_attr_host_ipaddress.attr,
3843 &dev_attr_host_initiatorname.attr,
Vikas Chaudharyaeddde22012-01-19 03:06:55 -08003844 &dev_attr_host_port_state.attr,
3845 &dev_attr_host_port_speed.attr,
Mike Christief27fb2e2011-07-25 13:48:45 -05003846 NULL,
3847};
3848
Al Viro587a1f12011-07-23 23:11:19 -04003849static umode_t iscsi_host_attr_is_visible(struct kobject *kobj,
Mike Christief27fb2e2011-07-25 13:48:45 -05003850 struct attribute *attr, int i)
3851{
3852 struct device *cdev = container_of(kobj, struct device, kobj);
3853 struct Scsi_Host *shost = transport_class_to_shost(cdev);
3854 struct iscsi_internal *priv = to_iscsi_internal(shost->transportt);
3855 int param;
3856
3857 if (attr == &dev_attr_host_netdev.attr)
3858 param = ISCSI_HOST_PARAM_NETDEV_NAME;
3859 else if (attr == &dev_attr_host_hwaddress.attr)
3860 param = ISCSI_HOST_PARAM_HWADDRESS;
3861 else if (attr == &dev_attr_host_ipaddress.attr)
3862 param = ISCSI_HOST_PARAM_IPADDRESS;
3863 else if (attr == &dev_attr_host_initiatorname.attr)
3864 param = ISCSI_HOST_PARAM_INITIATOR_NAME;
Vikas Chaudharyaeddde22012-01-19 03:06:55 -08003865 else if (attr == &dev_attr_host_port_state.attr)
3866 param = ISCSI_HOST_PARAM_PORT_STATE;
3867 else if (attr == &dev_attr_host_port_speed.attr)
3868 param = ISCSI_HOST_PARAM_PORT_SPEED;
Mike Christief27fb2e2011-07-25 13:48:45 -05003869 else {
3870 WARN_ONCE(1, "Invalid host attr");
3871 return 0;
3872 }
3873
3874 return priv->iscsi_transport->attr_is_visible(ISCSI_HOST_PARAM, param);
3875}
3876
3877static struct attribute_group iscsi_host_group = {
3878 .attrs = iscsi_host_attrs,
3879 .is_visible = iscsi_host_attr_is_visible,
3880};
Mike Christie1819dc82007-05-30 12:57:08 -05003881
Vikas Chaudharyaeddde22012-01-19 03:06:55 -08003882/* convert iscsi_port_speed values to ascii string name */
3883static const struct {
3884 enum iscsi_port_speed value;
3885 char *name;
3886} iscsi_port_speed_names[] = {
3887 {ISCSI_PORT_SPEED_UNKNOWN, "Unknown" },
3888 {ISCSI_PORT_SPEED_10MBPS, "10 Mbps" },
3889 {ISCSI_PORT_SPEED_100MBPS, "100 Mbps" },
3890 {ISCSI_PORT_SPEED_1GBPS, "1 Gbps" },
3891 {ISCSI_PORT_SPEED_10GBPS, "10 Gbps" },
3892};
3893
3894char *iscsi_get_port_speed_name(struct Scsi_Host *shost)
3895{
3896 int i;
3897 char *speed = "Unknown!";
3898 struct iscsi_cls_host *ihost = shost->shost_data;
3899 uint32_t port_speed = ihost->port_speed;
3900
3901 for (i = 0; i < ARRAY_SIZE(iscsi_port_speed_names); i++) {
3902 if (iscsi_port_speed_names[i].value & port_speed) {
3903 speed = iscsi_port_speed_names[i].name;
3904 break;
3905 }
3906 }
3907 return speed;
3908}
3909EXPORT_SYMBOL_GPL(iscsi_get_port_speed_name);
3910
3911/* convert iscsi_port_state values to ascii string name */
3912static const struct {
3913 enum iscsi_port_state value;
3914 char *name;
3915} iscsi_port_state_names[] = {
3916 {ISCSI_PORT_STATE_DOWN, "LINK DOWN" },
3917 {ISCSI_PORT_STATE_UP, "LINK UP" },
3918};
3919
3920char *iscsi_get_port_state_name(struct Scsi_Host *shost)
3921{
3922 int i;
3923 char *state = "Unknown!";
3924 struct iscsi_cls_host *ihost = shost->shost_data;
3925 uint32_t port_state = ihost->port_state;
3926
3927 for (i = 0; i < ARRAY_SIZE(iscsi_port_state_names); i++) {
3928 if (iscsi_port_state_names[i].value & port_state) {
3929 state = iscsi_port_state_names[i].name;
3930 break;
3931 }
3932 }
3933 return state;
3934}
3935EXPORT_SYMBOL_GPL(iscsi_get_port_state_name);
3936
Alex Aizman0896b752005-08-04 19:33:07 -07003937static int iscsi_session_match(struct attribute_container *cont,
3938 struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939{
Mike Christie7b8631b2006-01-13 18:05:50 -06003940 struct iscsi_cls_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 struct Scsi_Host *shost;
Alex Aizman0896b752005-08-04 19:33:07 -07003942 struct iscsi_internal *priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943
Alex Aizman0896b752005-08-04 19:33:07 -07003944 if (!iscsi_is_session_dev(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945 return 0;
3946
Mike Christie7b8631b2006-01-13 18:05:50 -06003947 session = iscsi_dev_to_session(dev);
3948 shost = iscsi_session_to_shost(session);
Alex Aizman0896b752005-08-04 19:33:07 -07003949 if (!shost->transportt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 return 0;
3951
Alex Aizman0896b752005-08-04 19:33:07 -07003952 priv = to_iscsi_internal(shost->transportt);
3953 if (priv->session_cont.ac.class != &iscsi_session_class.class)
3954 return 0;
3955
3956 return &priv->session_cont.ac == cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957}
3958
Alex Aizman0896b752005-08-04 19:33:07 -07003959static int iscsi_conn_match(struct attribute_container *cont,
3960 struct device *dev)
3961{
Mike Christie7b8631b2006-01-13 18:05:50 -06003962 struct iscsi_cls_session *session;
3963 struct iscsi_cls_conn *conn;
Alex Aizman0896b752005-08-04 19:33:07 -07003964 struct Scsi_Host *shost;
3965 struct iscsi_internal *priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966
Alex Aizman0896b752005-08-04 19:33:07 -07003967 if (!iscsi_is_conn_dev(dev))
3968 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969
Mike Christie7b8631b2006-01-13 18:05:50 -06003970 conn = iscsi_dev_to_conn(dev);
3971 session = iscsi_dev_to_session(conn->dev.parent);
3972 shost = iscsi_session_to_shost(session);
3973
Alex Aizman0896b752005-08-04 19:33:07 -07003974 if (!shost->transportt)
3975 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976
Alex Aizman0896b752005-08-04 19:33:07 -07003977 priv = to_iscsi_internal(shost->transportt);
3978 if (priv->conn_cont.ac.class != &iscsi_connection_class.class)
3979 return 0;
3980
3981 return &priv->conn_cont.ac == cont;
3982}
3983
Mike Christie30a6c652006-04-06 21:13:39 -05003984static int iscsi_host_match(struct attribute_container *cont,
3985 struct device *dev)
3986{
3987 struct Scsi_Host *shost;
3988 struct iscsi_internal *priv;
3989
3990 if (!scsi_is_host_device(dev))
3991 return 0;
3992
3993 shost = dev_to_shost(dev);
3994 if (!shost->transportt ||
3995 shost->transportt->host_attrs.ac.class != &iscsi_host_class.class)
3996 return 0;
3997
3998 priv = to_iscsi_internal(shost->transportt);
3999 return &priv->t.host_attrs.ac == cont;
4000}
4001
Mike Christie7b8631b2006-01-13 18:05:50 -06004002struct scsi_transport_template *
4003iscsi_register_transport(struct iscsi_transport *tt)
Alex Aizman0896b752005-08-04 19:33:07 -07004004{
4005 struct iscsi_internal *priv;
4006 unsigned long flags;
Mike Christief27fb2e2011-07-25 13:48:45 -05004007 int err;
Alex Aizman0896b752005-08-04 19:33:07 -07004008
4009 BUG_ON(!tt);
4010
4011 priv = iscsi_if_transport_lookup(tt);
4012 if (priv)
Mike Christie7b8631b2006-01-13 18:05:50 -06004013 return NULL;
Alex Aizman0896b752005-08-04 19:33:07 -07004014
Jes Sorensen24669f752006-01-16 10:31:18 -05004015 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
Alex Aizman0896b752005-08-04 19:33:07 -07004016 if (!priv)
Mike Christie7b8631b2006-01-13 18:05:50 -06004017 return NULL;
Alex Aizman0896b752005-08-04 19:33:07 -07004018 INIT_LIST_HEAD(&priv->list);
Alex Aizman0896b752005-08-04 19:33:07 -07004019 priv->iscsi_transport = tt;
Mike Christie30a6c652006-04-06 21:13:39 -05004020 priv->t.user_scan = iscsi_user_scan;
Mike Christie06d25af2009-03-05 14:46:02 -06004021 priv->t.create_work_queue = 1;
Alex Aizman0896b752005-08-04 19:33:07 -07004022
Tony Jonesee959b02008-02-22 00:13:36 +01004023 priv->dev.class = &iscsi_transport_class;
Kay Sievers71610f52008-12-03 22:41:36 +01004024 dev_set_name(&priv->dev, "%s", tt->name);
Tony Jonesee959b02008-02-22 00:13:36 +01004025 err = device_register(&priv->dev);
Alex Aizman0896b752005-08-04 19:33:07 -07004026 if (err)
4027 goto free_priv;
4028
Tony Jonesee959b02008-02-22 00:13:36 +01004029 err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
Alex Aizman0896b752005-08-04 19:33:07 -07004030 if (err)
Tony Jonesee959b02008-02-22 00:13:36 +01004031 goto unregister_dev;
Alex Aizman0896b752005-08-04 19:33:07 -07004032
Mike Christie30a6c652006-04-06 21:13:39 -05004033 /* host parameters */
Mike Christie30a6c652006-04-06 21:13:39 -05004034 priv->t.host_attrs.ac.class = &iscsi_host_class.class;
4035 priv->t.host_attrs.ac.match = iscsi_host_match;
Mike Christief27fb2e2011-07-25 13:48:45 -05004036 priv->t.host_attrs.ac.grp = &iscsi_host_group;
Mike Christie32c6e1b2008-05-21 15:53:58 -05004037 priv->t.host_size = sizeof(struct iscsi_cls_host);
Mike Christie30a6c652006-04-06 21:13:39 -05004038 transport_container_register(&priv->t.host_attrs);
4039
Alex Aizman0896b752005-08-04 19:33:07 -07004040 /* connection parameters */
Alex Aizman0896b752005-08-04 19:33:07 -07004041 priv->conn_cont.ac.class = &iscsi_connection_class.class;
4042 priv->conn_cont.ac.match = iscsi_conn_match;
Mike Christie3128c6c2011-07-25 13:48:42 -05004043 priv->conn_cont.ac.grp = &iscsi_conn_group;
Alex Aizman0896b752005-08-04 19:33:07 -07004044 transport_container_register(&priv->conn_cont);
4045
Alex Aizman0896b752005-08-04 19:33:07 -07004046 /* session parameters */
Alex Aizman0896b752005-08-04 19:33:07 -07004047 priv->session_cont.ac.class = &iscsi_session_class.class;
4048 priv->session_cont.ac.match = iscsi_session_match;
Mike Christie1d063c12011-07-25 13:48:43 -05004049 priv->session_cont.ac.grp = &iscsi_session_group;
Alex Aizman0896b752005-08-04 19:33:07 -07004050 transport_container_register(&priv->session_cont);
4051
Alex Aizman0896b752005-08-04 19:33:07 -07004052 spin_lock_irqsave(&iscsi_transport_lock, flags);
4053 list_add(&priv->list, &iscsi_transports);
4054 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055
Alex Aizman0896b752005-08-04 19:33:07 -07004056 printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
Mike Christie7b8631b2006-01-13 18:05:50 -06004057 return &priv->t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058
Tony Jonesee959b02008-02-22 00:13:36 +01004059unregister_dev:
4060 device_unregister(&priv->dev);
Mike Christied82ff9be2008-05-21 15:54:13 -05004061 return NULL;
Alex Aizman0896b752005-08-04 19:33:07 -07004062free_priv:
4063 kfree(priv);
Mike Christie7b8631b2006-01-13 18:05:50 -06004064 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065}
Alex Aizman0896b752005-08-04 19:33:07 -07004066EXPORT_SYMBOL_GPL(iscsi_register_transport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067
Alex Aizman0896b752005-08-04 19:33:07 -07004068int iscsi_unregister_transport(struct iscsi_transport *tt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069{
Alex Aizman0896b752005-08-04 19:33:07 -07004070 struct iscsi_internal *priv;
4071 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072
Alex Aizman0896b752005-08-04 19:33:07 -07004073 BUG_ON(!tt);
4074
Arjan van de Ven0b950672006-01-11 13:16:10 +01004075 mutex_lock(&rx_queue_mutex);
Alex Aizman0896b752005-08-04 19:33:07 -07004076
4077 priv = iscsi_if_transport_lookup(tt);
4078 BUG_ON (!priv);
4079
Alex Aizman0896b752005-08-04 19:33:07 -07004080 spin_lock_irqsave(&iscsi_transport_lock, flags);
4081 list_del(&priv->list);
4082 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
4083
4084 transport_container_unregister(&priv->conn_cont);
4085 transport_container_unregister(&priv->session_cont);
Mike Christie30a6c652006-04-06 21:13:39 -05004086 transport_container_unregister(&priv->t.host_attrs);
Alex Aizman0896b752005-08-04 19:33:07 -07004087
Tony Jonesee959b02008-02-22 00:13:36 +01004088 sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
4089 device_unregister(&priv->dev);
Arjan van de Ven0b950672006-01-11 13:16:10 +01004090 mutex_unlock(&rx_queue_mutex);
Alex Aizman0896b752005-08-04 19:33:07 -07004091
4092 return 0;
4093}
4094EXPORT_SYMBOL_GPL(iscsi_unregister_transport);
4095
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096static __init int iscsi_transport_init(void)
4097{
Alex Aizman0896b752005-08-04 19:33:07 -07004098 int err;
Pablo Neira Ayusoa31f2d12012-06-29 06:15:21 +00004099 struct netlink_kernel_cfg cfg = {
4100 .groups = 1,
4101 .input = iscsi_if_rx,
4102 };
Meelis Roos09492602006-12-17 12:10:26 -06004103 printk(KERN_INFO "Loading iSCSI transport class v%s.\n",
Mike Christief4246b32006-07-24 15:47:54 -05004104 ISCSI_TRANSPORT_VERSION);
4105
Mike Christie41be1442007-02-28 17:32:18 -06004106 atomic_set(&iscsi_session_nr, 0);
4107
Alex Aizman0896b752005-08-04 19:33:07 -07004108 err = class_register(&iscsi_transport_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 if (err)
4110 return err;
Alex Aizman0896b752005-08-04 19:33:07 -07004111
Mike Christied82ff9be2008-05-21 15:54:13 -05004112 err = class_register(&iscsi_endpoint_class);
Alex Aizman0896b752005-08-04 19:33:07 -07004113 if (err)
4114 goto unregister_transport_class;
4115
Mike Christie8d079132011-07-25 13:48:40 -05004116 err = class_register(&iscsi_iface_class);
Mike Christied82ff9be2008-05-21 15:54:13 -05004117 if (err)
4118 goto unregister_endpoint_class;
4119
Mike Christie8d079132011-07-25 13:48:40 -05004120 err = transport_class_register(&iscsi_host_class);
4121 if (err)
4122 goto unregister_iface_class;
4123
Mike Christie30a6c652006-04-06 21:13:39 -05004124 err = transport_class_register(&iscsi_connection_class);
4125 if (err)
4126 goto unregister_host_class;
4127
Alex Aizman0896b752005-08-04 19:33:07 -07004128 err = transport_class_register(&iscsi_session_class);
4129 if (err)
4130 goto unregister_conn_class;
4131
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04004132 err = bus_register(&iscsi_flashnode_bus);
4133 if (err)
4134 goto unregister_session_class;
4135
Pablo Neira Ayuso9f00d972012-09-08 02:53:54 +00004136 nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, &cfg);
Alex Aizman0896b752005-08-04 19:33:07 -07004137 if (!nls) {
4138 err = -ENOBUFS;
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04004139 goto unregister_flashnode_bus;
Alex Aizman0896b752005-08-04 19:33:07 -07004140 }
4141
Mike Christied8bf5412007-12-13 12:43:27 -06004142 iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh");
Wei Yongjunbcab2cc2013-04-19 09:23:28 +08004143 if (!iscsi_eh_timer_workq) {
4144 err = -ENOMEM;
Mike Christied8bf5412007-12-13 12:43:27 -06004145 goto release_nls;
Wei Yongjunbcab2cc2013-04-19 09:23:28 +08004146 }
Mike Christied8bf5412007-12-13 12:43:27 -06004147
Mike Christie43a145a2006-10-16 18:09:38 -04004148 return 0;
Alex Aizman0896b752005-08-04 19:33:07 -07004149
Mike Christied8bf5412007-12-13 12:43:27 -06004150release_nls:
Denis V. Lunevb7c6ba62008-01-28 14:41:19 -08004151 netlink_kernel_release(nls);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04004152unregister_flashnode_bus:
4153 bus_unregister(&iscsi_flashnode_bus);
Alex Aizman0896b752005-08-04 19:33:07 -07004154unregister_session_class:
4155 transport_class_unregister(&iscsi_session_class);
4156unregister_conn_class:
4157 transport_class_unregister(&iscsi_connection_class);
Mike Christie30a6c652006-04-06 21:13:39 -05004158unregister_host_class:
4159 transport_class_unregister(&iscsi_host_class);
Mike Christie8d079132011-07-25 13:48:40 -05004160unregister_iface_class:
4161 class_unregister(&iscsi_iface_class);
Mike Christied82ff9be2008-05-21 15:54:13 -05004162unregister_endpoint_class:
4163 class_unregister(&iscsi_endpoint_class);
Alex Aizman0896b752005-08-04 19:33:07 -07004164unregister_transport_class:
4165 class_unregister(&iscsi_transport_class);
4166 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167}
4168
4169static void __exit iscsi_transport_exit(void)
4170{
Mike Christied8bf5412007-12-13 12:43:27 -06004171 destroy_workqueue(iscsi_eh_timer_workq);
Denis V. Lunevb7c6ba62008-01-28 14:41:19 -08004172 netlink_kernel_release(nls);
Adheer Chandravanshic6a4bb22013-03-22 07:41:29 -04004173 bus_unregister(&iscsi_flashnode_bus);
Alex Aizman0896b752005-08-04 19:33:07 -07004174 transport_class_unregister(&iscsi_connection_class);
4175 transport_class_unregister(&iscsi_session_class);
Mike Christie30a6c652006-04-06 21:13:39 -05004176 transport_class_unregister(&iscsi_host_class);
Mike Christied82ff9be2008-05-21 15:54:13 -05004177 class_unregister(&iscsi_endpoint_class);
Mike Christie8d079132011-07-25 13:48:40 -05004178 class_unregister(&iscsi_iface_class);
Alex Aizman0896b752005-08-04 19:33:07 -07004179 class_unregister(&iscsi_transport_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180}
4181
4182module_init(iscsi_transport_init);
4183module_exit(iscsi_transport_exit);
4184
Alex Aizman0896b752005-08-04 19:33:07 -07004185MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
4186 "Dmitry Yusupov <dmitry_yus@yahoo.com>, "
4187 "Alex Aizman <itn780@yahoo.com>");
4188MODULE_DESCRIPTION("iSCSI Transport Interface");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189MODULE_LICENSE("GPL");
Mike Christief4246b32006-07-24 15:47:54 -05004190MODULE_VERSION(ISCSI_TRANSPORT_VERSION);
Stephen Hemminger058548a2010-12-09 09:37:56 -08004191MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_ISCSI);