blob: 4d5e64f429e73ab53078338fd8d0532ccb35e4ed [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>
Alex Aizman0896b752005-08-04 19:33:07 -070026#include <net/tcp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <scsi/scsi.h>
28#include <scsi/scsi_host.h>
29#include <scsi/scsi_device.h>
30#include <scsi/scsi_transport.h>
31#include <scsi/scsi_transport_iscsi.h>
Alex Aizman0896b752005-08-04 19:33:07 -070032#include <scsi/iscsi_if.h>
Mike Christiec01be6d2010-07-22 16:59:49 +053033#include <scsi/scsi_cmnd.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Vikas Chaudhary3b2bef12010-07-10 14:51:30 +053035#define ISCSI_SESSION_ATTRS 23
Mike Christiec238c3b2008-01-31 13:36:51 -060036#define ISCSI_CONN_ATTRS 13
Mike Christied8196ed2007-05-30 12:57:25 -050037#define ISCSI_HOST_ATTRS 4
Mike Christied82ff9be2008-05-21 15:54:13 -050038
Mike Christie4c2133c2008-06-16 10:11:34 -050039#define ISCSI_TRANSPORT_VERSION "2.0-870"
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
Mike Christie632248a2009-08-20 15:11:01 -050041static int dbg_session;
42module_param_named(debug_session, dbg_session, int,
43 S_IRUGO | S_IWUSR);
44MODULE_PARM_DESC(debug_session,
45 "Turn on debugging for sessions in scsi_transport_iscsi "
46 "module. Set to 1 to turn on, and zero to turn off. Default "
47 "is off.");
48
49static int dbg_conn;
50module_param_named(debug_conn, dbg_conn, int,
51 S_IRUGO | S_IWUSR);
52MODULE_PARM_DESC(debug_conn,
53 "Turn on debugging for connections in scsi_transport_iscsi "
54 "module. Set to 1 to turn on, and zero to turn off. Default "
55 "is off.");
56
57#define ISCSI_DBG_TRANS_SESSION(_session, dbg_fmt, arg...) \
58 do { \
59 if (dbg_session) \
60 iscsi_cls_session_printk(KERN_INFO, _session, \
61 "%s: " dbg_fmt, \
62 __func__, ##arg); \
63 } while (0);
64
65#define ISCSI_DBG_TRANS_CONN(_conn, dbg_fmt, arg...) \
66 do { \
67 if (dbg_conn) \
68 iscsi_cls_conn_printk(KERN_INFO, _conn, \
69 "%s: " dbg_fmt, \
70 __func__, ##arg); \
71 } while (0);
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073struct iscsi_internal {
74 struct scsi_transport_template t;
Alex Aizman0896b752005-08-04 19:33:07 -070075 struct iscsi_transport *iscsi_transport;
76 struct list_head list;
Tony Jonesee959b02008-02-22 00:13:36 +010077 struct device dev;
Mike Christie30a6c652006-04-06 21:13:39 -050078
Tony Jonesee959b02008-02-22 00:13:36 +010079 struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
Alex Aizman0896b752005-08-04 19:33:07 -070080 struct transport_container conn_cont;
Tony Jonesee959b02008-02-22 00:13:36 +010081 struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
Alex Aizman0896b752005-08-04 19:33:07 -070082 struct transport_container session_cont;
Tony Jonesee959b02008-02-22 00:13:36 +010083 struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070084};
85
Mike Christie41be1442007-02-28 17:32:18 -060086static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
Mike Christied8bf5412007-12-13 12:43:27 -060087static struct workqueue_struct *iscsi_eh_timer_workq;
Mike Christieb5c7a122006-04-06 21:13:33 -050088
Alex Aizman0896b752005-08-04 19:33:07 -070089/*
90 * list of registered transports and lock that must
91 * be held while accessing list. The iscsi_transport_lock must
Arjan van de Ven0b950672006-01-11 13:16:10 +010092 * be acquired after the rx_queue_mutex.
Alex Aizman0896b752005-08-04 19:33:07 -070093 */
94static LIST_HEAD(iscsi_transports);
95static DEFINE_SPINLOCK(iscsi_transport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Alex Aizman0896b752005-08-04 19:33:07 -070097#define to_iscsi_internal(tmpl) \
98 container_of(tmpl, struct iscsi_internal, t)
99
Tony Jonesee959b02008-02-22 00:13:36 +0100100#define dev_to_iscsi_internal(_dev) \
101 container_of(_dev, struct iscsi_internal, dev)
Alex Aizman0896b752005-08-04 19:33:07 -0700102
Tony Jonesee959b02008-02-22 00:13:36 +0100103static void iscsi_transport_release(struct device *dev)
Alex Aizman0896b752005-08-04 19:33:07 -0700104{
Tony Jonesee959b02008-02-22 00:13:36 +0100105 struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
Alex Aizman0896b752005-08-04 19:33:07 -0700106 kfree(priv);
107}
108
109/*
110 * iscsi_transport_class represents the iscsi_transports that are
111 * registered.
112 */
113static struct class iscsi_transport_class = {
114 .name = "iscsi_transport",
Tony Jonesee959b02008-02-22 00:13:36 +0100115 .dev_release = iscsi_transport_release,
Alex Aizman0896b752005-08-04 19:33:07 -0700116};
117
118static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +0100119show_transport_handle(struct device *dev, struct device_attribute *attr,
120 char *buf)
Alex Aizman0896b752005-08-04 19:33:07 -0700121{
Tony Jonesee959b02008-02-22 00:13:36 +0100122 struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
Mike Christie762e2bf2005-09-12 21:01:46 -0500123 return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
Alex Aizman0896b752005-08-04 19:33:07 -0700124}
Tony Jonesee959b02008-02-22 00:13:36 +0100125static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
Alex Aizman0896b752005-08-04 19:33:07 -0700126
127#define show_transport_attr(name, format) \
128static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100129show_transport_##name(struct device *dev, \
130 struct device_attribute *attr,char *buf) \
Alex Aizman0896b752005-08-04 19:33:07 -0700131{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100132 struct iscsi_internal *priv = dev_to_iscsi_internal(dev); \
Alex Aizman0896b752005-08-04 19:33:07 -0700133 return sprintf(buf, format"\n", priv->iscsi_transport->name); \
134} \
Tony Jonesee959b02008-02-22 00:13:36 +0100135static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
Alex Aizman0896b752005-08-04 19:33:07 -0700136
137show_transport_attr(caps, "0x%x");
Alex Aizman0896b752005-08-04 19:33:07 -0700138
139static struct attribute *iscsi_transport_attrs[] = {
Tony Jonesee959b02008-02-22 00:13:36 +0100140 &dev_attr_handle.attr,
141 &dev_attr_caps.attr,
Alex Aizman0896b752005-08-04 19:33:07 -0700142 NULL,
143};
144
145static struct attribute_group iscsi_transport_group = {
146 .attrs = iscsi_transport_attrs,
147};
148
Mike Christied82ff9be2008-05-21 15:54:13 -0500149/*
150 * iSCSI endpoint attrs
151 */
152#define iscsi_dev_to_endpoint(_dev) \
153 container_of(_dev, struct iscsi_endpoint, dev)
154
155#define ISCSI_ATTR(_prefix,_name,_mode,_show,_store) \
156struct device_attribute dev_attr_##_prefix##_##_name = \
157 __ATTR(_name,_mode,_show,_store)
158
159static void iscsi_endpoint_release(struct device *dev)
160{
161 struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
162 kfree(ep);
163}
164
165static struct class iscsi_endpoint_class = {
166 .name = "iscsi_endpoint",
167 .dev_release = iscsi_endpoint_release,
168};
169
170static ssize_t
171show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf)
172{
173 struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
Mike Christie21536062008-09-24 11:46:11 -0500174 return sprintf(buf, "%llu\n", (unsigned long long) ep->id);
Mike Christied82ff9be2008-05-21 15:54:13 -0500175}
176static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL);
177
178static struct attribute *iscsi_endpoint_attrs[] = {
179 &dev_attr_ep_handle.attr,
180 NULL,
181};
182
183static struct attribute_group iscsi_endpoint_group = {
184 .attrs = iscsi_endpoint_attrs,
185};
186
187#define ISCSI_MAX_EPID -1
188
189static int iscsi_match_epid(struct device *dev, void *data)
190{
191 struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
Mike Christie21536062008-09-24 11:46:11 -0500192 uint64_t *epid = (uint64_t *) data;
Mike Christied82ff9be2008-05-21 15:54:13 -0500193
194 return *epid == ep->id;
195}
196
197struct iscsi_endpoint *
198iscsi_create_endpoint(int dd_size)
199{
200 struct device *dev;
201 struct iscsi_endpoint *ep;
Mike Christie21536062008-09-24 11:46:11 -0500202 uint64_t id;
Mike Christied82ff9be2008-05-21 15:54:13 -0500203 int err;
204
205 for (id = 1; id < ISCSI_MAX_EPID; id++) {
Greg Kroah-Hartman695794a2008-05-22 17:21:08 -0400206 dev = class_find_device(&iscsi_endpoint_class, NULL, &id,
Mike Christied82ff9be2008-05-21 15:54:13 -0500207 iscsi_match_epid);
208 if (!dev)
209 break;
210 }
211 if (id == ISCSI_MAX_EPID) {
212 printk(KERN_ERR "Too many connections. Max supported %u\n",
213 ISCSI_MAX_EPID - 1);
214 return NULL;
215 }
216
217 ep = kzalloc(sizeof(*ep) + dd_size, GFP_KERNEL);
218 if (!ep)
219 return NULL;
220
221 ep->id = id;
222 ep->dev.class = &iscsi_endpoint_class;
Kay Sievers71610f52008-12-03 22:41:36 +0100223 dev_set_name(&ep->dev, "ep-%llu", (unsigned long long) id);
Mike Christied82ff9be2008-05-21 15:54:13 -0500224 err = device_register(&ep->dev);
225 if (err)
226 goto free_ep;
227
228 err = sysfs_create_group(&ep->dev.kobj, &iscsi_endpoint_group);
229 if (err)
230 goto unregister_dev;
231
232 if (dd_size)
233 ep->dd_data = &ep[1];
234 return ep;
235
236unregister_dev:
237 device_unregister(&ep->dev);
238 return NULL;
239
240free_ep:
241 kfree(ep);
242 return NULL;
243}
244EXPORT_SYMBOL_GPL(iscsi_create_endpoint);
245
246void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
247{
248 sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group);
249 device_unregister(&ep->dev);
250}
251EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint);
252
253struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
254{
Mike Christief80f8682008-06-16 10:11:35 -0500255 struct iscsi_endpoint *ep;
Mike Christied82ff9be2008-05-21 15:54:13 -0500256 struct device *dev;
257
Greg Kroah-Hartman695794a2008-05-22 17:21:08 -0400258 dev = class_find_device(&iscsi_endpoint_class, NULL, &handle,
Mike Christied82ff9be2008-05-21 15:54:13 -0500259 iscsi_match_epid);
260 if (!dev)
261 return NULL;
262
Mike Christief80f8682008-06-16 10:11:35 -0500263 ep = iscsi_dev_to_endpoint(dev);
264 /*
265 * we can drop this now because the interface will prevent
266 * removals and lookups from racing.
267 */
268 put_device(dev);
269 return ep;
Mike Christied82ff9be2008-05-21 15:54:13 -0500270}
271EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
272
Mike Christie8d079132011-07-25 13:48:40 -0500273/*
274 * Interface to display network param to sysfs
275 */
276
277static void iscsi_iface_release(struct device *dev)
278{
279 struct iscsi_iface *iface = iscsi_dev_to_iface(dev);
280 struct device *parent = iface->dev.parent;
281
282 kfree(iface);
283 put_device(parent);
284}
285
286
287static struct class iscsi_iface_class = {
288 .name = "iscsi_iface",
289 .dev_release = iscsi_iface_release,
290};
291
292#define ISCSI_IFACE_ATTR(_prefix, _name, _mode, _show, _store) \
293struct device_attribute dev_attr_##_prefix##_##_name = \
294 __ATTR(_name, _mode, _show, _store)
295
296/* iface attrs show */
297#define iscsi_iface_attr_show(type, name, param_type, param) \
298static ssize_t \
299show_##type##_##name(struct device *dev, struct device_attribute *attr, \
300 char *buf) \
301{ \
302 struct iscsi_iface *iface = iscsi_dev_to_iface(dev); \
303 struct iscsi_transport *t = iface->transport; \
304 return t->get_iface_param(iface, param_type, param, buf); \
305} \
306
307#define iscsi_iface_net_attr(type, name, param) \
308 iscsi_iface_attr_show(type, name, ISCSI_NET_PARAM, param) \
309static ISCSI_IFACE_ATTR(type, name, S_IRUGO, show_##type##_##name, NULL);
310
311/* generic read only ipvi4 attribute */
312iscsi_iface_net_attr(ipv4_iface, ipaddress, ISCSI_NET_PARAM_IPV4_ADDR);
313iscsi_iface_net_attr(ipv4_iface, gateway, ISCSI_NET_PARAM_IPV4_GW);
314iscsi_iface_net_attr(ipv4_iface, subnet, ISCSI_NET_PARAM_IPV4_SUBNET);
315iscsi_iface_net_attr(ipv4_iface, bootproto, ISCSI_NET_PARAM_IPV4_BOOTPROTO);
316
317/* generic read only ipv6 attribute */
318iscsi_iface_net_attr(ipv6_iface, ipaddress, ISCSI_NET_PARAM_IPV6_ADDR);
319iscsi_iface_net_attr(ipv6_iface, link_local_addr, ISCSI_NET_PARAM_IPV6_LINKLOCAL);
320iscsi_iface_net_attr(ipv6_iface, router_addr, ISCSI_NET_PARAM_IPV6_ROUTER);
321iscsi_iface_net_attr(ipv6_iface, ipaddr_autocfg,
322 ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG);
323iscsi_iface_net_attr(ipv6_iface, linklocal_autocfg,
324 ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG);
325
326/* common read only iface attribute */
327iscsi_iface_net_attr(iface, enabled, ISCSI_NET_PARAM_IFACE_ENABLE);
328iscsi_iface_net_attr(iface, vlan, ISCSI_NET_PARAM_VLAN_ID);
329
330static mode_t iscsi_iface_attr_is_visible(struct kobject *kobj,
331 struct attribute *attr, int i)
332{
333 struct device *dev = container_of(kobj, struct device, kobj);
334 struct iscsi_iface *iface = iscsi_dev_to_iface(dev);
335 struct iscsi_transport *t = iface->transport;
336
337 if (attr == &dev_attr_iface_enabled.attr)
338 return (t->iface_param_mask & ISCSI_NET_IFACE_ENABLE) ?
339 S_IRUGO : 0;
340 else if (attr == &dev_attr_iface_vlan.attr)
341 return (t->iface_param_mask & ISCSI_NET_VLAN_ID) ? S_IRUGO : 0;
342
343 if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
344 if (attr == &dev_attr_ipv4_iface_ipaddress.attr)
345 return (t->iface_param_mask & ISCSI_NET_IPV4_ADDR) ?
346 S_IRUGO : 0;
347 else if (attr == &dev_attr_ipv4_iface_gateway.attr)
348 return (t->iface_param_mask & ISCSI_NET_IPV4_GW) ?
349 S_IRUGO : 0;
350 else if (attr == &dev_attr_ipv4_iface_subnet.attr)
351 return (t->iface_param_mask & ISCSI_NET_IPV4_SUBNET) ?
352 S_IRUGO : 0;
353 else if (attr == &dev_attr_ipv4_iface_bootproto.attr)
354 return (t->iface_param_mask & ISCSI_NET_IPV4_BOOTPROTO) ?
355 S_IRUGO : 0;
356 } else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) {
357 if (attr == &dev_attr_ipv6_iface_ipaddress.attr)
358 return (t->iface_param_mask & ISCSI_NET_IPV6_ADDR) ?
359 S_IRUGO : 0;
360 else if (attr == &dev_attr_ipv6_iface_link_local_addr.attr)
361 return (t->iface_param_mask & ISCSI_NET_IPV6_LINKLOCAL) ?
362 S_IRUGO : 0;
363 else if (attr == &dev_attr_ipv6_iface_router_addr.attr)
364 return (t->iface_param_mask & ISCSI_NET_IPV6_ROUTER) ?
365 S_IRUGO : 0;
366 else if (attr == &dev_attr_ipv6_iface_ipaddr_autocfg.attr)
367 return (t->iface_param_mask & ISCSI_NET_IPV6_ADDR_AUTOCFG) ?
368 S_IRUGO : 0;
369 else if (attr == &dev_attr_ipv6_iface_linklocal_autocfg.attr)
370 return (t->iface_param_mask & ISCSI_NET_IPV6_LINKLOCAL_AUTOCFG) ?
371 S_IRUGO : 0;
372 }
373
374 return 0;
375}
376
377static struct attribute *iscsi_iface_attrs[] = {
378 &dev_attr_iface_enabled.attr,
379 &dev_attr_iface_vlan.attr,
380 &dev_attr_ipv4_iface_ipaddress.attr,
381 &dev_attr_ipv4_iface_gateway.attr,
382 &dev_attr_ipv4_iface_subnet.attr,
383 &dev_attr_ipv4_iface_bootproto.attr,
384 &dev_attr_ipv6_iface_ipaddress.attr,
385 &dev_attr_ipv6_iface_link_local_addr.attr,
386 &dev_attr_ipv6_iface_router_addr.attr,
387 &dev_attr_ipv6_iface_ipaddr_autocfg.attr,
388 &dev_attr_ipv6_iface_linklocal_autocfg.attr,
389 NULL,
390};
391
392static struct attribute_group iscsi_iface_group = {
393 .attrs = iscsi_iface_attrs,
394 .is_visible = iscsi_iface_attr_is_visible,
395};
396
397struct iscsi_iface *
398iscsi_create_iface(struct Scsi_Host *shost, struct iscsi_transport *transport,
399 uint32_t iface_type, uint32_t iface_num, int dd_size)
400{
401 struct iscsi_iface *iface;
402 int err;
403
404 iface = kzalloc(sizeof(*iface) + dd_size, GFP_KERNEL);
405 if (!iface)
406 return NULL;
407
408 iface->transport = transport;
409 iface->iface_type = iface_type;
410 iface->iface_num = iface_num;
411 iface->dev.release = iscsi_iface_release;
412 iface->dev.class = &iscsi_iface_class;
413 /* parent reference released in iscsi_iface_release */
414 iface->dev.parent = get_device(&shost->shost_gendev);
415 if (iface_type == ISCSI_IFACE_TYPE_IPV4)
416 dev_set_name(&iface->dev, "ipv4-iface-%u-%u", shost->host_no,
417 iface_num);
418 else
419 dev_set_name(&iface->dev, "ipv6-iface-%u-%u", shost->host_no,
420 iface_num);
421
422 err = device_register(&iface->dev);
423 if (err)
424 goto free_iface;
425
426 err = sysfs_create_group(&iface->dev.kobj, &iscsi_iface_group);
427 if (err)
428 goto unreg_iface;
429
430 if (dd_size)
431 iface->dd_data = &iface[1];
432 return iface;
433
434unreg_iface:
435 device_unregister(&iface->dev);
436 return NULL;
437
438free_iface:
439 put_device(iface->dev.parent);
440 kfree(iface);
441 return NULL;
442}
443EXPORT_SYMBOL_GPL(iscsi_create_iface);
444
445void iscsi_destroy_iface(struct iscsi_iface *iface)
446{
447 sysfs_remove_group(&iface->dev.kobj, &iscsi_iface_group);
448 device_unregister(&iface->dev);
449}
450EXPORT_SYMBOL_GPL(iscsi_destroy_iface);
451
Mike Christie30a6c652006-04-06 21:13:39 -0500452static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
Tony Jonesee959b02008-02-22 00:13:36 +0100453 struct device *cdev)
Mike Christie30a6c652006-04-06 21:13:39 -0500454{
455 struct Scsi_Host *shost = dev_to_shost(dev);
Mike Christie32c6e1b2008-05-21 15:53:58 -0500456 struct iscsi_cls_host *ihost = shost->shost_data;
Mike Christie30a6c652006-04-06 21:13:39 -0500457
458 memset(ihost, 0, sizeof(*ihost));
Mike Christie8aae18a2008-01-31 13:36:48 -0600459 atomic_set(&ihost->nr_scans, 0);
Mike Christie79706342008-05-21 15:54:12 -0500460 mutex_init(&ihost->mutex);
Mike Christie30a6c652006-04-06 21:13:39 -0500461 return 0;
462}
463
464static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
465 "iscsi_host",
466 iscsi_setup_host,
Mike Christie06d25af2009-03-05 14:46:02 -0600467 NULL,
Mike Christie30a6c652006-04-06 21:13:39 -0500468 NULL);
469
Alex Aizman0896b752005-08-04 19:33:07 -0700470static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
471 "iscsi_session",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 NULL,
473 NULL,
474 NULL);
475
Alex Aizman0896b752005-08-04 19:33:07 -0700476static DECLARE_TRANSPORT_CLASS(iscsi_connection_class,
477 "iscsi_connection",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 NULL,
479 NULL,
480 NULL);
Alex Aizman0896b752005-08-04 19:33:07 -0700481
482static struct sock *nls;
Arjan van de Ven0b950672006-01-11 13:16:10 +0100483static DEFINE_MUTEX(rx_queue_mutex);
Alex Aizman0896b752005-08-04 19:33:07 -0700484
Mike Christie7b7232f2006-02-01 21:06:49 -0600485static LIST_HEAD(sesslist);
486static DEFINE_SPINLOCK(sesslock);
Alex Aizman0896b752005-08-04 19:33:07 -0700487static LIST_HEAD(connlist);
488static DEFINE_SPINLOCK(connlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Mike Christieb5c7a122006-04-06 21:13:33 -0500490static uint32_t iscsi_conn_get_sid(struct iscsi_cls_conn *conn)
491{
492 struct iscsi_cls_session *sess = iscsi_dev_to_session(conn->dev.parent);
493 return sess->sid;
494}
495
496/*
497 * Returns the matching session to a given sid
498 */
499static struct iscsi_cls_session *iscsi_session_lookup(uint32_t sid)
Mike Christie7b7232f2006-02-01 21:06:49 -0600500{
501 unsigned long flags;
502 struct iscsi_cls_session *sess;
503
504 spin_lock_irqsave(&sesslock, flags);
505 list_for_each_entry(sess, &sesslist, sess_list) {
Mike Christieb5c7a122006-04-06 21:13:33 -0500506 if (sess->sid == sid) {
Mike Christie7b7232f2006-02-01 21:06:49 -0600507 spin_unlock_irqrestore(&sesslock, flags);
508 return sess;
509 }
510 }
511 spin_unlock_irqrestore(&sesslock, flags);
512 return NULL;
513}
514
Mike Christieb5c7a122006-04-06 21:13:33 -0500515/*
516 * Returns the matching connection to a given sid / cid tuple
517 */
518static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid)
Mike Christie7b7232f2006-02-01 21:06:49 -0600519{
520 unsigned long flags;
521 struct iscsi_cls_conn *conn;
522
523 spin_lock_irqsave(&connlock, flags);
524 list_for_each_entry(conn, &connlist, conn_list) {
Mike Christieb5c7a122006-04-06 21:13:33 -0500525 if ((conn->cid == cid) && (iscsi_conn_get_sid(conn) == sid)) {
Mike Christie7b7232f2006-02-01 21:06:49 -0600526 spin_unlock_irqrestore(&connlock, flags);
527 return conn;
528 }
529 }
530 spin_unlock_irqrestore(&connlock, flags);
531 return NULL;
532}
533
Mike Christie7b8631b2006-01-13 18:05:50 -0600534/*
535 * The following functions can be used by LLDs that allocate
536 * their own scsi_hosts or by software iscsi LLDs
537 */
Mike Christie6eabafb2008-01-31 13:36:43 -0600538static struct {
539 int value;
540 char *name;
541} iscsi_session_state_names[] = {
542 { ISCSI_SESSION_LOGGED_IN, "LOGGED_IN" },
543 { ISCSI_SESSION_FAILED, "FAILED" },
544 { ISCSI_SESSION_FREE, "FREE" },
545};
546
Adrian Bunk3b0f2082008-02-13 23:30:17 +0200547static const char *iscsi_session_state_name(int state)
Mike Christie6eabafb2008-01-31 13:36:43 -0600548{
549 int i;
550 char *name = NULL;
551
552 for (i = 0; i < ARRAY_SIZE(iscsi_session_state_names); i++) {
553 if (iscsi_session_state_names[i].value == state) {
554 name = iscsi_session_state_names[i].name;
555 break;
556 }
557 }
558 return name;
559}
560
561int iscsi_session_chkready(struct iscsi_cls_session *session)
562{
563 unsigned long flags;
564 int err;
565
566 spin_lock_irqsave(&session->lock, flags);
567 switch (session->state) {
568 case ISCSI_SESSION_LOGGED_IN:
569 err = 0;
570 break;
571 case ISCSI_SESSION_FAILED:
Andrew Vasquez9a1a69a12009-04-29 13:12:39 -0500572 err = DID_IMM_RETRY << 16;
Mike Christie6eabafb2008-01-31 13:36:43 -0600573 break;
574 case ISCSI_SESSION_FREE:
Mike Christie56d7fcf2008-08-19 18:45:26 -0500575 err = DID_TRANSPORT_FAILFAST << 16;
Mike Christie6eabafb2008-01-31 13:36:43 -0600576 break;
577 default:
578 err = DID_NO_CONNECT << 16;
579 break;
580 }
581 spin_unlock_irqrestore(&session->lock, flags);
582 return err;
583}
584EXPORT_SYMBOL_GPL(iscsi_session_chkready);
585
Mike Christie7b8631b2006-01-13 18:05:50 -0600586static void iscsi_session_release(struct device *dev)
587{
588 struct iscsi_cls_session *session = iscsi_dev_to_session(dev);
Mike Christie7b8631b2006-01-13 18:05:50 -0600589 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Mike Christie7b8631b2006-01-13 18:05:50 -0600591 shost = iscsi_session_to_shost(session);
592 scsi_host_put(shost);
Mike Christie632248a2009-08-20 15:11:01 -0500593 ISCSI_DBG_TRANS_SESSION(session, "Completing session release\n");
Mike Christie7b8631b2006-01-13 18:05:50 -0600594 kfree(session);
Mike Christie7b8631b2006-01-13 18:05:50 -0600595}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Mike Christie7b8631b2006-01-13 18:05:50 -0600597static int iscsi_is_session_dev(const struct device *dev)
598{
599 return dev->release == iscsi_session_release;
600}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Mike Christiea4804cd2008-05-21 15:54:00 -0500602static int iscsi_iter_session_fn(struct device *dev, void *data)
603{
604 void (* fn) (struct iscsi_cls_session *) = data;
605
606 if (!iscsi_is_session_dev(dev))
607 return 0;
608 fn(iscsi_dev_to_session(dev));
609 return 0;
610}
611
612void iscsi_host_for_each_session(struct Scsi_Host *shost,
613 void (*fn)(struct iscsi_cls_session *))
614{
615 device_for_each_child(&shost->shost_gendev, fn,
616 iscsi_iter_session_fn);
617}
618EXPORT_SYMBOL_GPL(iscsi_host_for_each_session);
619
Mike Christie8aae18a2008-01-31 13:36:48 -0600620/**
621 * iscsi_scan_finished - helper to report when running scans are done
622 * @shost: scsi host
623 * @time: scan run time
624 *
625 * This function can be used by drives like qla4xxx to report to the scsi
626 * layer when the scans it kicked off at module load time are done.
627 */
628int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time)
629{
Mike Christie32c6e1b2008-05-21 15:53:58 -0500630 struct iscsi_cls_host *ihost = shost->shost_data;
Mike Christie8aae18a2008-01-31 13:36:48 -0600631 /*
632 * qla4xxx will have kicked off some session unblocks before calling
633 * scsi_scan_host, so just wait for them to complete.
634 */
635 return !atomic_read(&ihost->nr_scans);
636}
637EXPORT_SYMBOL_GPL(iscsi_scan_finished);
638
Mike Christie79706342008-05-21 15:54:12 -0500639struct iscsi_scan_data {
640 unsigned int channel;
641 unsigned int id;
642 unsigned int lun;
643};
644
645static int iscsi_user_scan_session(struct device *dev, void *data)
646{
647 struct iscsi_scan_data *scan_data = data;
648 struct iscsi_cls_session *session;
649 struct Scsi_Host *shost;
650 struct iscsi_cls_host *ihost;
651 unsigned long flags;
652 unsigned int id;
653
654 if (!iscsi_is_session_dev(dev))
655 return 0;
656
657 session = iscsi_dev_to_session(dev);
Mike Christie632248a2009-08-20 15:11:01 -0500658
659 ISCSI_DBG_TRANS_SESSION(session, "Scanning session\n");
660
Mike Christie79706342008-05-21 15:54:12 -0500661 shost = iscsi_session_to_shost(session);
662 ihost = shost->shost_data;
663
664 mutex_lock(&ihost->mutex);
665 spin_lock_irqsave(&session->lock, flags);
666 if (session->state != ISCSI_SESSION_LOGGED_IN) {
667 spin_unlock_irqrestore(&session->lock, flags);
Mike Christie632248a2009-08-20 15:11:01 -0500668 goto user_scan_exit;
Mike Christie79706342008-05-21 15:54:12 -0500669 }
670 id = session->target_id;
671 spin_unlock_irqrestore(&session->lock, flags);
672
673 if (id != ISCSI_MAX_TARGET) {
674 if ((scan_data->channel == SCAN_WILD_CARD ||
675 scan_data->channel == 0) &&
676 (scan_data->id == SCAN_WILD_CARD ||
677 scan_data->id == id))
678 scsi_scan_target(&session->dev, 0, id,
679 scan_data->lun, 1);
680 }
Mike Christie632248a2009-08-20 15:11:01 -0500681
682user_scan_exit:
Mike Christie79706342008-05-21 15:54:12 -0500683 mutex_unlock(&ihost->mutex);
Mike Christie632248a2009-08-20 15:11:01 -0500684 ISCSI_DBG_TRANS_SESSION(session, "Completed session scan\n");
Mike Christie79706342008-05-21 15:54:12 -0500685 return 0;
686}
687
Mike Christie30a6c652006-04-06 21:13:39 -0500688static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
689 uint id, uint lun)
690{
Mike Christie79706342008-05-21 15:54:12 -0500691 struct iscsi_scan_data scan_data;
Mike Christie30a6c652006-04-06 21:13:39 -0500692
Mike Christie79706342008-05-21 15:54:12 -0500693 scan_data.channel = channel;
694 scan_data.id = id;
695 scan_data.lun = lun;
Mike Christie30a6c652006-04-06 21:13:39 -0500696
Mike Christie79706342008-05-21 15:54:12 -0500697 return device_for_each_child(&shost->shost_gendev, &scan_data,
698 iscsi_user_scan_session);
Mike Christie30a6c652006-04-06 21:13:39 -0500699}
700
Mike Christiebd976f62008-01-31 13:36:46 -0600701static void iscsi_scan_session(struct work_struct *work)
702{
703 struct iscsi_cls_session *session =
704 container_of(work, struct iscsi_cls_session, scan_work);
Mike Christie8aae18a2008-01-31 13:36:48 -0600705 struct Scsi_Host *shost = iscsi_session_to_shost(session);
Mike Christie32c6e1b2008-05-21 15:53:58 -0500706 struct iscsi_cls_host *ihost = shost->shost_data;
Mike Christie79706342008-05-21 15:54:12 -0500707 struct iscsi_scan_data scan_data;
Mike Christiebd976f62008-01-31 13:36:46 -0600708
Mike Christie79706342008-05-21 15:54:12 -0500709 scan_data.channel = 0;
710 scan_data.id = SCAN_WILD_CARD;
711 scan_data.lun = SCAN_WILD_CARD;
Mike Christiebd976f62008-01-31 13:36:46 -0600712
Mike Christie79706342008-05-21 15:54:12 -0500713 iscsi_user_scan_session(&session->dev, &scan_data);
Mike Christie8aae18a2008-01-31 13:36:48 -0600714 atomic_dec(&ihost->nr_scans);
Mike Christiebd976f62008-01-31 13:36:46 -0600715}
716
Mike Christiec01be6d2010-07-22 16:59:49 +0530717/**
718 * iscsi_block_scsi_eh - block scsi eh until session state has transistioned
Randy Dunlape6d4ef42010-08-14 13:05:41 -0700719 * @cmd: scsi cmd passed to scsi eh handler
Mike Christiec01be6d2010-07-22 16:59:49 +0530720 *
721 * If the session is down this function will wait for the recovery
722 * timer to fire or for the session to be logged back in. If the
723 * recovery timer fires then FAST_IO_FAIL is returned. The caller
724 * should pass this error value to the scsi eh.
725 */
726int iscsi_block_scsi_eh(struct scsi_cmnd *cmd)
727{
728 struct iscsi_cls_session *session =
729 starget_to_session(scsi_target(cmd->device));
730 unsigned long flags;
731 int ret = 0;
732
733 spin_lock_irqsave(&session->lock, flags);
734 while (session->state != ISCSI_SESSION_LOGGED_IN) {
735 if (session->state == ISCSI_SESSION_FREE) {
736 ret = FAST_IO_FAIL;
737 break;
738 }
739 spin_unlock_irqrestore(&session->lock, flags);
740 msleep(1000);
741 spin_lock_irqsave(&session->lock, flags);
742 }
743 spin_unlock_irqrestore(&session->lock, flags);
744 return ret;
745}
746EXPORT_SYMBOL_GPL(iscsi_block_scsi_eh);
747
David Howellsc4028952006-11-22 14:57:56 +0000748static void session_recovery_timedout(struct work_struct *work)
Mike Christie30a6c652006-04-06 21:13:39 -0500749{
David Howellsc4028952006-11-22 14:57:56 +0000750 struct iscsi_cls_session *session =
751 container_of(work, struct iscsi_cls_session,
752 recovery_work.work);
Mike Christie6eabafb2008-01-31 13:36:43 -0600753 unsigned long flags;
Mike Christie30a6c652006-04-06 21:13:39 -0500754
Mike Christie322d7392008-01-31 13:36:52 -0600755 iscsi_cls_session_printk(KERN_INFO, session,
756 "session recovery timed out after %d secs\n",
757 session->recovery_tmo);
Mike Christie30a6c652006-04-06 21:13:39 -0500758
Mike Christie6eabafb2008-01-31 13:36:43 -0600759 spin_lock_irqsave(&session->lock, flags);
760 switch (session->state) {
761 case ISCSI_SESSION_FAILED:
762 session->state = ISCSI_SESSION_FREE;
763 break;
764 case ISCSI_SESSION_LOGGED_IN:
765 case ISCSI_SESSION_FREE:
766 /* we raced with the unblock's flush */
767 spin_unlock_irqrestore(&session->lock, flags);
768 return;
769 }
770 spin_unlock_irqrestore(&session->lock, flags);
771
Mike Christie30a6c652006-04-06 21:13:39 -0500772 if (session->transport->session_recovery_timedout)
773 session->transport->session_recovery_timedout(session);
774
Mike Christie632248a2009-08-20 15:11:01 -0500775 ISCSI_DBG_TRANS_SESSION(session, "Unblocking SCSI target\n");
Mike Christie30a6c652006-04-06 21:13:39 -0500776 scsi_target_unblock(&session->dev);
Mike Christie632248a2009-08-20 15:11:01 -0500777 ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking SCSI target\n");
Mike Christie30a6c652006-04-06 21:13:39 -0500778}
779
Mike Christie45ab33b2008-03-04 13:26:55 -0600780static void __iscsi_unblock_session(struct work_struct *work)
Mike Christie30a6c652006-04-06 21:13:39 -0500781{
Mike Christie45ab33b2008-03-04 13:26:55 -0600782 struct iscsi_cls_session *session =
783 container_of(work, struct iscsi_cls_session,
784 unblock_work);
Mike Christiebd976f62008-01-31 13:36:46 -0600785 struct Scsi_Host *shost = iscsi_session_to_shost(session);
Mike Christie32c6e1b2008-05-21 15:53:58 -0500786 struct iscsi_cls_host *ihost = shost->shost_data;
Mike Christie6eabafb2008-01-31 13:36:43 -0600787 unsigned long flags;
788
Mike Christie632248a2009-08-20 15:11:01 -0500789 ISCSI_DBG_TRANS_SESSION(session, "Unblocking session\n");
Mike Christie45ab33b2008-03-04 13:26:55 -0600790 /*
791 * The recovery and unblock work get run from the same workqueue,
792 * so try to cancel it if it was going to run after this unblock.
793 */
794 cancel_delayed_work(&session->recovery_work);
Mike Christie6eabafb2008-01-31 13:36:43 -0600795 spin_lock_irqsave(&session->lock, flags);
796 session->state = ISCSI_SESSION_LOGGED_IN;
797 spin_unlock_irqrestore(&session->lock, flags);
Mike Christie45ab33b2008-03-04 13:26:55 -0600798 /* start IO */
799 scsi_target_unblock(&session->dev);
Mike Christie8aae18a2008-01-31 13:36:48 -0600800 /*
801 * Only do kernel scanning if the driver is properly hooked into
802 * the async scanning code (drivers like iscsi_tcp do login and
803 * scanning from userspace).
804 */
805 if (shost->hostt->scan_finished) {
Mike Christie06d25af2009-03-05 14:46:02 -0600806 if (scsi_queue_work(shost, &session->scan_work))
Mike Christie8aae18a2008-01-31 13:36:48 -0600807 atomic_inc(&ihost->nr_scans);
808 }
Mike Christie632248a2009-08-20 15:11:01 -0500809 ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking session\n");
Mike Christie6eabafb2008-01-31 13:36:43 -0600810}
Mike Christie45ab33b2008-03-04 13:26:55 -0600811
812/**
813 * iscsi_unblock_session - set a session as logged in and start IO.
814 * @session: iscsi session
815 *
816 * Mark a session as ready to accept IO.
817 */
818void iscsi_unblock_session(struct iscsi_cls_session *session)
819{
820 queue_work(iscsi_eh_timer_workq, &session->unblock_work);
821 /*
822 * make sure all the events have completed before tell the driver
823 * it is safe
824 */
825 flush_workqueue(iscsi_eh_timer_workq);
826}
Mike Christie30a6c652006-04-06 21:13:39 -0500827EXPORT_SYMBOL_GPL(iscsi_unblock_session);
828
Mike Christie45ab33b2008-03-04 13:26:55 -0600829static void __iscsi_block_session(struct work_struct *work)
Mike Christie30a6c652006-04-06 21:13:39 -0500830{
Mike Christie45ab33b2008-03-04 13:26:55 -0600831 struct iscsi_cls_session *session =
832 container_of(work, struct iscsi_cls_session,
833 block_work);
Mike Christie6eabafb2008-01-31 13:36:43 -0600834 unsigned long flags;
835
Mike Christie632248a2009-08-20 15:11:01 -0500836 ISCSI_DBG_TRANS_SESSION(session, "Blocking session\n");
Mike Christie6eabafb2008-01-31 13:36:43 -0600837 spin_lock_irqsave(&session->lock, flags);
838 session->state = ISCSI_SESSION_FAILED;
839 spin_unlock_irqrestore(&session->lock, flags);
Mike Christie30a6c652006-04-06 21:13:39 -0500840 scsi_target_block(&session->dev);
Mike Christie632248a2009-08-20 15:11:01 -0500841 ISCSI_DBG_TRANS_SESSION(session, "Completed SCSI target blocking\n");
Mike Christiefdd46dc2009-11-11 16:34:34 -0600842 if (session->recovery_tmo >= 0)
843 queue_delayed_work(iscsi_eh_timer_workq,
844 &session->recovery_work,
845 session->recovery_tmo * HZ);
Mike Christie30a6c652006-04-06 21:13:39 -0500846}
Mike Christie45ab33b2008-03-04 13:26:55 -0600847
848void iscsi_block_session(struct iscsi_cls_session *session)
849{
850 queue_work(iscsi_eh_timer_workq, &session->block_work);
851}
Mike Christie30a6c652006-04-06 21:13:39 -0500852EXPORT_SYMBOL_GPL(iscsi_block_session);
853
Mike Christie26974782007-12-13 12:43:29 -0600854static void __iscsi_unbind_session(struct work_struct *work)
855{
856 struct iscsi_cls_session *session =
857 container_of(work, struct iscsi_cls_session,
858 unbind_work);
859 struct Scsi_Host *shost = iscsi_session_to_shost(session);
Mike Christie32c6e1b2008-05-21 15:53:58 -0500860 struct iscsi_cls_host *ihost = shost->shost_data;
Mike Christie79706342008-05-21 15:54:12 -0500861 unsigned long flags;
Mike Christie26974782007-12-13 12:43:29 -0600862
Mike Christie632248a2009-08-20 15:11:01 -0500863 ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n");
864
Mike Christie26974782007-12-13 12:43:29 -0600865 /* Prevent new scans and make sure scanning is not in progress */
866 mutex_lock(&ihost->mutex);
Mike Christie79706342008-05-21 15:54:12 -0500867 spin_lock_irqsave(&session->lock, flags);
868 if (session->target_id == ISCSI_MAX_TARGET) {
869 spin_unlock_irqrestore(&session->lock, flags);
Mike Christie26974782007-12-13 12:43:29 -0600870 mutex_unlock(&ihost->mutex);
871 return;
872 }
Mike Christie79706342008-05-21 15:54:12 -0500873 session->target_id = ISCSI_MAX_TARGET;
874 spin_unlock_irqrestore(&session->lock, flags);
Mike Christie26974782007-12-13 12:43:29 -0600875 mutex_unlock(&ihost->mutex);
876
877 scsi_remove_target(&session->dev);
878 iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
Mike Christie632248a2009-08-20 15:11:01 -0500879 ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n");
Mike Christie26974782007-12-13 12:43:29 -0600880}
881
Mike Christie7b8631b2006-01-13 18:05:50 -0600882struct iscsi_cls_session *
Mike Christie5d91e202008-05-21 15:54:01 -0500883iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
884 int dd_size)
Mike Christie7b8631b2006-01-13 18:05:50 -0600885{
886 struct iscsi_cls_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
Mike Christie5d91e202008-05-21 15:54:01 -0500888 session = kzalloc(sizeof(*session) + dd_size,
Mike Christieb5c7a122006-04-06 21:13:33 -0500889 GFP_KERNEL);
Mike Christie7b8631b2006-01-13 18:05:50 -0600890 if (!session)
Mike Christief53a88d2006-06-28 12:00:27 -0500891 return NULL;
892
Mike Christie7b8631b2006-01-13 18:05:50 -0600893 session->transport = transport;
Mike Christie30a6c652006-04-06 21:13:39 -0500894 session->recovery_tmo = 120;
Mike Christie6eabafb2008-01-31 13:36:43 -0600895 session->state = ISCSI_SESSION_FREE;
David Howellsc4028952006-11-22 14:57:56 +0000896 INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
Mike Christie30a6c652006-04-06 21:13:39 -0500897 INIT_LIST_HEAD(&session->sess_list);
Mike Christie45ab33b2008-03-04 13:26:55 -0600898 INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
899 INIT_WORK(&session->block_work, __iscsi_block_session);
Mike Christie26974782007-12-13 12:43:29 -0600900 INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
Mike Christiebd976f62008-01-31 13:36:46 -0600901 INIT_WORK(&session->scan_work, iscsi_scan_session);
Mike Christie6eabafb2008-01-31 13:36:43 -0600902 spin_lock_init(&session->lock);
Mike Christie7b8631b2006-01-13 18:05:50 -0600903
Mike Christie6a8a0d32006-06-28 12:00:31 -0500904 /* this is released in the dev's release function */
905 scsi_host_get(shost);
Mike Christie8434aa82006-06-28 12:00:30 -0500906 session->dev.parent = &shost->shost_gendev;
907 session->dev.release = iscsi_session_release;
908 device_initialize(&session->dev);
Mike Christie5d91e202008-05-21 15:54:01 -0500909 if (dd_size)
Mike Christieb5c7a122006-04-06 21:13:33 -0500910 session->dd_data = &session[1];
Mike Christie632248a2009-08-20 15:11:01 -0500911
912 ISCSI_DBG_TRANS_SESSION(session, "Completed session allocation\n");
Mike Christie8434aa82006-06-28 12:00:30 -0500913 return session;
914}
915EXPORT_SYMBOL_GPL(iscsi_alloc_session);
916
Mike Christie79706342008-05-21 15:54:12 -0500917static int iscsi_get_next_target_id(struct device *dev, void *data)
918{
919 struct iscsi_cls_session *session;
920 unsigned long flags;
921 int err = 0;
922
923 if (!iscsi_is_session_dev(dev))
924 return 0;
925
926 session = iscsi_dev_to_session(dev);
927 spin_lock_irqsave(&session->lock, flags);
928 if (*((unsigned int *) data) == session->target_id)
929 err = -EEXIST;
930 spin_unlock_irqrestore(&session->lock, flags);
931 return err;
932}
933
Mike Christie6a8a0d32006-06-28 12:00:31 -0500934int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
Mike Christie8434aa82006-06-28 12:00:30 -0500935{
936 struct Scsi_Host *shost = iscsi_session_to_shost(session);
Mike Christie32c6e1b2008-05-21 15:53:58 -0500937 struct iscsi_cls_host *ihost;
Mike Christie26974782007-12-13 12:43:29 -0600938 unsigned long flags;
Mike Christie79706342008-05-21 15:54:12 -0500939 unsigned int id = target_id;
Mike Christie8434aa82006-06-28 12:00:30 -0500940 int err;
Mike Christieb5c7a122006-04-06 21:13:33 -0500941
Mike Christie30a6c652006-04-06 21:13:39 -0500942 ihost = shost->shost_data;
Mike Christie41be1442007-02-28 17:32:18 -0600943 session->sid = atomic_add_return(1, &iscsi_session_nr);
Mike Christie79706342008-05-21 15:54:12 -0500944
945 if (id == ISCSI_MAX_TARGET) {
946 for (id = 0; id < ISCSI_MAX_TARGET; id++) {
947 err = device_for_each_child(&shost->shost_gendev, &id,
948 iscsi_get_next_target_id);
949 if (!err)
950 break;
951 }
952
953 if (id == ISCSI_MAX_TARGET) {
954 iscsi_cls_session_printk(KERN_ERR, session,
955 "Too many iscsi targets. Max "
956 "number of targets is %d.\n",
957 ISCSI_MAX_TARGET - 1);
Jaswinder Singh Rajput24add1c2009-06-20 13:29:21 +0530958 err = -EOVERFLOW;
Mike Christie79706342008-05-21 15:54:12 -0500959 goto release_host;
960 }
961 }
962 session->target_id = id;
Mike Christie30a6c652006-04-06 21:13:39 -0500963
Kay Sievers71610f52008-12-03 22:41:36 +0100964 dev_set_name(&session->dev, "session%u", session->sid);
Mike Christie8434aa82006-06-28 12:00:30 -0500965 err = device_add(&session->dev);
Mike Christie7b8631b2006-01-13 18:05:50 -0600966 if (err) {
Mike Christie322d7392008-01-31 13:36:52 -0600967 iscsi_cls_session_printk(KERN_ERR, session,
968 "could not register session's dev\n");
Mike Christie8434aa82006-06-28 12:00:30 -0500969 goto release_host;
Mike Christie7b8631b2006-01-13 18:05:50 -0600970 }
971 transport_register_device(&session->dev);
972
Mike Christie26974782007-12-13 12:43:29 -0600973 spin_lock_irqsave(&sesslock, flags);
974 list_add(&session->sess_list, &sesslist);
975 spin_unlock_irqrestore(&sesslock, flags);
976
Mike Christie26974782007-12-13 12:43:29 -0600977 iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
Mike Christie632248a2009-08-20 15:11:01 -0500978 ISCSI_DBG_TRANS_SESSION(session, "Completed session adding\n");
Mike Christie8434aa82006-06-28 12:00:30 -0500979 return 0;
Mike Christie30a6c652006-04-06 21:13:39 -0500980
Mike Christie8434aa82006-06-28 12:00:30 -0500981release_host:
982 scsi_host_put(shost);
983 return err;
Mike Christie7b8631b2006-01-13 18:05:50 -0600984}
Mike Christie8434aa82006-06-28 12:00:30 -0500985EXPORT_SYMBOL_GPL(iscsi_add_session);
Mike Christie7b8631b2006-01-13 18:05:50 -0600986
987/**
Mike Christie8434aa82006-06-28 12:00:30 -0500988 * iscsi_create_session - create iscsi class session
989 * @shost: scsi host
990 * @transport: iscsi transport
Mike Christie5d91e202008-05-21 15:54:01 -0500991 * @dd_size: private driver data size
Rob Landleyeb448202007-11-03 13:30:39 -0500992 * @target_id: which target
Mike Christie7b8631b2006-01-13 18:05:50 -0600993 *
Mike Christie8434aa82006-06-28 12:00:30 -0500994 * This can be called from a LLD or iscsi_transport.
Rob Landleyeb448202007-11-03 13:30:39 -0500995 */
Mike Christie8434aa82006-06-28 12:00:30 -0500996struct iscsi_cls_session *
Mike Christie5d91e202008-05-21 15:54:01 -0500997iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
998 int dd_size, unsigned int target_id)
Mike Christie8434aa82006-06-28 12:00:30 -0500999{
1000 struct iscsi_cls_session *session;
1001
Mike Christie5d91e202008-05-21 15:54:01 -05001002 session = iscsi_alloc_session(shost, transport, dd_size);
Mike Christie8434aa82006-06-28 12:00:30 -05001003 if (!session)
1004 return NULL;
1005
Mike Christie6a8a0d32006-06-28 12:00:31 -05001006 if (iscsi_add_session(session, target_id)) {
Mike Christie8434aa82006-06-28 12:00:30 -05001007 iscsi_free_session(session);
1008 return NULL;
1009 }
1010 return session;
1011}
1012EXPORT_SYMBOL_GPL(iscsi_create_session);
1013
Mike Christie26974782007-12-13 12:43:29 -06001014static void iscsi_conn_release(struct device *dev)
1015{
1016 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
1017 struct device *parent = conn->dev.parent;
1018
Mike Christie632248a2009-08-20 15:11:01 -05001019 ISCSI_DBG_TRANS_CONN(conn, "Releasing conn\n");
Mike Christie26974782007-12-13 12:43:29 -06001020 kfree(conn);
1021 put_device(parent);
1022}
1023
1024static int iscsi_is_conn_dev(const struct device *dev)
1025{
1026 return dev->release == iscsi_conn_release;
1027}
1028
1029static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
1030{
1031 if (!iscsi_is_conn_dev(dev))
1032 return 0;
1033 return iscsi_destroy_conn(iscsi_dev_to_conn(dev));
1034}
1035
Mike Christie8434aa82006-06-28 12:00:30 -05001036void iscsi_remove_session(struct iscsi_cls_session *session)
Mike Christie7b8631b2006-01-13 18:05:50 -06001037{
Mike Christie30a6c652006-04-06 21:13:39 -05001038 struct Scsi_Host *shost = iscsi_session_to_shost(session);
Mike Christie26974782007-12-13 12:43:29 -06001039 unsigned long flags;
1040 int err;
Mike Christie30a6c652006-04-06 21:13:39 -05001041
Mike Christie632248a2009-08-20 15:11:01 -05001042 ISCSI_DBG_TRANS_SESSION(session, "Removing session\n");
1043
Mike Christie26974782007-12-13 12:43:29 -06001044 spin_lock_irqsave(&sesslock, flags);
1045 list_del(&session->sess_list);
1046 spin_unlock_irqrestore(&sesslock, flags);
1047
Mike Christie45ab33b2008-03-04 13:26:55 -06001048 /* make sure there are no blocks/unblocks queued */
1049 flush_workqueue(iscsi_eh_timer_workq);
1050 /* make sure the timedout callout is not running */
1051 if (!cancel_delayed_work(&session->recovery_work))
1052 flush_workqueue(iscsi_eh_timer_workq);
Mike Christie26974782007-12-13 12:43:29 -06001053 /*
1054 * If we are blocked let commands flow again. The lld or iscsi
1055 * layer should set up the queuecommand to fail commands.
Mike Christie45ab33b2008-03-04 13:26:55 -06001056 * We assume that LLD will not be calling block/unblock while
1057 * removing the session.
Mike Christie26974782007-12-13 12:43:29 -06001058 */
Mike Christie6eabafb2008-01-31 13:36:43 -06001059 spin_lock_irqsave(&session->lock, flags);
1060 session->state = ISCSI_SESSION_FREE;
1061 spin_unlock_irqrestore(&session->lock, flags);
Mike Christiebd976f62008-01-31 13:36:46 -06001062
Mike Christie45ab33b2008-03-04 13:26:55 -06001063 scsi_target_unblock(&session->dev);
1064 /* flush running scans then delete devices */
Mike Christie06d25af2009-03-05 14:46:02 -06001065 scsi_flush_work(shost);
Mike Christie45ab33b2008-03-04 13:26:55 -06001066 __iscsi_unbind_session(&session->unbind_work);
Mike Christie30a6c652006-04-06 21:13:39 -05001067
Mike Christie26974782007-12-13 12:43:29 -06001068 /* hw iscsi may not have removed all connections from session */
1069 err = device_for_each_child(&session->dev, NULL,
1070 iscsi_iter_destroy_conn_fn);
1071 if (err)
Mike Christie322d7392008-01-31 13:36:52 -06001072 iscsi_cls_session_printk(KERN_ERR, session,
1073 "Could not delete all connections "
1074 "for session. Error %d.\n", err);
Mike Christie8434aa82006-06-28 12:00:30 -05001075
Mike Christie7b8631b2006-01-13 18:05:50 -06001076 transport_unregister_device(&session->dev);
Mike Christie632248a2009-08-20 15:11:01 -05001077
1078 ISCSI_DBG_TRANS_SESSION(session, "Completing session removal\n");
Mike Christie8434aa82006-06-28 12:00:30 -05001079 device_del(&session->dev);
1080}
1081EXPORT_SYMBOL_GPL(iscsi_remove_session);
1082
1083void iscsi_free_session(struct iscsi_cls_session *session)
1084{
Mike Christie632248a2009-08-20 15:11:01 -05001085 ISCSI_DBG_TRANS_SESSION(session, "Freeing session\n");
Mike Christie26974782007-12-13 12:43:29 -06001086 iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION);
Mike Christie8434aa82006-06-28 12:00:30 -05001087 put_device(&session->dev);
Mike Christie7b8631b2006-01-13 18:05:50 -06001088}
Mike Christie8434aa82006-06-28 12:00:30 -05001089EXPORT_SYMBOL_GPL(iscsi_free_session);
1090
1091/**
1092 * iscsi_destroy_session - destroy iscsi session
1093 * @session: iscsi_session
1094 *
1095 * Can be called by a LLD or iscsi_transport. There must not be
1096 * any running connections.
Rob Landleyeb448202007-11-03 13:30:39 -05001097 */
Mike Christie8434aa82006-06-28 12:00:30 -05001098int iscsi_destroy_session(struct iscsi_cls_session *session)
1099{
1100 iscsi_remove_session(session);
Mike Christie632248a2009-08-20 15:11:01 -05001101 ISCSI_DBG_TRANS_SESSION(session, "Completing session destruction\n");
Mike Christie8434aa82006-06-28 12:00:30 -05001102 iscsi_free_session(session);
1103 return 0;
1104}
Mike Christie7b8631b2006-01-13 18:05:50 -06001105EXPORT_SYMBOL_GPL(iscsi_destroy_session);
1106
Mike Christie7b8631b2006-01-13 18:05:50 -06001107/**
1108 * iscsi_create_conn - create iscsi class connection
1109 * @session: iscsi cls session
Mike Christie5d91e202008-05-21 15:54:01 -05001110 * @dd_size: private driver data size
Mike Christie7b8631b2006-01-13 18:05:50 -06001111 * @cid: connection id
1112 *
1113 * This can be called from a LLD or iscsi_transport. The connection
1114 * is child of the session so cid must be unique for all connections
1115 * on the session.
Mike Christieb5c7a122006-04-06 21:13:33 -05001116 *
1117 * Since we do not support MCS, cid will normally be zero. In some cases
1118 * for software iscsi we could be trying to preallocate a connection struct
1119 * in which case there could be two connection structs and cid would be
1120 * non-zero.
Rob Landleyeb448202007-11-03 13:30:39 -05001121 */
Mike Christie7b8631b2006-01-13 18:05:50 -06001122struct iscsi_cls_conn *
Mike Christie5d91e202008-05-21 15:54:01 -05001123iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
Mike Christie7b8631b2006-01-13 18:05:50 -06001124{
1125 struct iscsi_transport *transport = session->transport;
Mike Christie7b8631b2006-01-13 18:05:50 -06001126 struct iscsi_cls_conn *conn;
Mike Christie26974782007-12-13 12:43:29 -06001127 unsigned long flags;
Mike Christie7b8631b2006-01-13 18:05:50 -06001128 int err;
1129
Mike Christie5d91e202008-05-21 15:54:01 -05001130 conn = kzalloc(sizeof(*conn) + dd_size, GFP_KERNEL);
Mike Christie7b8631b2006-01-13 18:05:50 -06001131 if (!conn)
1132 return NULL;
Mike Christie5d91e202008-05-21 15:54:01 -05001133 if (dd_size)
Mike Christie7b8631b2006-01-13 18:05:50 -06001134 conn->dd_data = &conn[1];
1135
Mike Christie22a39fb2011-02-16 15:04:33 -06001136 mutex_init(&conn->ep_mutex);
Mike Christie7b8631b2006-01-13 18:05:50 -06001137 INIT_LIST_HEAD(&conn->conn_list);
1138 conn->transport = transport;
Mike Christieb5c7a122006-04-06 21:13:33 -05001139 conn->cid = cid;
Mike Christie7b8631b2006-01-13 18:05:50 -06001140
1141 /* this is released in the dev's release function */
1142 if (!get_device(&session->dev))
Mike Christie43a145a2006-10-16 18:09:38 -04001143 goto free_conn;
Mike Christieb5c7a122006-04-06 21:13:33 -05001144
Kay Sievers71610f52008-12-03 22:41:36 +01001145 dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid);
Mike Christie7b8631b2006-01-13 18:05:50 -06001146 conn->dev.parent = &session->dev;
1147 conn->dev.release = iscsi_conn_release;
1148 err = device_register(&conn->dev);
1149 if (err) {
Mike Christie322d7392008-01-31 13:36:52 -06001150 iscsi_cls_session_printk(KERN_ERR, session, "could not "
1151 "register connection's dev\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06001152 goto release_parent_ref;
1153 }
1154 transport_register_device(&conn->dev);
Mike Christie26974782007-12-13 12:43:29 -06001155
1156 spin_lock_irqsave(&connlock, flags);
1157 list_add(&conn->conn_list, &connlist);
Mike Christie26974782007-12-13 12:43:29 -06001158 spin_unlock_irqrestore(&connlock, flags);
Mike Christie632248a2009-08-20 15:11:01 -05001159
1160 ISCSI_DBG_TRANS_CONN(conn, "Completed conn creation\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06001161 return conn;
1162
1163release_parent_ref:
1164 put_device(&session->dev);
1165free_conn:
1166 kfree(conn);
1167 return NULL;
1168}
1169
1170EXPORT_SYMBOL_GPL(iscsi_create_conn);
1171
1172/**
1173 * iscsi_destroy_conn - destroy iscsi class connection
Rob Landleyeb448202007-11-03 13:30:39 -05001174 * @conn: iscsi cls session
Mike Christie7b8631b2006-01-13 18:05:50 -06001175 *
Mike Christie26974782007-12-13 12:43:29 -06001176 * This can be called from a LLD or iscsi_transport.
Rob Landleyeb448202007-11-03 13:30:39 -05001177 */
Mike Christie7b8631b2006-01-13 18:05:50 -06001178int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
1179{
Mike Christie26974782007-12-13 12:43:29 -06001180 unsigned long flags;
1181
1182 spin_lock_irqsave(&connlock, flags);
Mike Christie26974782007-12-13 12:43:29 -06001183 list_del(&conn->conn_list);
1184 spin_unlock_irqrestore(&connlock, flags);
1185
Mike Christie7b8631b2006-01-13 18:05:50 -06001186 transport_unregister_device(&conn->dev);
Mike Christie632248a2009-08-20 15:11:01 -05001187 ISCSI_DBG_TRANS_CONN(conn, "Completing conn destruction\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06001188 device_unregister(&conn->dev);
1189 return 0;
1190}
Mike Christie7b8631b2006-01-13 18:05:50 -06001191EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
1192
1193/*
Mike Christie7b8631b2006-01-13 18:05:50 -06001194 * iscsi interface functions
1195 */
Alex Aizman0896b752005-08-04 19:33:07 -07001196static struct iscsi_internal *
1197iscsi_if_transport_lookup(struct iscsi_transport *tt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198{
Alex Aizman0896b752005-08-04 19:33:07 -07001199 struct iscsi_internal *priv;
1200 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201
Alex Aizman0896b752005-08-04 19:33:07 -07001202 spin_lock_irqsave(&iscsi_transport_lock, flags);
1203 list_for_each_entry(priv, &iscsi_transports, list) {
1204 if (tt == priv->iscsi_transport) {
1205 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
1206 return priv;
1207 }
1208 }
1209 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
1210 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
Alex Aizman0896b752005-08-04 19:33:07 -07001213static int
Michael Chan43514772009-06-08 18:14:41 -07001214iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp)
Mike Christie53cb8a12006-06-28 12:00:32 -05001215{
Michael Chan43514772009-06-08 18:14:41 -07001216 return nlmsg_multicast(nls, skb, 0, group, gfp);
Alex Aizman0896b752005-08-04 19:33:07 -07001217}
1218
Mike Christie7b7232f2006-02-01 21:06:49 -06001219int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
Alex Aizman0896b752005-08-04 19:33:07 -07001220 char *data, uint32_t data_size)
1221{
1222 struct nlmsghdr *nlh;
1223 struct sk_buff *skb;
1224 struct iscsi_uevent *ev;
Alex Aizman0896b752005-08-04 19:33:07 -07001225 char *pdu;
Mike Christie790f39a2006-05-18 20:31:39 -05001226 struct iscsi_internal *priv;
Alex Aizman0896b752005-08-04 19:33:07 -07001227 int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) +
1228 data_size);
1229
Mike Christie790f39a2006-05-18 20:31:39 -05001230 priv = iscsi_if_transport_lookup(conn->transport);
1231 if (!priv)
1232 return -EINVAL;
1233
Mike Christie43a145a2006-10-16 18:09:38 -04001234 skb = alloc_skb(len, GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07001235 if (!skb) {
Mike Christiee5bd7b542008-09-24 11:46:10 -05001236 iscsi_conn_error_event(conn, ISCSI_ERR_CONN_FAILED);
Mike Christie322d7392008-01-31 13:36:52 -06001237 iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver "
1238 "control PDU: OOM\n");
Alex Aizman0896b752005-08-04 19:33:07 -07001239 return -ENOMEM;
1240 }
1241
Michael Chan43514772009-06-08 18:14:41 -07001242 nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
Alex Aizman0896b752005-08-04 19:33:07 -07001243 ev = NLMSG_DATA(nlh);
1244 memset(ev, 0, sizeof(*ev));
1245 ev->transport_handle = iscsi_handle(conn->transport);
1246 ev->type = ISCSI_KEVENT_RECV_PDU;
Mike Christieb5c7a122006-04-06 21:13:33 -05001247 ev->r.recv_req.cid = conn->cid;
1248 ev->r.recv_req.sid = iscsi_conn_get_sid(conn);
Alex Aizman0896b752005-08-04 19:33:07 -07001249 pdu = (char*)ev + sizeof(*ev);
1250 memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
1251 memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
1252
Michael Chan43514772009-06-08 18:14:41 -07001253 return iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07001254}
1255EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
1256
Michael Chan43514772009-06-08 18:14:41 -07001257int iscsi_offload_mesg(struct Scsi_Host *shost,
1258 struct iscsi_transport *transport, uint32_t type,
1259 char *data, uint16_t data_size)
1260{
1261 struct nlmsghdr *nlh;
1262 struct sk_buff *skb;
1263 struct iscsi_uevent *ev;
1264 int len = NLMSG_SPACE(sizeof(*ev) + data_size);
1265
Michael Chana541f842009-07-29 08:49:52 +00001266 skb = alloc_skb(len, GFP_ATOMIC);
Michael Chan43514772009-06-08 18:14:41 -07001267 if (!skb) {
1268 printk(KERN_ERR "can not deliver iscsi offload message:OOM\n");
1269 return -ENOMEM;
1270 }
1271
1272 nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
1273 ev = NLMSG_DATA(nlh);
1274 memset(ev, 0, sizeof(*ev));
1275 ev->type = type;
1276 ev->transport_handle = iscsi_handle(transport);
1277 switch (type) {
1278 case ISCSI_KEVENT_PATH_REQ:
1279 ev->r.req_path.host_no = shost->host_no;
1280 break;
1281 case ISCSI_KEVENT_IF_DOWN:
1282 ev->r.notify_if_down.host_no = shost->host_no;
1283 break;
1284 }
1285
1286 memcpy((char *)ev + sizeof(*ev), data, data_size);
1287
Michael Chana541f842009-07-29 08:49:52 +00001288 return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_ATOMIC);
Michael Chan43514772009-06-08 18:14:41 -07001289}
1290EXPORT_SYMBOL_GPL(iscsi_offload_mesg);
1291
Mike Christiee5bd7b542008-09-24 11:46:10 -05001292void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
Alex Aizman0896b752005-08-04 19:33:07 -07001293{
1294 struct nlmsghdr *nlh;
1295 struct sk_buff *skb;
1296 struct iscsi_uevent *ev;
Mike Christie790f39a2006-05-18 20:31:39 -05001297 struct iscsi_internal *priv;
Alex Aizman0896b752005-08-04 19:33:07 -07001298 int len = NLMSG_SPACE(sizeof(*ev));
1299
Mike Christie790f39a2006-05-18 20:31:39 -05001300 priv = iscsi_if_transport_lookup(conn->transport);
1301 if (!priv)
1302 return;
1303
Mike Christie43a145a2006-10-16 18:09:38 -04001304 skb = alloc_skb(len, GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07001305 if (!skb) {
Mike Christie322d7392008-01-31 13:36:52 -06001306 iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored "
1307 "conn error (%d)\n", error);
Alex Aizman0896b752005-08-04 19:33:07 -07001308 return;
1309 }
1310
Michael Chan43514772009-06-08 18:14:41 -07001311 nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
Alex Aizman0896b752005-08-04 19:33:07 -07001312 ev = NLMSG_DATA(nlh);
1313 ev->transport_handle = iscsi_handle(conn->transport);
1314 ev->type = ISCSI_KEVENT_CONN_ERROR;
Alex Aizman0896b752005-08-04 19:33:07 -07001315 ev->r.connerror.error = error;
Mike Christieb5c7a122006-04-06 21:13:33 -05001316 ev->r.connerror.cid = conn->cid;
1317 ev->r.connerror.sid = iscsi_conn_get_sid(conn);
Alex Aizman0896b752005-08-04 19:33:07 -07001318
Michael Chan43514772009-06-08 18:14:41 -07001319 iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07001320
Mike Christie322d7392008-01-31 13:36:52 -06001321 iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n",
1322 error);
Alex Aizman0896b752005-08-04 19:33:07 -07001323}
Mike Christiee5bd7b542008-09-24 11:46:10 -05001324EXPORT_SYMBOL_GPL(iscsi_conn_error_event);
Alex Aizman0896b752005-08-04 19:33:07 -07001325
1326static int
Michael Chan43514772009-06-08 18:14:41 -07001327iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
1328 void *payload, int size)
Alex Aizman0896b752005-08-04 19:33:07 -07001329{
1330 struct sk_buff *skb;
1331 struct nlmsghdr *nlh;
1332 int len = NLMSG_SPACE(size);
1333 int flags = multi ? NLM_F_MULTI : 0;
1334 int t = done ? NLMSG_DONE : type;
1335
Mike Christie43a145a2006-10-16 18:09:38 -04001336 skb = alloc_skb(len, GFP_ATOMIC);
Mike Christie239a7dc2007-05-30 12:57:07 -05001337 if (!skb) {
1338 printk(KERN_ERR "Could not allocate skb to send reply.\n");
1339 return -ENOMEM;
1340 }
Alex Aizman0896b752005-08-04 19:33:07 -07001341
Michael Chan43514772009-06-08 18:14:41 -07001342 nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0);
Alex Aizman0896b752005-08-04 19:33:07 -07001343 nlh->nlmsg_flags = flags;
1344 memcpy(NLMSG_DATA(nlh), payload, size);
Michael Chan43514772009-06-08 18:14:41 -07001345 return iscsi_multicast_skb(skb, group, GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07001346}
1347
1348static int
Mike Christie5b940ad2006-02-01 21:06:56 -06001349iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
Alex Aizman0896b752005-08-04 19:33:07 -07001350{
1351 struct iscsi_uevent *ev = NLMSG_DATA(nlh);
1352 struct iscsi_stats *stats;
1353 struct sk_buff *skbstat;
Mike Christie7b8631b2006-01-13 18:05:50 -06001354 struct iscsi_cls_conn *conn;
Alex Aizman0896b752005-08-04 19:33:07 -07001355 struct nlmsghdr *nlhstat;
1356 struct iscsi_uevent *evstat;
Mike Christie790f39a2006-05-18 20:31:39 -05001357 struct iscsi_internal *priv;
Alex Aizman0896b752005-08-04 19:33:07 -07001358 int len = NLMSG_SPACE(sizeof(*ev) +
1359 sizeof(struct iscsi_stats) +
1360 sizeof(struct iscsi_stats_custom) *
1361 ISCSI_STATS_CUSTOM_MAX);
1362 int err = 0;
1363
Mike Christie790f39a2006-05-18 20:31:39 -05001364 priv = iscsi_if_transport_lookup(transport);
1365 if (!priv)
1366 return -EINVAL;
1367
Mike Christieb5c7a122006-04-06 21:13:33 -05001368 conn = iscsi_conn_lookup(ev->u.get_stats.sid, ev->u.get_stats.cid);
Alex Aizman0896b752005-08-04 19:33:07 -07001369 if (!conn)
1370 return -EEXIST;
1371
1372 do {
1373 int actual_size;
1374
Mike Christie43a145a2006-10-16 18:09:38 -04001375 skbstat = alloc_skb(len, GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07001376 if (!skbstat) {
Mike Christie322d7392008-01-31 13:36:52 -06001377 iscsi_cls_conn_printk(KERN_ERR, conn, "can not "
1378 "deliver stats: OOM\n");
Alex Aizman0896b752005-08-04 19:33:07 -07001379 return -ENOMEM;
1380 }
1381
Michael Chan43514772009-06-08 18:14:41 -07001382 nlhstat = __nlmsg_put(skbstat, 0, 0, 0,
Alex Aizman0896b752005-08-04 19:33:07 -07001383 (len - sizeof(*nlhstat)), 0);
1384 evstat = NLMSG_DATA(nlhstat);
1385 memset(evstat, 0, sizeof(*evstat));
1386 evstat->transport_handle = iscsi_handle(conn->transport);
1387 evstat->type = nlh->nlmsg_type;
Mike Christieb5c7a122006-04-06 21:13:33 -05001388 evstat->u.get_stats.cid =
1389 ev->u.get_stats.cid;
1390 evstat->u.get_stats.sid =
1391 ev->u.get_stats.sid;
Alex Aizman0896b752005-08-04 19:33:07 -07001392 stats = (struct iscsi_stats *)
1393 ((char*)evstat + sizeof(*evstat));
1394 memset(stats, 0, sizeof(*stats));
1395
Mike Christie7b7232f2006-02-01 21:06:49 -06001396 transport->get_stats(conn, stats);
Alex Aizman0896b752005-08-04 19:33:07 -07001397 actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) +
1398 sizeof(struct iscsi_stats) +
1399 sizeof(struct iscsi_stats_custom) *
1400 stats->custom_length);
1401 actual_size -= sizeof(*nlhstat);
1402 actual_size = NLMSG_LENGTH(actual_size);
Mike Christie5b940ad2006-02-01 21:06:56 -06001403 skb_trim(skbstat, NLMSG_ALIGN(actual_size));
Alex Aizman0896b752005-08-04 19:33:07 -07001404 nlhstat->nlmsg_len = actual_size;
1405
Michael Chan43514772009-06-08 18:14:41 -07001406 err = iscsi_multicast_skb(skbstat, ISCSI_NL_GRP_ISCSID,
1407 GFP_ATOMIC);
Alex Aizman0896b752005-08-04 19:33:07 -07001408 } while (err < 0 && err != -ECONNREFUSED);
1409
1410 return err;
1411}
1412
Mike Christie53cb8a12006-06-28 12:00:32 -05001413/**
Mike Christie26974782007-12-13 12:43:29 -06001414 * iscsi_session_event - send session destr. completion event
1415 * @session: iscsi class session
1416 * @event: type of event
Rob Landleyeb448202007-11-03 13:30:39 -05001417 */
Mike Christie26974782007-12-13 12:43:29 -06001418int iscsi_session_event(struct iscsi_cls_session *session,
1419 enum iscsi_uevent_e event)
Mike Christie53cb8a12006-06-28 12:00:32 -05001420{
1421 struct iscsi_internal *priv;
Mike Christie53cb8a12006-06-28 12:00:32 -05001422 struct Scsi_Host *shost;
1423 struct iscsi_uevent *ev;
1424 struct sk_buff *skb;
1425 struct nlmsghdr *nlh;
Mike Christie53cb8a12006-06-28 12:00:32 -05001426 int rc, len = NLMSG_SPACE(sizeof(*ev));
1427
Mike Christie26974782007-12-13 12:43:29 -06001428 priv = iscsi_if_transport_lookup(session->transport);
Mike Christie53cb8a12006-06-28 12:00:32 -05001429 if (!priv)
1430 return -EINVAL;
Mike Christie53cb8a12006-06-28 12:00:32 -05001431 shost = iscsi_session_to_shost(session);
1432
Mike Christie43a145a2006-10-16 18:09:38 -04001433 skb = alloc_skb(len, GFP_KERNEL);
Mike Christie53cb8a12006-06-28 12:00:32 -05001434 if (!skb) {
Mike Christie322d7392008-01-31 13:36:52 -06001435 iscsi_cls_session_printk(KERN_ERR, session,
1436 "Cannot notify userspace of session "
1437 "event %u\n", event);
Mike Christie53cb8a12006-06-28 12:00:32 -05001438 return -ENOMEM;
1439 }
1440
Michael Chan43514772009-06-08 18:14:41 -07001441 nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
Mike Christie53cb8a12006-06-28 12:00:32 -05001442 ev = NLMSG_DATA(nlh);
Mike Christie26974782007-12-13 12:43:29 -06001443 ev->transport_handle = iscsi_handle(session->transport);
1444
1445 ev->type = event;
1446 switch (event) {
1447 case ISCSI_KEVENT_DESTROY_SESSION:
1448 ev->r.d_session.host_no = shost->host_no;
1449 ev->r.d_session.sid = session->sid;
1450 break;
1451 case ISCSI_KEVENT_CREATE_SESSION:
1452 ev->r.c_session_ret.host_no = shost->host_no;
1453 ev->r.c_session_ret.sid = session->sid;
1454 break;
1455 case ISCSI_KEVENT_UNBIND_SESSION:
1456 ev->r.unbind_session.host_no = shost->host_no;
1457 ev->r.unbind_session.sid = session->sid;
1458 break;
1459 default:
Mike Christie322d7392008-01-31 13:36:52 -06001460 iscsi_cls_session_printk(KERN_ERR, session, "Invalid event "
1461 "%u.\n", event);
Mike Christie26974782007-12-13 12:43:29 -06001462 kfree_skb(skb);
1463 return -EINVAL;
1464 }
Mike Christie53cb8a12006-06-28 12:00:32 -05001465
1466 /*
1467 * this will occur if the daemon is not up, so we just warn
1468 * the user and when the daemon is restarted it will handle it
1469 */
Michael Chan43514772009-06-08 18:14:41 -07001470 rc = iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
Pablo Neira Ayusoff491a72009-02-05 23:56:36 -08001471 if (rc == -ESRCH)
Mike Christie322d7392008-01-31 13:36:52 -06001472 iscsi_cls_session_printk(KERN_ERR, session,
1473 "Cannot notify userspace of session "
1474 "event %u. Check iscsi daemon\n",
1475 event);
Mike Christie632248a2009-08-20 15:11:01 -05001476
1477 ISCSI_DBG_TRANS_SESSION(session, "Completed handling event %d rc %d\n",
1478 event, rc);
Mike Christie53cb8a12006-06-28 12:00:32 -05001479 return rc;
1480}
Mike Christie26974782007-12-13 12:43:29 -06001481EXPORT_SYMBOL_GPL(iscsi_session_event);
Mike Christie53cb8a12006-06-28 12:00:32 -05001482
Alex Aizman0896b752005-08-04 19:33:07 -07001483static int
Mike Christied82ff9be2008-05-21 15:54:13 -05001484iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep,
1485 struct iscsi_uevent *ev, uint32_t initial_cmdsn,
Mike Christie40753ca2008-05-21 15:53:56 -05001486 uint16_t cmds_max, uint16_t queue_depth)
Mike Christie7b8631b2006-01-13 18:05:50 -06001487{
1488 struct iscsi_transport *transport = priv->iscsi_transport;
Mike Christie7b7232f2006-02-01 21:06:49 -06001489 struct iscsi_cls_session *session;
Mike Christie5e7facb2009-03-05 14:46:06 -06001490 struct Scsi_Host *shost;
Mike Christie7b8631b2006-01-13 18:05:50 -06001491
Mike Christied82ff9be2008-05-21 15:54:13 -05001492 session = transport->create_session(ep, cmds_max, queue_depth,
Mike Christie5e7facb2009-03-05 14:46:06 -06001493 initial_cmdsn);
Mike Christie7b7232f2006-02-01 21:06:49 -06001494 if (!session)
Mike Christie7b8631b2006-01-13 18:05:50 -06001495 return -ENOMEM;
1496
Mike Christie5e7facb2009-03-05 14:46:06 -06001497 shost = iscsi_session_to_shost(session);
1498 ev->r.c_session_ret.host_no = shost->host_no;
Mike Christieb5c7a122006-04-06 21:13:33 -05001499 ev->r.c_session_ret.sid = session->sid;
Mike Christie632248a2009-08-20 15:11:01 -05001500 ISCSI_DBG_TRANS_SESSION(session,
1501 "Completed creating transport session\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06001502 return 0;
1503}
1504
1505static int
Mike Christie7b7232f2006-02-01 21:06:49 -06001506iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
Mike Christie7b8631b2006-01-13 18:05:50 -06001507{
Mike Christie7b8631b2006-01-13 18:05:50 -06001508 struct iscsi_cls_conn *conn;
Mike Christie7b7232f2006-02-01 21:06:49 -06001509 struct iscsi_cls_session *session;
Mike Christie7b8631b2006-01-13 18:05:50 -06001510
Mike Christieb5c7a122006-04-06 21:13:33 -05001511 session = iscsi_session_lookup(ev->u.c_conn.sid);
1512 if (!session) {
Mike Christie322d7392008-01-31 13:36:52 -06001513 printk(KERN_ERR "iscsi: invalid session %d.\n",
Mike Christieb5c7a122006-04-06 21:13:33 -05001514 ev->u.c_conn.sid);
Mike Christie7b8631b2006-01-13 18:05:50 -06001515 return -EINVAL;
Mike Christieb5c7a122006-04-06 21:13:33 -05001516 }
Mike Christie7b8631b2006-01-13 18:05:50 -06001517
Mike Christie7b7232f2006-02-01 21:06:49 -06001518 conn = transport->create_conn(session, ev->u.c_conn.cid);
Mike Christieb5c7a122006-04-06 21:13:33 -05001519 if (!conn) {
Mike Christie322d7392008-01-31 13:36:52 -06001520 iscsi_cls_session_printk(KERN_ERR, session,
1521 "couldn't create a new connection.");
Mike Christie7b7232f2006-02-01 21:06:49 -06001522 return -ENOMEM;
Mike Christieb5c7a122006-04-06 21:13:33 -05001523 }
Mike Christie7b8631b2006-01-13 18:05:50 -06001524
Mike Christieb5c7a122006-04-06 21:13:33 -05001525 ev->r.c_conn_ret.sid = session->sid;
1526 ev->r.c_conn_ret.cid = conn->cid;
Mike Christie632248a2009-08-20 15:11:01 -05001527
1528 ISCSI_DBG_TRANS_CONN(conn, "Completed creating transport conn\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06001529 return 0;
Mike Christie7b8631b2006-01-13 18:05:50 -06001530}
1531
1532static int
1533iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
1534{
Mike Christie7b8631b2006-01-13 18:05:50 -06001535 struct iscsi_cls_conn *conn;
Mike Christie7b8631b2006-01-13 18:05:50 -06001536
Mike Christieb5c7a122006-04-06 21:13:33 -05001537 conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
Mike Christie7b8631b2006-01-13 18:05:50 -06001538 if (!conn)
Mike Christie7b8631b2006-01-13 18:05:50 -06001539 return -EINVAL;
Mike Christie7b8631b2006-01-13 18:05:50 -06001540
Mike Christie632248a2009-08-20 15:11:01 -05001541 ISCSI_DBG_TRANS_CONN(conn, "Destroying transport conn\n");
Mike Christie7b8631b2006-01-13 18:05:50 -06001542 if (transport->destroy_conn)
1543 transport->destroy_conn(conn);
Mike Christie632248a2009-08-20 15:11:01 -05001544
Mike Christie7b8631b2006-01-13 18:05:50 -06001545 return 0;
1546}
1547
Mike Christiefd7255f2006-04-06 21:13:36 -05001548static int
1549iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
1550{
1551 char *data = (char*)ev + sizeof(*ev);
1552 struct iscsi_cls_conn *conn;
1553 struct iscsi_cls_session *session;
Mike Christiea54a52c2006-06-28 12:00:23 -05001554 int err = 0, value = 0;
Mike Christiefd7255f2006-04-06 21:13:36 -05001555
1556 session = iscsi_session_lookup(ev->u.set_param.sid);
1557 conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid);
1558 if (!conn || !session)
1559 return -EINVAL;
1560
1561 switch (ev->u.set_param.param) {
Mike Christie30a6c652006-04-06 21:13:39 -05001562 case ISCSI_PARAM_SESS_RECOVERY_TMO:
Mike Christiea54a52c2006-06-28 12:00:23 -05001563 sscanf(data, "%d", &value);
Mike Christiefdd46dc2009-11-11 16:34:34 -06001564 session->recovery_tmo = value;
Mike Christie30a6c652006-04-06 21:13:39 -05001565 break;
Mike Christiefd7255f2006-04-06 21:13:36 -05001566 default:
Mike Christiea54a52c2006-06-28 12:00:23 -05001567 err = transport->set_param(conn, ev->u.set_param.param,
1568 data, ev->u.set_param.len);
Mike Christiefd7255f2006-04-06 21:13:36 -05001569 }
1570
1571 return err;
1572}
1573
Mike Christie10eb0f02009-05-13 17:57:38 -05001574static int iscsi_if_ep_connect(struct iscsi_transport *transport,
1575 struct iscsi_uevent *ev, int msg_type)
1576{
1577 struct iscsi_endpoint *ep;
1578 struct sockaddr *dst_addr;
1579 struct Scsi_Host *shost = NULL;
1580 int non_blocking, err = 0;
1581
1582 if (!transport->ep_connect)
1583 return -EINVAL;
1584
1585 if (msg_type == ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST) {
1586 shost = scsi_host_lookup(ev->u.ep_connect_through_host.host_no);
1587 if (!shost) {
1588 printk(KERN_ERR "ep connect failed. Could not find "
1589 "host no %u\n",
1590 ev->u.ep_connect_through_host.host_no);
1591 return -ENODEV;
1592 }
1593 non_blocking = ev->u.ep_connect_through_host.non_blocking;
1594 } else
1595 non_blocking = ev->u.ep_connect.non_blocking;
1596
1597 dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
1598 ep = transport->ep_connect(shost, dst_addr, non_blocking);
1599 if (IS_ERR(ep)) {
1600 err = PTR_ERR(ep);
1601 goto release_host;
1602 }
1603
1604 ev->r.ep_connect_ret.handle = ep->id;
1605release_host:
1606 if (shost)
1607 scsi_host_put(shost);
1608 return err;
1609}
1610
Mike Christie22a39fb2011-02-16 15:04:33 -06001611static int iscsi_if_ep_disconnect(struct iscsi_transport *transport,
1612 u64 ep_handle)
1613{
1614 struct iscsi_cls_conn *conn;
1615 struct iscsi_endpoint *ep;
1616
1617 if (!transport->ep_disconnect)
1618 return -EINVAL;
1619
1620 ep = iscsi_lookup_endpoint(ep_handle);
1621 if (!ep)
1622 return -EINVAL;
1623 conn = ep->conn;
1624 if (conn) {
1625 mutex_lock(&conn->ep_mutex);
1626 conn->ep = NULL;
1627 mutex_unlock(&conn->ep_mutex);
1628 }
1629
1630 transport->ep_disconnect(ep);
1631 return 0;
1632}
1633
Mike Christie7b8631b2006-01-13 18:05:50 -06001634static int
Or Gerlitz264faaa2006-05-02 19:46:36 -05001635iscsi_if_transport_ep(struct iscsi_transport *transport,
1636 struct iscsi_uevent *ev, int msg_type)
1637{
Mike Christied82ff9be2008-05-21 15:54:13 -05001638 struct iscsi_endpoint *ep;
Or Gerlitz264faaa2006-05-02 19:46:36 -05001639 int rc = 0;
1640
1641 switch (msg_type) {
Mike Christie10eb0f02009-05-13 17:57:38 -05001642 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
Or Gerlitz264faaa2006-05-02 19:46:36 -05001643 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
Mike Christie10eb0f02009-05-13 17:57:38 -05001644 rc = iscsi_if_ep_connect(transport, ev, msg_type);
Or Gerlitz264faaa2006-05-02 19:46:36 -05001645 break;
1646 case ISCSI_UEVENT_TRANSPORT_EP_POLL:
1647 if (!transport->ep_poll)
1648 return -EINVAL;
1649
Mike Christied82ff9be2008-05-21 15:54:13 -05001650 ep = iscsi_lookup_endpoint(ev->u.ep_poll.ep_handle);
1651 if (!ep)
1652 return -EINVAL;
1653
1654 ev->r.retcode = transport->ep_poll(ep,
Or Gerlitz264faaa2006-05-02 19:46:36 -05001655 ev->u.ep_poll.timeout_ms);
1656 break;
1657 case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
Mike Christie22a39fb2011-02-16 15:04:33 -06001658 rc = iscsi_if_ep_disconnect(transport,
1659 ev->u.ep_disconnect.ep_handle);
Or Gerlitz264faaa2006-05-02 19:46:36 -05001660 break;
1661 }
1662 return rc;
1663}
1664
1665static int
Mike Christie01cb2252006-06-28 12:00:22 -05001666iscsi_tgt_dscvr(struct iscsi_transport *transport,
1667 struct iscsi_uevent *ev)
1668{
Mike Christie2174a042007-05-30 12:57:10 -05001669 struct Scsi_Host *shost;
Mike Christie01cb2252006-06-28 12:00:22 -05001670 struct sockaddr *dst_addr;
Mike Christie2174a042007-05-30 12:57:10 -05001671 int err;
Mike Christie01cb2252006-06-28 12:00:22 -05001672
1673 if (!transport->tgt_dscvr)
1674 return -EINVAL;
1675
Mike Christie2174a042007-05-30 12:57:10 -05001676 shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no);
James Smart315cb0a2008-08-07 20:49:30 -04001677 if (!shost) {
Mike Christie2174a042007-05-30 12:57:10 -05001678 printk(KERN_ERR "target discovery could not find host no %u\n",
1679 ev->u.tgt_dscvr.host_no);
1680 return -ENODEV;
1681 }
1682
1683
Mike Christie01cb2252006-06-28 12:00:22 -05001684 dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
Mike Christie2174a042007-05-30 12:57:10 -05001685 err = transport->tgt_dscvr(shost, ev->u.tgt_dscvr.type,
1686 ev->u.tgt_dscvr.enable, dst_addr);
1687 scsi_host_put(shost);
1688 return err;
Mike Christie01cb2252006-06-28 12:00:22 -05001689}
1690
1691static int
Mike Christie1d9bf132007-05-30 12:57:11 -05001692iscsi_set_host_param(struct iscsi_transport *transport,
1693 struct iscsi_uevent *ev)
1694{
1695 char *data = (char*)ev + sizeof(*ev);
1696 struct Scsi_Host *shost;
1697 int err;
1698
1699 if (!transport->set_host_param)
1700 return -ENOSYS;
1701
1702 shost = scsi_host_lookup(ev->u.set_host_param.host_no);
James Smart315cb0a2008-08-07 20:49:30 -04001703 if (!shost) {
Mike Christie1d9bf132007-05-30 12:57:11 -05001704 printk(KERN_ERR "set_host_param could not find host no %u\n",
1705 ev->u.set_host_param.host_no);
1706 return -ENODEV;
1707 }
1708
1709 err = transport->set_host_param(shost, ev->u.set_host_param.param,
1710 data, ev->u.set_host_param.len);
1711 scsi_host_put(shost);
1712 return err;
1713}
1714
1715static int
Michael Chan43514772009-06-08 18:14:41 -07001716iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev)
1717{
1718 struct Scsi_Host *shost;
1719 struct iscsi_path *params;
1720 int err;
1721
1722 if (!transport->set_path)
1723 return -ENOSYS;
1724
1725 shost = scsi_host_lookup(ev->u.set_path.host_no);
1726 if (!shost) {
1727 printk(KERN_ERR "set path could not find host no %u\n",
1728 ev->u.set_path.host_no);
1729 return -ENODEV;
1730 }
1731
1732 params = (struct iscsi_path *)((char *)ev + sizeof(*ev));
1733 err = transport->set_path(shost, params);
1734
1735 scsi_host_put(shost);
1736 return err;
1737}
1738
1739static int
Mike Christie56c155b2011-07-25 13:48:37 -05001740iscsi_set_iface_params(struct iscsi_transport *transport,
1741 struct iscsi_uevent *ev)
1742{
1743 char *data = (char *)ev + sizeof(*ev);
1744 struct Scsi_Host *shost;
1745 int err;
1746
1747 if (!transport->set_iface_param)
1748 return -ENOSYS;
1749
1750 shost = scsi_host_lookup(ev->u.set_iface_params.host_no);
1751 if (!shost) {
1752 printk(KERN_ERR "set_iface_params could not find host no %u\n",
1753 ev->u.set_iface_params.host_no);
1754 return -ENODEV;
1755 }
1756
1757 err = transport->set_iface_param(shost, data,
1758 ev->u.set_iface_params.count);
1759 scsi_host_put(shost);
1760 return err;
1761}
1762
1763static int
Michael Chan43514772009-06-08 18:14:41 -07001764iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
Alex Aizman0896b752005-08-04 19:33:07 -07001765{
1766 int err = 0;
1767 struct iscsi_uevent *ev = NLMSG_DATA(nlh);
1768 struct iscsi_transport *transport = NULL;
1769 struct iscsi_internal *priv;
Mike Christie7b7232f2006-02-01 21:06:49 -06001770 struct iscsi_cls_session *session;
1771 struct iscsi_cls_conn *conn;
Mike Christied82ff9be2008-05-21 15:54:13 -05001772 struct iscsi_endpoint *ep = NULL;
Alex Aizman0896b752005-08-04 19:33:07 -07001773
Michael Chan43514772009-06-08 18:14:41 -07001774 if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE)
1775 *group = ISCSI_NL_GRP_UIP;
1776 else
1777 *group = ISCSI_NL_GRP_ISCSID;
1778
Alex Aizman0896b752005-08-04 19:33:07 -07001779 priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
1780 if (!priv)
1781 return -EINVAL;
1782 transport = priv->iscsi_transport;
1783
Mike Christie7b7232f2006-02-01 21:06:49 -06001784 if (!try_module_get(transport->owner))
1785 return -EINVAL;
1786
Alex Aizman0896b752005-08-04 19:33:07 -07001787 switch (nlh->nlmsg_type) {
1788 case ISCSI_UEVENT_CREATE_SESSION:
Mike Christied82ff9be2008-05-21 15:54:13 -05001789 err = iscsi_if_create_session(priv, ep, ev,
Mike Christie40753ca2008-05-21 15:53:56 -05001790 ev->u.c_session.initial_cmdsn,
1791 ev->u.c_session.cmds_max,
1792 ev->u.c_session.queue_depth);
1793 break;
1794 case ISCSI_UEVENT_CREATE_BOUND_SESSION:
Mike Christied82ff9be2008-05-21 15:54:13 -05001795 ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
Mike Christiec95fddc2008-06-16 10:11:32 -05001796 if (!ep) {
1797 err = -EINVAL;
1798 break;
1799 }
Mike Christied82ff9be2008-05-21 15:54:13 -05001800
1801 err = iscsi_if_create_session(priv, ep, ev,
Mike Christie40753ca2008-05-21 15:53:56 -05001802 ev->u.c_bound_session.initial_cmdsn,
1803 ev->u.c_bound_session.cmds_max,
1804 ev->u.c_bound_session.queue_depth);
Alex Aizman0896b752005-08-04 19:33:07 -07001805 break;
1806 case ISCSI_UEVENT_DESTROY_SESSION:
Mike Christieb5c7a122006-04-06 21:13:33 -05001807 session = iscsi_session_lookup(ev->u.d_session.sid);
Mike Christie26974782007-12-13 12:43:29 -06001808 if (session)
Mike Christie7b7232f2006-02-01 21:06:49 -06001809 transport->destroy_session(session);
Mike Christie26974782007-12-13 12:43:29 -06001810 else
1811 err = -EINVAL;
1812 break;
1813 case ISCSI_UEVENT_UNBIND_SESSION:
1814 session = iscsi_session_lookup(ev->u.d_session.sid);
1815 if (session)
Mike Christie06d25af2009-03-05 14:46:02 -06001816 scsi_queue_work(iscsi_session_to_shost(session),
1817 &session->unbind_work);
Mike Christie26974782007-12-13 12:43:29 -06001818 else
Mike Christie7b7232f2006-02-01 21:06:49 -06001819 err = -EINVAL;
Alex Aizman0896b752005-08-04 19:33:07 -07001820 break;
1821 case ISCSI_UEVENT_CREATE_CONN:
1822 err = iscsi_if_create_conn(transport, ev);
1823 break;
1824 case ISCSI_UEVENT_DESTROY_CONN:
1825 err = iscsi_if_destroy_conn(transport, ev);
1826 break;
1827 case ISCSI_UEVENT_BIND_CONN:
Mike Christieb5c7a122006-04-06 21:13:33 -05001828 session = iscsi_session_lookup(ev->u.b_conn.sid);
1829 conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid);
Mike Christie7b7232f2006-02-01 21:06:49 -06001830
Mike Christie22a39fb2011-02-16 15:04:33 -06001831 if (conn && conn->ep)
1832 iscsi_if_ep_disconnect(transport, conn->ep->id);
1833
1834 if (!session || !conn) {
Mike Christie7b7232f2006-02-01 21:06:49 -06001835 err = -EINVAL;
Mike Christie22a39fb2011-02-16 15:04:33 -06001836 break;
1837 }
1838
1839 ev->r.retcode = transport->bind_conn(session, conn,
1840 ev->u.b_conn.transport_eph,
1841 ev->u.b_conn.is_leading);
1842 if (ev->r.retcode || !transport->ep_connect)
1843 break;
1844
1845 ep = iscsi_lookup_endpoint(ev->u.b_conn.transport_eph);
1846 if (ep) {
1847 ep->conn = conn;
1848
1849 mutex_lock(&conn->ep_mutex);
1850 conn->ep = ep;
1851 mutex_unlock(&conn->ep_mutex);
1852 } else
1853 iscsi_cls_conn_printk(KERN_ERR, conn,
1854 "Could not set ep conn "
1855 "binding\n");
Alex Aizman0896b752005-08-04 19:33:07 -07001856 break;
1857 case ISCSI_UEVENT_SET_PARAM:
Mike Christiefd7255f2006-04-06 21:13:36 -05001858 err = iscsi_set_param(transport, ev);
Alex Aizman0896b752005-08-04 19:33:07 -07001859 break;
1860 case ISCSI_UEVENT_START_CONN:
Mike Christieb5c7a122006-04-06 21:13:33 -05001861 conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid);
Mike Christie7b7232f2006-02-01 21:06:49 -06001862 if (conn)
1863 ev->r.retcode = transport->start_conn(conn);
1864 else
1865 err = -EINVAL;
Alex Aizman0896b752005-08-04 19:33:07 -07001866 break;
1867 case ISCSI_UEVENT_STOP_CONN:
Mike Christieb5c7a122006-04-06 21:13:33 -05001868 conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid);
Mike Christie7b7232f2006-02-01 21:06:49 -06001869 if (conn)
1870 transport->stop_conn(conn, ev->u.stop_conn.flag);
1871 else
1872 err = -EINVAL;
Alex Aizman0896b752005-08-04 19:33:07 -07001873 break;
1874 case ISCSI_UEVENT_SEND_PDU:
Mike Christieb5c7a122006-04-06 21:13:33 -05001875 conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid);
Mike Christie7b7232f2006-02-01 21:06:49 -06001876 if (conn)
1877 ev->r.retcode = transport->send_pdu(conn,
1878 (struct iscsi_hdr*)((char*)ev + sizeof(*ev)),
1879 (char*)ev + sizeof(*ev) + ev->u.send_pdu.hdr_size,
1880 ev->u.send_pdu.data_size);
1881 else
1882 err = -EINVAL;
Alex Aizman0896b752005-08-04 19:33:07 -07001883 break;
1884 case ISCSI_UEVENT_GET_STATS:
Mike Christie5b940ad2006-02-01 21:06:56 -06001885 err = iscsi_if_get_stats(transport, nlh);
Alex Aizman0896b752005-08-04 19:33:07 -07001886 break;
Or Gerlitz264faaa2006-05-02 19:46:36 -05001887 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
1888 case ISCSI_UEVENT_TRANSPORT_EP_POLL:
1889 case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
Mike Christie10eb0f02009-05-13 17:57:38 -05001890 case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
Or Gerlitz264faaa2006-05-02 19:46:36 -05001891 err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
1892 break;
Mike Christie01cb2252006-06-28 12:00:22 -05001893 case ISCSI_UEVENT_TGT_DSCVR:
1894 err = iscsi_tgt_dscvr(transport, ev);
1895 break;
Mike Christie1d9bf132007-05-30 12:57:11 -05001896 case ISCSI_UEVENT_SET_HOST_PARAM:
1897 err = iscsi_set_host_param(transport, ev);
1898 break;
Michael Chan43514772009-06-08 18:14:41 -07001899 case ISCSI_UEVENT_PATH_UPDATE:
1900 err = iscsi_set_path(transport, ev);
1901 break;
Mike Christie56c155b2011-07-25 13:48:37 -05001902 case ISCSI_UEVENT_SET_IFACE_PARAMS:
1903 err = iscsi_set_iface_params(transport, ev);
1904 break;
Alex Aizman0896b752005-08-04 19:33:07 -07001905 default:
Mike Christie1d9bf132007-05-30 12:57:11 -05001906 err = -ENOSYS;
Alex Aizman0896b752005-08-04 19:33:07 -07001907 break;
1908 }
1909
Mike Christie7b7232f2006-02-01 21:06:49 -06001910 module_put(transport->owner);
Alex Aizman0896b752005-08-04 19:33:07 -07001911 return err;
1912}
1913
Mike Christieb5c7a122006-04-06 21:13:33 -05001914/*
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07001915 * Get message from skb. Each message is processed by iscsi_if_recv_msg.
1916 * Malformed skbs with wrong lengths or invalid creds are not processed.
Mike Christieb5c7a122006-04-06 21:13:33 -05001917 */
Alex Aizman0896b752005-08-04 19:33:07 -07001918static void
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07001919iscsi_if_rx(struct sk_buff *skb)
Alex Aizman0896b752005-08-04 19:33:07 -07001920{
Arjan van de Ven0b950672006-01-11 13:16:10 +01001921 mutex_lock(&rx_queue_mutex);
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07001922 while (skb->len >= NLMSG_SPACE(0)) {
1923 int err;
1924 uint32_t rlen;
1925 struct nlmsghdr *nlh;
1926 struct iscsi_uevent *ev;
Michael Chan43514772009-06-08 18:14:41 -07001927 uint32_t group;
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07001928
1929 nlh = nlmsg_hdr(skb);
1930 if (nlh->nlmsg_len < sizeof(*nlh) ||
1931 skb->len < nlh->nlmsg_len) {
1932 break;
Mike Christieee7f8e42006-02-01 21:07:01 -06001933 }
Mike Christieee7f8e42006-02-01 21:07:01 -06001934
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07001935 ev = NLMSG_DATA(nlh);
1936 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
1937 if (rlen > skb->len)
1938 rlen = skb->len;
Alex Aizman0896b752005-08-04 19:33:07 -07001939
Michael Chan43514772009-06-08 18:14:41 -07001940 err = iscsi_if_recv_msg(skb, nlh, &group);
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07001941 if (err) {
1942 ev->type = ISCSI_KEVENT_IF_ERROR;
1943 ev->iferror = err;
1944 }
1945 do {
1946 /*
1947 * special case for GET_STATS:
1948 * on success - sending reply and stats from
1949 * inside of if_recv_msg(),
1950 * on error - fall through.
1951 */
1952 if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
Alex Aizman0896b752005-08-04 19:33:07 -07001953 break;
Michael Chan43514772009-06-08 18:14:41 -07001954 err = iscsi_if_send_reply(group, nlh->nlmsg_seq,
Denis V. Lunevcd40b7d2007-10-10 21:15:29 -07001955 nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
1956 } while (err < 0 && err != -ECONNREFUSED);
1957 skb_pull(skb, rlen);
Alex Aizman0896b752005-08-04 19:33:07 -07001958 }
Arjan van de Ven0b950672006-01-11 13:16:10 +01001959 mutex_unlock(&rx_queue_mutex);
Alex Aizman0896b752005-08-04 19:33:07 -07001960}
1961
Mike Christiefd7255f2006-04-06 21:13:36 -05001962#define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \
Tony Jonesee959b02008-02-22 00:13:36 +01001963struct device_attribute dev_attr_##_prefix##_##_name = \
Mike Christiefd7255f2006-04-06 21:13:36 -05001964 __ATTR(_name,_mode,_show,_store)
1965
Alex Aizman0896b752005-08-04 19:33:07 -07001966/*
1967 * iSCSI connection attrs
1968 */
Mike Christiea54a52c2006-06-28 12:00:23 -05001969#define iscsi_conn_attr_show(param) \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01001971show_conn_param_##param(struct device *dev, \
1972 struct device_attribute *attr, char *buf) \
Mike Christiefd7255f2006-04-06 21:13:36 -05001973{ \
Tony Jonesee959b02008-02-22 00:13:36 +01001974 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
Mike Christiefd7255f2006-04-06 21:13:36 -05001975 struct iscsi_transport *t = conn->transport; \
Mike Christiea54a52c2006-06-28 12:00:23 -05001976 return t->get_conn_param(conn, param, buf); \
Mike Christiefd7255f2006-04-06 21:13:36 -05001977}
1978
Mike Christiea54a52c2006-06-28 12:00:23 -05001979#define iscsi_conn_attr(field, param) \
1980 iscsi_conn_attr_show(param) \
1981static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_param_##param, \
Mike Christiefd7255f2006-04-06 21:13:36 -05001982 NULL);
1983
Mike Christiea54a52c2006-06-28 12:00:23 -05001984iscsi_conn_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH);
1985iscsi_conn_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH);
1986iscsi_conn_attr(header_digest, ISCSI_PARAM_HDRDGST_EN);
1987iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN);
1988iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN);
1989iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN);
1990iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT);
Mike Christiea54a52c2006-06-28 12:00:23 -05001991iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
1992iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
Mike Christief6d51802007-12-13 12:43:30 -06001993iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
1994iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995
Mike Christie289324b2011-02-16 15:04:37 -06001996#define iscsi_conn_ep_attr_show(param) \
1997static ssize_t show_conn_ep_param_##param(struct device *dev, \
1998 struct device_attribute *attr,\
1999 char *buf) \
2000{ \
2001 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
2002 struct iscsi_transport *t = conn->transport; \
2003 struct iscsi_endpoint *ep; \
2004 ssize_t rc; \
2005 \
2006 /* \
2007 * Need to make sure ep_disconnect does not free the LLD's \
2008 * interconnect resources while we are trying to read them. \
2009 */ \
2010 mutex_lock(&conn->ep_mutex); \
2011 ep = conn->ep; \
2012 if (!ep && t->ep_connect) { \
2013 mutex_unlock(&conn->ep_mutex); \
2014 return -ENOTCONN; \
2015 } \
2016 \
2017 if (ep) \
2018 rc = t->get_ep_param(ep, param, buf); \
2019 else \
2020 rc = t->get_conn_param(conn, param, buf); \
2021 mutex_unlock(&conn->ep_mutex); \
2022 return rc; \
2023}
2024
2025#define iscsi_conn_ep_attr(field, param) \
2026 iscsi_conn_ep_attr_show(param) \
2027static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, \
2028 show_conn_ep_param_##param, NULL);
2029
2030iscsi_conn_ep_attr(address, ISCSI_PARAM_CONN_ADDRESS);
2031iscsi_conn_ep_attr(port, ISCSI_PARAM_CONN_PORT);
2032
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033/*
Alex Aizman0896b752005-08-04 19:33:07 -07002034 * iSCSI session attrs
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 */
Mike Christieb2c64162007-05-30 12:57:16 -05002036#define iscsi_session_attr_show(param, perm) \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01002038show_session_param_##param(struct device *dev, \
2039 struct device_attribute *attr, char *buf) \
Mike Christiefd7255f2006-04-06 21:13:36 -05002040{ \
Tony Jonesee959b02008-02-22 00:13:36 +01002041 struct iscsi_cls_session *session = \
2042 iscsi_dev_to_session(dev->parent); \
Mike Christiefd7255f2006-04-06 21:13:36 -05002043 struct iscsi_transport *t = session->transport; \
Mike Christieb2c64162007-05-30 12:57:16 -05002044 \
2045 if (perm && !capable(CAP_SYS_ADMIN)) \
2046 return -EACCES; \
Mike Christiea54a52c2006-06-28 12:00:23 -05002047 return t->get_session_param(session, param, buf); \
Mike Christiefd7255f2006-04-06 21:13:36 -05002048}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
Mike Christieb2c64162007-05-30 12:57:16 -05002050#define iscsi_session_attr(field, param, perm) \
2051 iscsi_session_attr_show(param, perm) \
Mike Christiea54a52c2006-06-28 12:00:23 -05002052static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \
Mike Christiefd7255f2006-04-06 21:13:36 -05002053 NULL);
2054
Mike Christieb2c64162007-05-30 12:57:16 -05002055iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME, 0);
2056iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, 0);
2057iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, 0);
2058iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, 0);
2059iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, 0);
2060iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, 0);
2061iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, 0);
2062iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, 0);
2063iscsi_session_attr(erl, ISCSI_PARAM_ERL, 0);
2064iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT, 0);
2065iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1);
2066iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
2067iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
2068iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
Mike Christie4cd49ea2007-12-13 12:43:38 -06002069iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
2070iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
2071iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
Mike Christie3fe5ae82009-11-11 16:34:33 -06002072iscsi_session_attr(tgt_reset_tmo, ISCSI_PARAM_TGT_RESET_TMO, 0);
Mike Christie88dfd342008-05-21 15:54:16 -05002073iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
Vikas Chaudhary3b2bef12010-07-10 14:51:30 +05302074iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0);
2075iscsi_session_attr(targetalias, ISCSI_PARAM_TARGET_ALIAS, 0);
Mike Christiefd7255f2006-04-06 21:13:36 -05002076
Mike Christie6eabafb2008-01-31 13:36:43 -06002077static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01002078show_priv_session_state(struct device *dev, struct device_attribute *attr,
2079 char *buf)
Mike Christie6eabafb2008-01-31 13:36:43 -06002080{
Tony Jonesee959b02008-02-22 00:13:36 +01002081 struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
Mike Christie6eabafb2008-01-31 13:36:43 -06002082 return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
2083}
2084static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
2085 NULL);
2086
Mike Christiefd7255f2006-04-06 21:13:36 -05002087#define iscsi_priv_session_attr_show(field, format) \
2088static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01002089show_priv_session_##field(struct device *dev, \
2090 struct device_attribute *attr, char *buf) \
Mike Christiefd7255f2006-04-06 21:13:36 -05002091{ \
Tony Jonesee959b02008-02-22 00:13:36 +01002092 struct iscsi_cls_session *session = \
2093 iscsi_dev_to_session(dev->parent); \
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05302094 if (session->field == -1) \
2095 return sprintf(buf, "off\n"); \
Mike Christiefd7255f2006-04-06 21:13:36 -05002096 return sprintf(buf, format"\n", session->field); \
2097}
2098
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05302099#define iscsi_priv_session_attr_store(field) \
2100static ssize_t \
2101store_priv_session_##field(struct device *dev, \
2102 struct device_attribute *attr, \
2103 const char *buf, size_t count) \
2104{ \
2105 int val; \
2106 char *cp; \
2107 struct iscsi_cls_session *session = \
2108 iscsi_dev_to_session(dev->parent); \
2109 if ((session->state == ISCSI_SESSION_FREE) || \
2110 (session->state == ISCSI_SESSION_FAILED)) \
2111 return -EBUSY; \
2112 if (strncmp(buf, "off", 3) == 0) \
2113 session->field = -1; \
2114 else { \
2115 val = simple_strtoul(buf, &cp, 0); \
2116 if (*cp != '\0' && *cp != '\n') \
2117 return -EINVAL; \
2118 session->field = val; \
2119 } \
2120 return count; \
2121}
2122
2123#define iscsi_priv_session_rw_attr(field, format) \
Mike Christiefd7255f2006-04-06 21:13:36 -05002124 iscsi_priv_session_attr_show(field, format) \
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05302125 iscsi_priv_session_attr_store(field) \
Vasiliy Kulikov523f3c82011-02-04 15:24:14 +03002126static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUSR, \
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05302127 show_priv_session_##field, \
2128 store_priv_session_##field)
2129iscsi_priv_session_rw_attr(recovery_tmo, "%d");
Mike Christiefd7255f2006-04-06 21:13:36 -05002130
Mike Christie1819dc82007-05-30 12:57:08 -05002131/*
2132 * iSCSI host attrs
2133 */
2134#define iscsi_host_attr_show(param) \
2135static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01002136show_host_param_##param(struct device *dev, \
2137 struct device_attribute *attr, char *buf) \
Mike Christie1819dc82007-05-30 12:57:08 -05002138{ \
Tony Jonesee959b02008-02-22 00:13:36 +01002139 struct Scsi_Host *shost = transport_class_to_shost(dev); \
Mike Christie1819dc82007-05-30 12:57:08 -05002140 struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
2141 return priv->iscsi_transport->get_host_param(shost, param, buf); \
2142}
2143
2144#define iscsi_host_attr(field, param) \
2145 iscsi_host_attr_show(param) \
2146static ISCSI_CLASS_ATTR(host, field, S_IRUGO, show_host_param_##param, \
2147 NULL);
2148
Mike Christied8196ed2007-05-30 12:57:25 -05002149iscsi_host_attr(netdev, ISCSI_HOST_PARAM_NETDEV_NAME);
Mike Christie1819dc82007-05-30 12:57:08 -05002150iscsi_host_attr(hwaddress, ISCSI_HOST_PARAM_HWADDRESS);
Mike Christied8196ed2007-05-30 12:57:25 -05002151iscsi_host_attr(ipaddress, ISCSI_HOST_PARAM_IPADDRESS);
Mike Christie8ad57812007-05-30 12:57:13 -05002152iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
Mike Christie1819dc82007-05-30 12:57:08 -05002153
Mike Christiefd7255f2006-04-06 21:13:36 -05002154#define SETUP_PRIV_SESSION_RD_ATTR(field) \
2155do { \
Tony Jonesee959b02008-02-22 00:13:36 +01002156 priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
Mike Christiefd7255f2006-04-06 21:13:36 -05002157 count++; \
2158} while (0)
2159
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05302160#define SETUP_PRIV_SESSION_RW_ATTR(field) \
2161do { \
2162 priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
2163 count++; \
2164} while (0)
Mike Christiea54a52c2006-06-28 12:00:23 -05002165
Mike Christiefd7255f2006-04-06 21:13:36 -05002166#define SETUP_SESSION_RD_ATTR(field, param_flag) \
2167do { \
2168 if (tt->param_mask & param_flag) { \
Tony Jonesee959b02008-02-22 00:13:36 +01002169 priv->session_attrs[count] = &dev_attr_sess_##field; \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 count++; \
Mike Christiefd7255f2006-04-06 21:13:36 -05002171 } \
2172} while (0)
2173
Mike Christiefd7255f2006-04-06 21:13:36 -05002174#define SETUP_CONN_RD_ATTR(field, param_flag) \
2175do { \
2176 if (tt->param_mask & param_flag) { \
Tony Jonesee959b02008-02-22 00:13:36 +01002177 priv->conn_attrs[count] = &dev_attr_conn_##field; \
Mike Christiefd7255f2006-04-06 21:13:36 -05002178 count++; \
2179 } \
2180} while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181
Mike Christie1819dc82007-05-30 12:57:08 -05002182#define SETUP_HOST_RD_ATTR(field, param_flag) \
2183do { \
2184 if (tt->host_param_mask & param_flag) { \
Tony Jonesee959b02008-02-22 00:13:36 +01002185 priv->host_attrs[count] = &dev_attr_host_##field; \
Mike Christie1819dc82007-05-30 12:57:08 -05002186 count++; \
2187 } \
2188} while (0)
2189
Alex Aizman0896b752005-08-04 19:33:07 -07002190static int iscsi_session_match(struct attribute_container *cont,
2191 struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192{
Mike Christie7b8631b2006-01-13 18:05:50 -06002193 struct iscsi_cls_session *session;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 struct Scsi_Host *shost;
Alex Aizman0896b752005-08-04 19:33:07 -07002195 struct iscsi_internal *priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196
Alex Aizman0896b752005-08-04 19:33:07 -07002197 if (!iscsi_is_session_dev(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 return 0;
2199
Mike Christie7b8631b2006-01-13 18:05:50 -06002200 session = iscsi_dev_to_session(dev);
2201 shost = iscsi_session_to_shost(session);
Alex Aizman0896b752005-08-04 19:33:07 -07002202 if (!shost->transportt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 return 0;
2204
Alex Aizman0896b752005-08-04 19:33:07 -07002205 priv = to_iscsi_internal(shost->transportt);
2206 if (priv->session_cont.ac.class != &iscsi_session_class.class)
2207 return 0;
2208
2209 return &priv->session_cont.ac == cont;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210}
2211
Alex Aizman0896b752005-08-04 19:33:07 -07002212static int iscsi_conn_match(struct attribute_container *cont,
2213 struct device *dev)
2214{
Mike Christie7b8631b2006-01-13 18:05:50 -06002215 struct iscsi_cls_session *session;
2216 struct iscsi_cls_conn *conn;
Alex Aizman0896b752005-08-04 19:33:07 -07002217 struct Scsi_Host *shost;
2218 struct iscsi_internal *priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
Alex Aizman0896b752005-08-04 19:33:07 -07002220 if (!iscsi_is_conn_dev(dev))
2221 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
Mike Christie7b8631b2006-01-13 18:05:50 -06002223 conn = iscsi_dev_to_conn(dev);
2224 session = iscsi_dev_to_session(conn->dev.parent);
2225 shost = iscsi_session_to_shost(session);
2226
Alex Aizman0896b752005-08-04 19:33:07 -07002227 if (!shost->transportt)
2228 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229
Alex Aizman0896b752005-08-04 19:33:07 -07002230 priv = to_iscsi_internal(shost->transportt);
2231 if (priv->conn_cont.ac.class != &iscsi_connection_class.class)
2232 return 0;
2233
2234 return &priv->conn_cont.ac == cont;
2235}
2236
Mike Christie30a6c652006-04-06 21:13:39 -05002237static int iscsi_host_match(struct attribute_container *cont,
2238 struct device *dev)
2239{
2240 struct Scsi_Host *shost;
2241 struct iscsi_internal *priv;
2242
2243 if (!scsi_is_host_device(dev))
2244 return 0;
2245
2246 shost = dev_to_shost(dev);
2247 if (!shost->transportt ||
2248 shost->transportt->host_attrs.ac.class != &iscsi_host_class.class)
2249 return 0;
2250
2251 priv = to_iscsi_internal(shost->transportt);
2252 return &priv->t.host_attrs.ac == cont;
2253}
2254
Mike Christie7b8631b2006-01-13 18:05:50 -06002255struct scsi_transport_template *
2256iscsi_register_transport(struct iscsi_transport *tt)
Alex Aizman0896b752005-08-04 19:33:07 -07002257{
2258 struct iscsi_internal *priv;
2259 unsigned long flags;
2260 int count = 0, err;
2261
2262 BUG_ON(!tt);
2263
2264 priv = iscsi_if_transport_lookup(tt);
2265 if (priv)
Mike Christie7b8631b2006-01-13 18:05:50 -06002266 return NULL;
Alex Aizman0896b752005-08-04 19:33:07 -07002267
Jes Sorensen24669f752006-01-16 10:31:18 -05002268 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
Alex Aizman0896b752005-08-04 19:33:07 -07002269 if (!priv)
Mike Christie7b8631b2006-01-13 18:05:50 -06002270 return NULL;
Alex Aizman0896b752005-08-04 19:33:07 -07002271 INIT_LIST_HEAD(&priv->list);
Alex Aizman0896b752005-08-04 19:33:07 -07002272 priv->iscsi_transport = tt;
Mike Christie30a6c652006-04-06 21:13:39 -05002273 priv->t.user_scan = iscsi_user_scan;
Mike Christie06d25af2009-03-05 14:46:02 -06002274 priv->t.create_work_queue = 1;
Alex Aizman0896b752005-08-04 19:33:07 -07002275
Tony Jonesee959b02008-02-22 00:13:36 +01002276 priv->dev.class = &iscsi_transport_class;
Kay Sievers71610f52008-12-03 22:41:36 +01002277 dev_set_name(&priv->dev, "%s", tt->name);
Tony Jonesee959b02008-02-22 00:13:36 +01002278 err = device_register(&priv->dev);
Alex Aizman0896b752005-08-04 19:33:07 -07002279 if (err)
2280 goto free_priv;
2281
Tony Jonesee959b02008-02-22 00:13:36 +01002282 err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
Alex Aizman0896b752005-08-04 19:33:07 -07002283 if (err)
Tony Jonesee959b02008-02-22 00:13:36 +01002284 goto unregister_dev;
Alex Aizman0896b752005-08-04 19:33:07 -07002285
Mike Christie30a6c652006-04-06 21:13:39 -05002286 /* host parameters */
2287 priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
2288 priv->t.host_attrs.ac.class = &iscsi_host_class.class;
2289 priv->t.host_attrs.ac.match = iscsi_host_match;
Mike Christie32c6e1b2008-05-21 15:53:58 -05002290 priv->t.host_size = sizeof(struct iscsi_cls_host);
Mike Christie30a6c652006-04-06 21:13:39 -05002291 transport_container_register(&priv->t.host_attrs);
2292
Mike Christied8196ed2007-05-30 12:57:25 -05002293 SETUP_HOST_RD_ATTR(netdev, ISCSI_HOST_NETDEV_NAME);
Mike Christie22236962007-05-30 12:57:24 -05002294 SETUP_HOST_RD_ATTR(ipaddress, ISCSI_HOST_IPADDRESS);
Mike Christie1819dc82007-05-30 12:57:08 -05002295 SETUP_HOST_RD_ATTR(hwaddress, ISCSI_HOST_HWADDRESS);
Mike Christie8ad57812007-05-30 12:57:13 -05002296 SETUP_HOST_RD_ATTR(initiatorname, ISCSI_HOST_INITIATOR_NAME);
Mike Christie1819dc82007-05-30 12:57:08 -05002297 BUG_ON(count > ISCSI_HOST_ATTRS);
2298 priv->host_attrs[count] = NULL;
2299 count = 0;
2300
Alex Aizman0896b752005-08-04 19:33:07 -07002301 /* connection parameters */
2302 priv->conn_cont.ac.attrs = &priv->conn_attrs[0];
2303 priv->conn_cont.ac.class = &iscsi_connection_class.class;
2304 priv->conn_cont.ac.match = iscsi_conn_match;
2305 transport_container_register(&priv->conn_cont);
2306
Mike Christiefd7255f2006-04-06 21:13:36 -05002307 SETUP_CONN_RD_ATTR(max_recv_dlength, ISCSI_MAX_RECV_DLENGTH);
2308 SETUP_CONN_RD_ATTR(max_xmit_dlength, ISCSI_MAX_XMIT_DLENGTH);
2309 SETUP_CONN_RD_ATTR(header_digest, ISCSI_HDRDGST_EN);
2310 SETUP_CONN_RD_ATTR(data_digest, ISCSI_DATADGST_EN);
2311 SETUP_CONN_RD_ATTR(ifmarker, ISCSI_IFMARKER_EN);
2312 SETUP_CONN_RD_ATTR(ofmarker, ISCSI_OFMARKER_EN);
2313 SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS);
2314 SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT);
Mike Christie8d2860b2006-05-02 19:46:47 -05002315 SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);
Mike Christiea54a52c2006-06-28 12:00:23 -05002316 SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
2317 SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
Mike Christief6d51802007-12-13 12:43:30 -06002318 SETUP_CONN_RD_ATTR(ping_tmo, ISCSI_PING_TMO);
2319 SETUP_CONN_RD_ATTR(recv_tmo, ISCSI_RECV_TMO);
Alex Aizman0896b752005-08-04 19:33:07 -07002320
2321 BUG_ON(count > ISCSI_CONN_ATTRS);
2322 priv->conn_attrs[count] = NULL;
2323 count = 0;
2324
2325 /* session parameters */
2326 priv->session_cont.ac.attrs = &priv->session_attrs[0];
2327 priv->session_cont.ac.class = &iscsi_session_class.class;
2328 priv->session_cont.ac.match = iscsi_session_match;
2329 transport_container_register(&priv->session_cont);
2330
Mike Christiefd7255f2006-04-06 21:13:36 -05002331 SETUP_SESSION_RD_ATTR(initial_r2t, ISCSI_INITIAL_R2T_EN);
2332 SETUP_SESSION_RD_ATTR(max_outstanding_r2t, ISCSI_MAX_R2T);
2333 SETUP_SESSION_RD_ATTR(immediate_data, ISCSI_IMM_DATA_EN);
2334 SETUP_SESSION_RD_ATTR(first_burst_len, ISCSI_FIRST_BURST);
2335 SETUP_SESSION_RD_ATTR(max_burst_len, ISCSI_MAX_BURST);
2336 SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN);
2337 SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN);
2338 SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL);
Mike Christiea54a52c2006-06-28 12:00:23 -05002339 SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
2340 SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT);
Mike Christieb2c64162007-05-30 12:57:16 -05002341 SETUP_SESSION_RD_ATTR(password, ISCSI_USERNAME);
2342 SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN);
2343 SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD);
2344 SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN);
Mike Christie843c0a82007-12-13 12:43:20 -06002345 SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT);
Mike Christie4cd49ea2007-12-13 12:43:38 -06002346 SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO);
2347 SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO);
Mike Christie3fe5ae82009-11-11 16:34:33 -06002348 SETUP_SESSION_RD_ATTR(tgt_reset_tmo,ISCSI_TGT_RESET_TMO);
Mike Christie88dfd342008-05-21 15:54:16 -05002349 SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME);
2350 SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME);
Vikas Chaudhary3b2bef12010-07-10 14:51:30 +05302351 SETUP_SESSION_RD_ATTR(targetalias, ISCSI_TARGET_ALIAS);
Vikas Chaudharyfe4f0bd2010-07-22 16:57:43 +05302352 SETUP_PRIV_SESSION_RW_ATTR(recovery_tmo);
Mike Christie6eabafb2008-01-31 13:36:43 -06002353 SETUP_PRIV_SESSION_RD_ATTR(state);
Mike Christiefd7255f2006-04-06 21:13:36 -05002354
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 BUG_ON(count > ISCSI_SESSION_ATTRS);
Alex Aizman0896b752005-08-04 19:33:07 -07002356 priv->session_attrs[count] = NULL;
Mike Christie8d079132011-07-25 13:48:40 -05002357 count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358
Alex Aizman0896b752005-08-04 19:33:07 -07002359 spin_lock_irqsave(&iscsi_transport_lock, flags);
2360 list_add(&priv->list, &iscsi_transports);
2361 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362
Alex Aizman0896b752005-08-04 19:33:07 -07002363 printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
Mike Christie7b8631b2006-01-13 18:05:50 -06002364 return &priv->t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365
Tony Jonesee959b02008-02-22 00:13:36 +01002366unregister_dev:
2367 device_unregister(&priv->dev);
Mike Christied82ff9be2008-05-21 15:54:13 -05002368 return NULL;
Alex Aizman0896b752005-08-04 19:33:07 -07002369free_priv:
2370 kfree(priv);
Mike Christie7b8631b2006-01-13 18:05:50 -06002371 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372}
Alex Aizman0896b752005-08-04 19:33:07 -07002373EXPORT_SYMBOL_GPL(iscsi_register_transport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
Alex Aizman0896b752005-08-04 19:33:07 -07002375int iscsi_unregister_transport(struct iscsi_transport *tt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376{
Alex Aizman0896b752005-08-04 19:33:07 -07002377 struct iscsi_internal *priv;
2378 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379
Alex Aizman0896b752005-08-04 19:33:07 -07002380 BUG_ON(!tt);
2381
Arjan van de Ven0b950672006-01-11 13:16:10 +01002382 mutex_lock(&rx_queue_mutex);
Alex Aizman0896b752005-08-04 19:33:07 -07002383
2384 priv = iscsi_if_transport_lookup(tt);
2385 BUG_ON (!priv);
2386
Alex Aizman0896b752005-08-04 19:33:07 -07002387 spin_lock_irqsave(&iscsi_transport_lock, flags);
2388 list_del(&priv->list);
2389 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
2390
2391 transport_container_unregister(&priv->conn_cont);
2392 transport_container_unregister(&priv->session_cont);
Mike Christie30a6c652006-04-06 21:13:39 -05002393 transport_container_unregister(&priv->t.host_attrs);
Alex Aizman0896b752005-08-04 19:33:07 -07002394
Tony Jonesee959b02008-02-22 00:13:36 +01002395 sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
2396 device_unregister(&priv->dev);
Arjan van de Ven0b950672006-01-11 13:16:10 +01002397 mutex_unlock(&rx_queue_mutex);
Alex Aizman0896b752005-08-04 19:33:07 -07002398
2399 return 0;
2400}
2401EXPORT_SYMBOL_GPL(iscsi_unregister_transport);
2402
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403static __init int iscsi_transport_init(void)
2404{
Alex Aizman0896b752005-08-04 19:33:07 -07002405 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
Meelis Roos09492602006-12-17 12:10:26 -06002407 printk(KERN_INFO "Loading iSCSI transport class v%s.\n",
Mike Christief4246b32006-07-24 15:47:54 -05002408 ISCSI_TRANSPORT_VERSION);
2409
Mike Christie41be1442007-02-28 17:32:18 -06002410 atomic_set(&iscsi_session_nr, 0);
2411
Alex Aizman0896b752005-08-04 19:33:07 -07002412 err = class_register(&iscsi_transport_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 if (err)
2414 return err;
Alex Aizman0896b752005-08-04 19:33:07 -07002415
Mike Christied82ff9be2008-05-21 15:54:13 -05002416 err = class_register(&iscsi_endpoint_class);
Alex Aizman0896b752005-08-04 19:33:07 -07002417 if (err)
2418 goto unregister_transport_class;
2419
Mike Christie8d079132011-07-25 13:48:40 -05002420 err = class_register(&iscsi_iface_class);
Mike Christied82ff9be2008-05-21 15:54:13 -05002421 if (err)
2422 goto unregister_endpoint_class;
2423
Mike Christie8d079132011-07-25 13:48:40 -05002424 err = transport_class_register(&iscsi_host_class);
2425 if (err)
2426 goto unregister_iface_class;
2427
Mike Christie30a6c652006-04-06 21:13:39 -05002428 err = transport_class_register(&iscsi_connection_class);
2429 if (err)
2430 goto unregister_host_class;
2431
Alex Aizman0896b752005-08-04 19:33:07 -07002432 err = transport_class_register(&iscsi_session_class);
2433 if (err)
2434 goto unregister_conn_class;
2435
Mike Christied82ff9be2008-05-21 15:54:13 -05002436 nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx,
2437 NULL, THIS_MODULE);
Alex Aizman0896b752005-08-04 19:33:07 -07002438 if (!nls) {
2439 err = -ENOBUFS;
Mike Christie43a145a2006-10-16 18:09:38 -04002440 goto unregister_session_class;
Alex Aizman0896b752005-08-04 19:33:07 -07002441 }
2442
Mike Christied8bf5412007-12-13 12:43:27 -06002443 iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh");
2444 if (!iscsi_eh_timer_workq)
2445 goto release_nls;
2446
Mike Christie43a145a2006-10-16 18:09:38 -04002447 return 0;
Alex Aizman0896b752005-08-04 19:33:07 -07002448
Mike Christied8bf5412007-12-13 12:43:27 -06002449release_nls:
Denis V. Lunevb7c6ba62008-01-28 14:41:19 -08002450 netlink_kernel_release(nls);
Alex Aizman0896b752005-08-04 19:33:07 -07002451unregister_session_class:
2452 transport_class_unregister(&iscsi_session_class);
2453unregister_conn_class:
2454 transport_class_unregister(&iscsi_connection_class);
Mike Christie30a6c652006-04-06 21:13:39 -05002455unregister_host_class:
2456 transport_class_unregister(&iscsi_host_class);
Mike Christie8d079132011-07-25 13:48:40 -05002457unregister_iface_class:
2458 class_unregister(&iscsi_iface_class);
Mike Christied82ff9be2008-05-21 15:54:13 -05002459unregister_endpoint_class:
2460 class_unregister(&iscsi_endpoint_class);
Alex Aizman0896b752005-08-04 19:33:07 -07002461unregister_transport_class:
2462 class_unregister(&iscsi_transport_class);
2463 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464}
2465
2466static void __exit iscsi_transport_exit(void)
2467{
Mike Christied8bf5412007-12-13 12:43:27 -06002468 destroy_workqueue(iscsi_eh_timer_workq);
Denis V. Lunevb7c6ba62008-01-28 14:41:19 -08002469 netlink_kernel_release(nls);
Alex Aizman0896b752005-08-04 19:33:07 -07002470 transport_class_unregister(&iscsi_connection_class);
2471 transport_class_unregister(&iscsi_session_class);
Mike Christie30a6c652006-04-06 21:13:39 -05002472 transport_class_unregister(&iscsi_host_class);
Mike Christied82ff9be2008-05-21 15:54:13 -05002473 class_unregister(&iscsi_endpoint_class);
Mike Christie8d079132011-07-25 13:48:40 -05002474 class_unregister(&iscsi_iface_class);
Alex Aizman0896b752005-08-04 19:33:07 -07002475 class_unregister(&iscsi_transport_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476}
2477
2478module_init(iscsi_transport_init);
2479module_exit(iscsi_transport_exit);
2480
Alex Aizman0896b752005-08-04 19:33:07 -07002481MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
2482 "Dmitry Yusupov <dmitry_yus@yahoo.com>, "
2483 "Alex Aizman <itn780@yahoo.com>");
2484MODULE_DESCRIPTION("iSCSI Transport Interface");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485MODULE_LICENSE("GPL");
Mike Christief4246b32006-07-24 15:47:54 -05002486MODULE_VERSION(ISCSI_TRANSPORT_VERSION);
Stephen Hemminger058548a2010-12-09 09:37:56 -08002487MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_ISCSI);