[SCSI] iscsi: add sysfs attrs for uspace sync up
[deliverable/linux.git] / drivers / scsi / scsi_transport_iscsi.c
CommitLineData
0896b752 1/*
1da177e4
LT
2 * iSCSI transport class definitions
3 *
4 * Copyright (C) IBM Corporation, 2004
0896b752
AA
5 * Copyright (C) Mike Christie, 2004 - 2005
6 * Copyright (C) Dmitry Yusupov, 2004 - 2005
7 * Copyright (C) Alex Aizman, 2004 - 2005
1da177e4
LT
8 *
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>
0896b752 24#include <linux/mempool.h>
0b950672 25#include <linux/mutex.h>
0896b752 26#include <net/tcp.h>
1da177e4
LT
27#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>
0896b752 32#include <scsi/iscsi_if.h>
1da177e4 33
fd7255f5
MC
34#define ISCSI_SESSION_ATTRS 10
35#define ISCSI_CONN_ATTRS 10
1da177e4
LT
36
37struct iscsi_internal {
38 struct scsi_transport_template t;
0896b752
AA
39 struct iscsi_transport *iscsi_transport;
40 struct list_head list;
0896b752 41 struct class_device cdev;
1da177e4
LT
42 /*
43 * We do not have any private or other attrs.
44 */
0896b752
AA
45 struct transport_container conn_cont;
46 struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
47 struct transport_container session_cont;
1da177e4 48 struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
1da177e4
LT
49};
50
b5c7a12d
MC
51static int iscsi_session_nr; /* sysfs session id for next new session */
52
0896b752
AA
53/*
54 * list of registered transports and lock that must
55 * be held while accessing list. The iscsi_transport_lock must
0b950672 56 * be acquired after the rx_queue_mutex.
0896b752
AA
57 */
58static LIST_HEAD(iscsi_transports);
59static DEFINE_SPINLOCK(iscsi_transport_lock);
60
61#define to_iscsi_internal(tmpl) \
62 container_of(tmpl, struct iscsi_internal, t)
63
64#define cdev_to_iscsi_internal(_cdev) \
65 container_of(_cdev, struct iscsi_internal, cdev)
66
67static void iscsi_transport_release(struct class_device *cdev)
68{
69 struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
70 kfree(priv);
71}
1da177e4 72
0896b752
AA
73/*
74 * iscsi_transport_class represents the iscsi_transports that are
75 * registered.
76 */
77static struct class iscsi_transport_class = {
78 .name = "iscsi_transport",
79 .release = iscsi_transport_release,
80};
81
82static ssize_t
83show_transport_handle(struct class_device *cdev, char *buf)
84{
85 struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev);
762e2bfa 86 return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
0896b752
AA
87}
88static CLASS_DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
89
90#define show_transport_attr(name, format) \
91static ssize_t \
92show_transport_##name(struct class_device *cdev, char *buf) \
93{ \
94 struct iscsi_internal *priv = cdev_to_iscsi_internal(cdev); \
95 return sprintf(buf, format"\n", priv->iscsi_transport->name); \
96} \
97static CLASS_DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
98
99show_transport_attr(caps, "0x%x");
100show_transport_attr(max_lun, "%d");
101show_transport_attr(max_conn, "%d");
102show_transport_attr(max_cmd_len, "%d");
103
104static struct attribute *iscsi_transport_attrs[] = {
105 &class_device_attr_handle.attr,
106 &class_device_attr_caps.attr,
107 &class_device_attr_max_lun.attr,
108 &class_device_attr_max_conn.attr,
109 &class_device_attr_max_cmd_len.attr,
110 NULL,
111};
112
113static struct attribute_group iscsi_transport_group = {
114 .attrs = iscsi_transport_attrs,
115};
116
117static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
118 "iscsi_session",
1da177e4
LT
119 NULL,
120 NULL,
121 NULL);
122
0896b752
AA
123static DECLARE_TRANSPORT_CLASS(iscsi_connection_class,
124 "iscsi_connection",
1da177e4
LT
125 NULL,
126 NULL,
127 NULL);
0896b752
AA
128
129static struct sock *nls;
130static int daemon_pid;
0b950672 131static DEFINE_MUTEX(rx_queue_mutex);
0896b752
AA
132
133struct mempool_zone {
134 mempool_t *pool;
135 atomic_t allocated;
136 int size;
137 int hiwat;
138 struct list_head freequeue;
139 spinlock_t freelock;
140};
141
7b8631b5 142static struct mempool_zone *z_reply;
0896b752 143
1da177e4 144/*
0896b752
AA
145 * Z_MAX_* - actual mempool size allocated at the mempool_zone_init() time
146 * Z_HIWAT_* - zone's high watermark when if_error bit will be set to -ENOMEM
147 * so daemon will notice OOM on NETLINK tranposrt level and will
148 * be able to predict or change operational behavior
1da177e4 149 */
0896b752
AA
150#define Z_MAX_REPLY 8
151#define Z_HIWAT_REPLY 6
152#define Z_MAX_PDU 8
153#define Z_HIWAT_PDU 6
154#define Z_MAX_ERROR 16
155#define Z_HIWAT_ERROR 12
156
7b7232f3
MC
157static LIST_HEAD(sesslist);
158static DEFINE_SPINLOCK(sesslock);
7b8631b5
MC
159static LIST_HEAD(connlist);
160static DEFINE_SPINLOCK(connlock);
0896b752 161
b5c7a12d
MC
162static uint32_t iscsi_conn_get_sid(struct iscsi_cls_conn *conn)
163{
164 struct iscsi_cls_session *sess = iscsi_dev_to_session(conn->dev.parent);
165 return sess->sid;
166}
167
168/*
169 * Returns the matching session to a given sid
170 */
171static struct iscsi_cls_session *iscsi_session_lookup(uint32_t sid)
7b7232f3
MC
172{
173 unsigned long flags;
174 struct iscsi_cls_session *sess;
175
176 spin_lock_irqsave(&sesslock, flags);
177 list_for_each_entry(sess, &sesslist, sess_list) {
b5c7a12d 178 if (sess->sid == sid) {
7b7232f3
MC
179 spin_unlock_irqrestore(&sesslock, flags);
180 return sess;
181 }
182 }
183 spin_unlock_irqrestore(&sesslock, flags);
184 return NULL;
185}
186
b5c7a12d
MC
187/*
188 * Returns the matching connection to a given sid / cid tuple
189 */
190static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid)
7b7232f3
MC
191{
192 unsigned long flags;
193 struct iscsi_cls_conn *conn;
194
195 spin_lock_irqsave(&connlock, flags);
196 list_for_each_entry(conn, &connlist, conn_list) {
b5c7a12d 197 if ((conn->cid == cid) && (iscsi_conn_get_sid(conn) == sid)) {
7b7232f3
MC
198 spin_unlock_irqrestore(&connlock, flags);
199 return conn;
200 }
201 }
202 spin_unlock_irqrestore(&connlock, flags);
203 return NULL;
204}
205
7b8631b5
MC
206/*
207 * The following functions can be used by LLDs that allocate
208 * their own scsi_hosts or by software iscsi LLDs
209 */
210static void iscsi_session_release(struct device *dev)
211{
212 struct iscsi_cls_session *session = iscsi_dev_to_session(dev);
213 struct iscsi_transport *transport = session->transport;
214 struct Scsi_Host *shost;
0896b752 215
7b8631b5
MC
216 shost = iscsi_session_to_shost(session);
217 scsi_host_put(shost);
fd7255f5 218 kfree(session->targetname);
7b8631b5
MC
219 kfree(session);
220 module_put(transport->owner);
221}
0896b752 222
7b8631b5
MC
223static int iscsi_is_session_dev(const struct device *dev)
224{
225 return dev->release == iscsi_session_release;
226}
0896b752 227
7b8631b5
MC
228/**
229 * iscsi_create_session - create iscsi class session
230 * @shost: scsi host
231 * @transport: iscsi transport
232 *
b5c7a12d 233 * This can be called from a LLD or iscsi_transport.
7b8631b5
MC
234 **/
235struct iscsi_cls_session *
236iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport)
237{
238 struct iscsi_cls_session *session;
239 int err;
240
241 if (!try_module_get(transport->owner))
242 return NULL;
243
b5c7a12d
MC
244 session = kzalloc(sizeof(*session) + transport->sessiondata_size,
245 GFP_KERNEL);
7b8631b5
MC
246 if (!session)
247 goto module_put;
248 session->transport = transport;
249
b5c7a12d
MC
250 if (transport->sessiondata_size)
251 session->dd_data = &session[1];
252
7b8631b5
MC
253 /* this is released in the dev's release function */
254 scsi_host_get(shost);
b5c7a12d
MC
255 session->sid = iscsi_session_nr++;
256 snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
257 session->sid);
7b8631b5
MC
258 session->dev.parent = &shost->shost_gendev;
259 session->dev.release = iscsi_session_release;
260 err = device_register(&session->dev);
261 if (err) {
262 dev_printk(KERN_ERR, &session->dev, "iscsi: could not "
263 "register session's dev\n");
264 goto free_session;
265 }
266 transport_register_device(&session->dev);
267
268 return session;
269
270free_session:
271 kfree(session);
272module_put:
273 module_put(transport->owner);
274 return NULL;
275}
276
277EXPORT_SYMBOL_GPL(iscsi_create_session);
278
279/**
280 * iscsi_destroy_session - destroy iscsi session
281 * @session: iscsi_session
282 *
283 * Can be called by a LLD or iscsi_transport. There must not be
284 * any running connections.
285 **/
286int iscsi_destroy_session(struct iscsi_cls_session *session)
287{
288 transport_unregister_device(&session->dev);
289 device_unregister(&session->dev);
290 return 0;
291}
292
293EXPORT_SYMBOL_GPL(iscsi_destroy_session);
294
295static void iscsi_conn_release(struct device *dev)
296{
297 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
298 struct device *parent = conn->dev.parent;
299
fd7255f5 300 kfree(conn->persistent_address);
7b8631b5
MC
301 kfree(conn);
302 put_device(parent);
303}
304
305static int iscsi_is_conn_dev(const struct device *dev)
306{
307 return dev->release == iscsi_conn_release;
308}
309
310/**
311 * iscsi_create_conn - create iscsi class connection
312 * @session: iscsi cls session
313 * @cid: connection id
314 *
315 * This can be called from a LLD or iscsi_transport. The connection
316 * is child of the session so cid must be unique for all connections
317 * on the session.
b5c7a12d
MC
318 *
319 * Since we do not support MCS, cid will normally be zero. In some cases
320 * for software iscsi we could be trying to preallocate a connection struct
321 * in which case there could be two connection structs and cid would be
322 * non-zero.
7b8631b5
MC
323 **/
324struct iscsi_cls_conn *
325iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
326{
327 struct iscsi_transport *transport = session->transport;
7b8631b5
MC
328 struct iscsi_cls_conn *conn;
329 int err;
330
331 conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL);
332 if (!conn)
333 return NULL;
334
335 if (transport->conndata_size)
336 conn->dd_data = &conn[1];
337
338 INIT_LIST_HEAD(&conn->conn_list);
339 conn->transport = transport;
b5c7a12d 340 conn->cid = cid;
7b8631b5
MC
341
342 /* this is released in the dev's release function */
343 if (!get_device(&session->dev))
344 goto free_conn;
b5c7a12d 345
7b8631b5 346 snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
b5c7a12d 347 session->sid, cid);
7b8631b5
MC
348 conn->dev.parent = &session->dev;
349 conn->dev.release = iscsi_conn_release;
350 err = device_register(&conn->dev);
351 if (err) {
352 dev_printk(KERN_ERR, &conn->dev, "iscsi: could not register "
353 "connection's dev\n");
354 goto release_parent_ref;
355 }
356 transport_register_device(&conn->dev);
357 return conn;
358
359release_parent_ref:
360 put_device(&session->dev);
361free_conn:
362 kfree(conn);
363 return NULL;
364}
365
366EXPORT_SYMBOL_GPL(iscsi_create_conn);
367
368/**
369 * iscsi_destroy_conn - destroy iscsi class connection
370 * @session: iscsi cls session
371 *
372 * This can be called from a LLD or iscsi_transport.
373 **/
374int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
375{
376 transport_unregister_device(&conn->dev);
377 device_unregister(&conn->dev);
378 return 0;
379}
380
381EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
382
383/*
384 * These functions are used only by software iscsi_transports
385 * which do not allocate and more their scsi_hosts since this
386 * is initiated from userspace.
387 */
388
389/*
390 * iSCSI Session's hostdata organization:
391 *
392 * *------------------* <== hostdata_session(host->hostdata)
393 * | ptr to class sess|
394 * |------------------| <== iscsi_hostdata(host->hostdata)
395 * | transport's data |
396 * *------------------*
397 */
398
399#define hostdata_privsize(_t) (sizeof(unsigned long) + _t->hostdata_size + \
400 _t->hostdata_size % sizeof(unsigned long))
401
402#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
403
404/**
405 * iscsi_transport_create_session - create iscsi cls session and host
406 * scsit: scsi transport template
407 * transport: iscsi transport template
408 *
409 * This can be used by software iscsi_transports that allocate
410 * a session per scsi host.
411 **/
412struct Scsi_Host *
413iscsi_transport_create_session(struct scsi_transport_template *scsit,
414 struct iscsi_transport *transport)
415{
416 struct iscsi_cls_session *session;
417 struct Scsi_Host *shost;
7b7232f3 418 unsigned long flags;
7b8631b5
MC
419
420 shost = scsi_host_alloc(transport->host_template,
421 hostdata_privsize(transport));
422 if (!shost) {
423 printk(KERN_ERR "iscsi: can not allocate SCSI host for "
424 "session\n");
425 return NULL;
426 }
427
428 shost->max_id = 1;
429 shost->max_channel = 0;
430 shost->max_lun = transport->max_lun;
431 shost->max_cmd_len = transport->max_cmd_len;
432 shost->transportt = scsit;
55e3299d 433 shost->transportt->create_work_queue = 1;
7b8631b5
MC
434
435 if (scsi_add_host(shost, NULL))
436 goto free_host;
437
438 session = iscsi_create_session(shost, transport);
439 if (!session)
440 goto remove_host;
0896b752 441
7b8631b5 442 *(unsigned long*)shost->hostdata = (unsigned long)session;
7b7232f3
MC
443 spin_lock_irqsave(&sesslock, flags);
444 list_add(&session->sess_list, &sesslist);
445 spin_unlock_irqrestore(&sesslock, flags);
7b8631b5
MC
446 return shost;
447
448remove_host:
449 scsi_remove_host(shost);
450free_host:
451 scsi_host_put(shost);
452 return NULL;
453}
0896b752 454
7b8631b5 455EXPORT_SYMBOL_GPL(iscsi_transport_create_session);
0896b752 456
7b8631b5
MC
457/**
458 * iscsi_transport_destroy_session - destroy session and scsi host
459 * shost: scsi host
460 *
461 * This can be used by software iscsi_transports that allocate
462 * a session per scsi host.
463 **/
464int iscsi_transport_destroy_session(struct Scsi_Host *shost)
465{
466 struct iscsi_cls_session *session;
7b7232f3 467 unsigned long flags;
0896b752 468
7b8631b5
MC
469 scsi_remove_host(shost);
470 session = hostdata_session(shost->hostdata);
7b7232f3
MC
471 spin_lock_irqsave(&sesslock, flags);
472 list_del(&session->sess_list);
473 spin_unlock_irqrestore(&sesslock, flags);
7b8631b5
MC
474 iscsi_destroy_session(session);
475 /* ref from host alloc */
476 scsi_host_put(shost);
477 return 0;
478}
479
480EXPORT_SYMBOL_GPL(iscsi_transport_destroy_session);
481
482/*
483 * iscsi interface functions
484 */
0896b752
AA
485static struct iscsi_internal *
486iscsi_if_transport_lookup(struct iscsi_transport *tt)
487{
488 struct iscsi_internal *priv;
489 unsigned long flags;
490
491 spin_lock_irqsave(&iscsi_transport_lock, flags);
492 list_for_each_entry(priv, &iscsi_transports, list) {
493 if (tt == priv->iscsi_transport) {
494 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
495 return priv;
496 }
497 }
498 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
499 return NULL;
500}
1da177e4 501
0896b752
AA
502static inline struct list_head *skb_to_lh(struct sk_buff *skb)
503{
504 return (struct list_head *)&skb->cb;
505}
1da177e4 506
0896b752 507static void*
28e5554d 508mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data)
0896b752
AA
509{
510 struct mempool_zone *zone = pool_data;
1da177e4 511
0896b752 512 return alloc_skb(zone->size, gfp_mask);
1da177e4
LT
513}
514
0896b752
AA
515static void
516mempool_zone_free_skb(void *element, void *pool_data)
517{
518 kfree_skb(element);
519}
1da177e4 520
0896b752
AA
521static void
522mempool_zone_complete(struct mempool_zone *zone)
523{
524 unsigned long flags;
525 struct list_head *lh, *n;
1da177e4 526
0896b752
AA
527 spin_lock_irqsave(&zone->freelock, flags);
528 list_for_each_safe(lh, n, &zone->freequeue) {
529 struct sk_buff *skb = (struct sk_buff *)((char *)lh -
530 offsetof(struct sk_buff, cb));
531 if (!skb_shared(skb)) {
532 list_del(skb_to_lh(skb));
533 mempool_free(skb, zone->pool);
534 atomic_dec(&zone->allocated);
535 }
536 }
537 spin_unlock_irqrestore(&zone->freelock, flags);
1da177e4
LT
538}
539
7b8631b5
MC
540static struct mempool_zone *
541mempool_zone_init(unsigned max, unsigned size, unsigned hiwat)
0896b752 542{
7b8631b5
MC
543 struct mempool_zone *zp;
544
545 zp = kzalloc(sizeof(*zp), GFP_KERNEL);
546 if (!zp)
547 return NULL;
548
142e301f
MC
549 zp->size = size;
550 zp->hiwat = hiwat;
551 INIT_LIST_HEAD(&zp->freequeue);
552 spin_lock_init(&zp->freelock);
553 atomic_set(&zp->allocated, 0);
554
0896b752
AA
555 zp->pool = mempool_create(max, mempool_zone_alloc_skb,
556 mempool_zone_free_skb, zp);
7b8631b5
MC
557 if (!zp->pool) {
558 kfree(zp);
559 return NULL;
560 }
1da177e4 561
7b8631b5 562 return zp;
0896b752
AA
563}
564
7b8631b5
MC
565static void mempool_zone_destroy(struct mempool_zone *zp)
566{
567 mempool_destroy(zp->pool);
568 kfree(zp);
569}
0896b752
AA
570
571static struct sk_buff*
572mempool_zone_get_skb(struct mempool_zone *zone)
1da177e4 573{
0896b752
AA
574 struct sk_buff *skb;
575
576 skb = mempool_alloc(zone->pool, GFP_ATOMIC);
577 if (skb)
578 atomic_inc(&zone->allocated);
579 return skb;
580}
1da177e4 581
0896b752
AA
582static int
583iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb)
584{
585 unsigned long flags;
586 int rc;
1da177e4 587
0896b752
AA
588 skb_get(skb);
589 rc = netlink_unicast(nls, skb, daemon_pid, MSG_DONTWAIT);
590 if (rc < 0) {
591 mempool_free(skb, zone->pool);
592 printk(KERN_ERR "iscsi: can not unicast skb (%d)\n", rc);
593 return rc;
594 }
595
596 spin_lock_irqsave(&zone->freelock, flags);
597 list_add(skb_to_lh(skb), &zone->freequeue);
598 spin_unlock_irqrestore(&zone->freelock, flags);
599
600 return 0;
1da177e4 601}
1da177e4 602
7b7232f3 603int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
0896b752 604 char *data, uint32_t data_size)
1da177e4 605{
0896b752
AA
606 struct nlmsghdr *nlh;
607 struct sk_buff *skb;
608 struct iscsi_uevent *ev;
0896b752
AA
609 char *pdu;
610 int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) +
611 data_size);
612
7b8631b5 613 mempool_zone_complete(conn->z_pdu);
0896b752 614
7b8631b5 615 skb = mempool_zone_get_skb(conn->z_pdu);
0896b752 616 if (!skb) {
7b7232f3 617 iscsi_conn_error(conn, ISCSI_ERR_CONN_FAILED);
7b8631b5
MC
618 dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver "
619 "control PDU: OOM\n");
0896b752
AA
620 return -ENOMEM;
621 }
1da177e4 622
0896b752
AA
623 nlh = __nlmsg_put(skb, daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
624 ev = NLMSG_DATA(nlh);
625 memset(ev, 0, sizeof(*ev));
626 ev->transport_handle = iscsi_handle(conn->transport);
627 ev->type = ISCSI_KEVENT_RECV_PDU;
7b8631b5 628 if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat)
0896b752 629 ev->iferror = -ENOMEM;
b5c7a12d
MC
630 ev->r.recv_req.cid = conn->cid;
631 ev->r.recv_req.sid = iscsi_conn_get_sid(conn);
0896b752
AA
632 pdu = (char*)ev + sizeof(*ev);
633 memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
634 memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
1da177e4 635
7b8631b5 636 return iscsi_unicast_skb(conn->z_pdu, skb);
1da177e4 637}
0896b752 638EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
1da177e4 639
7b7232f3 640void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error)
1da177e4 641{
0896b752
AA
642 struct nlmsghdr *nlh;
643 struct sk_buff *skb;
644 struct iscsi_uevent *ev;
0896b752
AA
645 int len = NLMSG_SPACE(sizeof(*ev));
646
7b8631b5 647 mempool_zone_complete(conn->z_error);
0896b752 648
7b8631b5 649 skb = mempool_zone_get_skb(conn->z_error);
0896b752 650 if (!skb) {
7b8631b5
MC
651 dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored "
652 "conn error (%d)\n", error);
0896b752
AA
653 return;
654 }
655
656 nlh = __nlmsg_put(skb, daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
657 ev = NLMSG_DATA(nlh);
658 ev->transport_handle = iscsi_handle(conn->transport);
659 ev->type = ISCSI_KEVENT_CONN_ERROR;
7b8631b5 660 if (atomic_read(&conn->z_error->allocated) >= conn->z_error->hiwat)
0896b752
AA
661 ev->iferror = -ENOMEM;
662 ev->r.connerror.error = error;
b5c7a12d
MC
663 ev->r.connerror.cid = conn->cid;
664 ev->r.connerror.sid = iscsi_conn_get_sid(conn);
1da177e4 665
7b8631b5 666 iscsi_unicast_skb(conn->z_error, skb);
1da177e4 667
7b8631b5
MC
668 dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n",
669 error);
0896b752
AA
670}
671EXPORT_SYMBOL_GPL(iscsi_conn_error);
672
673static int
674iscsi_if_send_reply(int pid, int seq, int type, int done, int multi,
675 void *payload, int size)
676{
677 struct sk_buff *skb;
678 struct nlmsghdr *nlh;
679 int len = NLMSG_SPACE(size);
680 int flags = multi ? NLM_F_MULTI : 0;
681 int t = done ? NLMSG_DONE : type;
682
7b8631b5 683 mempool_zone_complete(z_reply);
0896b752 684
7b8631b5 685 skb = mempool_zone_get_skb(z_reply);
0896b752
AA
686 /*
687 * FIXME:
688 * user is supposed to react on iferror == -ENOMEM;
689 * see iscsi_if_rx().
690 */
691 BUG_ON(!skb);
692
693 nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0);
694 nlh->nlmsg_flags = flags;
695 memcpy(NLMSG_DATA(nlh), payload, size);
7b8631b5 696 return iscsi_unicast_skb(z_reply, skb);
1da177e4 697}
1da177e4 698
7b8631b5 699static int
5b940adf 700iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
7b8631b5
MC
701{
702 struct iscsi_uevent *ev = NLMSG_DATA(nlh);
703 struct iscsi_stats *stats;
704 struct sk_buff *skbstat;
705 struct iscsi_cls_conn *conn;
706 struct nlmsghdr *nlhstat;
707 struct iscsi_uevent *evstat;
708 int len = NLMSG_SPACE(sizeof(*ev) +
709 sizeof(struct iscsi_stats) +
710 sizeof(struct iscsi_stats_custom) *
711 ISCSI_STATS_CUSTOM_MAX);
712 int err = 0;
0896b752 713
b5c7a12d 714 conn = iscsi_conn_lookup(ev->u.get_stats.sid, ev->u.get_stats.cid);
7b8631b5
MC
715 if (!conn)
716 return -EEXIST;
0896b752 717
7b8631b5
MC
718 do {
719 int actual_size;
0896b752 720
7b8631b5 721 mempool_zone_complete(conn->z_pdu);
0896b752 722
7b8631b5
MC
723 skbstat = mempool_zone_get_skb(conn->z_pdu);
724 if (!skbstat) {
725 dev_printk(KERN_ERR, &conn->dev, "iscsi: can not "
726 "deliver stats: OOM\n");
727 return -ENOMEM;
728 }
729
730 nlhstat = __nlmsg_put(skbstat, daemon_pid, 0, 0,
731 (len - sizeof(*nlhstat)), 0);
732 evstat = NLMSG_DATA(nlhstat);
733 memset(evstat, 0, sizeof(*evstat));
734 evstat->transport_handle = iscsi_handle(conn->transport);
735 evstat->type = nlh->nlmsg_type;
736 if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat)
737 evstat->iferror = -ENOMEM;
b5c7a12d
MC
738 evstat->u.get_stats.cid =
739 ev->u.get_stats.cid;
740 evstat->u.get_stats.sid =
741 ev->u.get_stats.sid;
7b8631b5
MC
742 stats = (struct iscsi_stats *)
743 ((char*)evstat + sizeof(*evstat));
744 memset(stats, 0, sizeof(*stats));
745
7b7232f3 746 transport->get_stats(conn, stats);
7b8631b5
MC
747 actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) +
748 sizeof(struct iscsi_stats) +
749 sizeof(struct iscsi_stats_custom) *
750 stats->custom_length);
751 actual_size -= sizeof(*nlhstat);
752 actual_size = NLMSG_LENGTH(actual_size);
5b940adf 753 skb_trim(skbstat, NLMSG_ALIGN(actual_size));
7b8631b5
MC
754 nlhstat->nlmsg_len = actual_size;
755
756 err = iscsi_unicast_skb(conn->z_pdu, skbstat);
757 } while (err < 0 && err != -ECONNREFUSED);
758
759 return err;
0896b752
AA
760}
761
762static int
763iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
764{
765 struct iscsi_transport *transport = priv->iscsi_transport;
7b7232f3 766 struct iscsi_cls_session *session;
b5c7a12d 767 uint32_t hostno;
0896b752 768
7b7232f3
MC
769 session = transport->create_session(&priv->t,
770 ev->u.c_session.initial_cmdsn,
b5c7a12d 771 &hostno);
7b7232f3 772 if (!session)
7b8631b5 773 return -ENOMEM;
0896b752 774
b5c7a12d
MC
775 ev->r.c_session_ret.host_no = hostno;
776 ev->r.c_session_ret.sid = session->sid;
0896b752 777 return 0;
0896b752
AA
778}
779
780static int
7b7232f3 781iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
0896b752 782{
7b8631b5 783 struct iscsi_cls_conn *conn;
7b7232f3 784 struct iscsi_cls_session *session;
0896b752 785 unsigned long flags;
7b8631b5 786
b5c7a12d
MC
787 session = iscsi_session_lookup(ev->u.c_conn.sid);
788 if (!session) {
789 printk(KERN_ERR "iscsi: invalid session %d\n",
790 ev->u.c_conn.sid);
7b8631b5 791 return -EINVAL;
b5c7a12d 792 }
0896b752 793
7b7232f3 794 conn = transport->create_conn(session, ev->u.c_conn.cid);
b5c7a12d
MC
795 if (!conn) {
796 printk(KERN_ERR "iscsi: couldn't create a new "
797 "connection for session %d\n",
798 session->sid);
7b7232f3 799 return -ENOMEM;
b5c7a12d 800 }
0896b752 801
7b8631b5 802 conn->z_pdu = mempool_zone_init(Z_MAX_PDU,
0896b752
AA
803 NLMSG_SPACE(sizeof(struct iscsi_uevent) +
804 sizeof(struct iscsi_hdr) +
805 DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH),
806 Z_HIWAT_PDU);
7b8631b5
MC
807 if (!conn->z_pdu) {
808 dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
809 "pdu zone for new conn\n");
810 goto destroy_conn;
0896b752 811 }
7b8631b5
MC
812
813 conn->z_error = mempool_zone_init(Z_MAX_ERROR,
0896b752
AA
814 NLMSG_SPACE(sizeof(struct iscsi_uevent)),
815 Z_HIWAT_ERROR);
7b8631b5
MC
816 if (!conn->z_error) {
817 dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
818 "error zone for new conn\n");
819 goto free_pdu_pool;
0896b752
AA
820 }
821
b5c7a12d
MC
822 ev->r.c_conn_ret.sid = session->sid;
823 ev->r.c_conn_ret.cid = conn->cid;
0896b752
AA
824
825 spin_lock_irqsave(&connlock, flags);
826 list_add(&conn->conn_list, &connlist);
0896b752
AA
827 conn->active = 1;
828 spin_unlock_irqrestore(&connlock, flags);
829
0896b752
AA
830 return 0;
831
7b8631b5
MC
832free_pdu_pool:
833 mempool_zone_destroy(conn->z_pdu);
834destroy_conn:
835 if (transport->destroy_conn)
836 transport->destroy_conn(conn->dd_data);
7b8631b5 837 return -ENOMEM;
1da177e4
LT
838}
839
0896b752
AA
840static int
841iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
842{
843 unsigned long flags;
7b8631b5
MC
844 struct iscsi_cls_conn *conn;
845 struct mempool_zone *z_error, *z_pdu;
0896b752 846
b5c7a12d 847 conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
0896b752 848 if (!conn)
7b8631b5 849 return -EINVAL;
0896b752
AA
850 spin_lock_irqsave(&connlock, flags);
851 conn->active = 0;
852 list_del(&conn->conn_list);
853 spin_unlock_irqrestore(&connlock, flags);
854
7b8631b5
MC
855 z_pdu = conn->z_pdu;
856 z_error = conn->z_error;
0896b752 857
7b8631b5
MC
858 if (transport->destroy_conn)
859 transport->destroy_conn(conn);
0896b752 860
7b8631b5
MC
861 mempool_zone_destroy(z_pdu);
862 mempool_zone_destroy(z_error);
0896b752 863
7b8631b5 864 return 0;
0896b752
AA
865}
866
fd7255f5
MC
867static void
868iscsi_copy_param(struct iscsi_uevent *ev, uint32_t *value, char *data)
869{
870 if (ev->u.set_param.len != sizeof(uint32_t))
871 BUG();
872 memcpy(value, data, min_t(uint32_t, sizeof(uint32_t),
873 ev->u.set_param.len));
874}
875
876static int
877iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
878{
879 char *data = (char*)ev + sizeof(*ev);
880 struct iscsi_cls_conn *conn;
881 struct iscsi_cls_session *session;
882 int err = 0;
883 uint32_t value = 0;
884
885 session = iscsi_session_lookup(ev->u.set_param.sid);
886 conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid);
887 if (!conn || !session)
888 return -EINVAL;
889
890 switch (ev->u.set_param.param) {
891 case ISCSI_PARAM_TARGET_NAME:
892 /* this should not change between logins */
893 if (session->targetname)
894 return 0;
895
896 session->targetname = kstrdup(data, GFP_KERNEL);
897 if (!session->targetname)
898 return -ENOMEM;
899 break;
900 case ISCSI_PARAM_TPGT:
901 iscsi_copy_param(ev, &value, data);
902 session->tpgt = value;
903 break;
904 case ISCSI_PARAM_PERSISTENT_PORT:
905 iscsi_copy_param(ev, &value, data);
906 conn->persistent_port = value;
907 break;
908 case ISCSI_PARAM_PERSISTENT_ADDRESS:
909 /*
910 * this is the address returned in discovery so it should
911 * not change between logins.
912 */
913 if (conn->persistent_address)
914 return 0;
915
916 conn->persistent_address = kstrdup(data, GFP_KERNEL);
917 if (!conn->persistent_address)
918 return -ENOMEM;
919 break;
920 default:
921 iscsi_copy_param(ev, &value, data);
922 err = transport->set_param(conn, ev->u.set_param.param, value);
923 }
924
925 return err;
926}
927
0896b752
AA
928static int
929iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
930{
931 int err = 0;
932 struct iscsi_uevent *ev = NLMSG_DATA(nlh);
933 struct iscsi_transport *transport = NULL;
934 struct iscsi_internal *priv;
7b7232f3
MC
935 struct iscsi_cls_session *session;
936 struct iscsi_cls_conn *conn;
0896b752 937
0896b752
AA
938 priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
939 if (!priv)
940 return -EINVAL;
941 transport = priv->iscsi_transport;
942
7b7232f3
MC
943 if (!try_module_get(transport->owner))
944 return -EINVAL;
945
0896b752
AA
946 switch (nlh->nlmsg_type) {
947 case ISCSI_UEVENT_CREATE_SESSION:
948 err = iscsi_if_create_session(priv, ev);
949 break;
950 case ISCSI_UEVENT_DESTROY_SESSION:
b5c7a12d 951 session = iscsi_session_lookup(ev->u.d_session.sid);
7b7232f3
MC
952 if (session)
953 transport->destroy_session(session);
954 else
955 err = -EINVAL;
0896b752
AA
956 break;
957 case ISCSI_UEVENT_CREATE_CONN:
958 err = iscsi_if_create_conn(transport, ev);
959 break;
960 case ISCSI_UEVENT_DESTROY_CONN:
961 err = iscsi_if_destroy_conn(transport, ev);
962 break;
963 case ISCSI_UEVENT_BIND_CONN:
b5c7a12d
MC
964 session = iscsi_session_lookup(ev->u.b_conn.sid);
965 conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid);
7b7232f3
MC
966
967 if (session && conn)
968 ev->r.retcode = transport->bind_conn(session, conn,
969 ev->u.b_conn.transport_fd,
970 ev->u.b_conn.is_leading);
971 else
972 err = -EINVAL;
0896b752
AA
973 break;
974 case ISCSI_UEVENT_SET_PARAM:
fd7255f5 975 err = iscsi_set_param(transport, ev);
0896b752
AA
976 break;
977 case ISCSI_UEVENT_START_CONN:
b5c7a12d 978 conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid);
7b7232f3
MC
979 if (conn)
980 ev->r.retcode = transport->start_conn(conn);
981 else
982 err = -EINVAL;
983
0896b752
AA
984 break;
985 case ISCSI_UEVENT_STOP_CONN:
b5c7a12d 986 conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid);
7b7232f3
MC
987 if (conn)
988 transport->stop_conn(conn, ev->u.stop_conn.flag);
989 else
990 err = -EINVAL;
0896b752
AA
991 break;
992 case ISCSI_UEVENT_SEND_PDU:
b5c7a12d 993 conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid);
7b7232f3
MC
994 if (conn)
995 ev->r.retcode = transport->send_pdu(conn,
996 (struct iscsi_hdr*)((char*)ev + sizeof(*ev)),
997 (char*)ev + sizeof(*ev) + ev->u.send_pdu.hdr_size,
998 ev->u.send_pdu.data_size);
999 else
1000 err = -EINVAL;
0896b752
AA
1001 break;
1002 case ISCSI_UEVENT_GET_STATS:
5b940adf 1003 err = iscsi_if_get_stats(transport, nlh);
0896b752
AA
1004 break;
1005 default:
1006 err = -EINVAL;
1007 break;
1008 }
1009
7b7232f3 1010 module_put(transport->owner);
0896b752
AA
1011 return err;
1012}
1013
b5c7a12d
MC
1014/*
1015 * Get message from skb (based on rtnetlink_rcv_skb). Each message is
1016 * processed by iscsi_if_recv_msg. Malformed skbs with wrong lengths or
1017 * invalid creds are discarded silently.
1018 */
0896b752
AA
1019static void
1020iscsi_if_rx(struct sock *sk, int len)
1021{
1022 struct sk_buff *skb;
1da177e4 1023
0b950672 1024 mutex_lock(&rx_queue_mutex);
0896b752 1025 while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
ee7f8e40
MC
1026 if (NETLINK_CREDS(skb)->uid) {
1027 skb_pull(skb, skb->len);
1028 goto free_skb;
1029 }
1030 daemon_pid = NETLINK_CREDS(skb)->pid;
1031
0896b752
AA
1032 while (skb->len >= NLMSG_SPACE(0)) {
1033 int err;
1034 uint32_t rlen;
1035 struct nlmsghdr *nlh;
1036 struct iscsi_uevent *ev;
1037
1038 nlh = (struct nlmsghdr *)skb->data;
1039 if (nlh->nlmsg_len < sizeof(*nlh) ||
1040 skb->len < nlh->nlmsg_len) {
1041 break;
1042 }
ee7f8e40 1043
0896b752
AA
1044 ev = NLMSG_DATA(nlh);
1045 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
1046 if (rlen > skb->len)
1047 rlen = skb->len;
ee7f8e40 1048
0896b752
AA
1049 err = iscsi_if_recv_msg(skb, nlh);
1050 if (err) {
1051 ev->type = ISCSI_KEVENT_IF_ERROR;
1052 ev->iferror = err;
1053 }
1054 do {
1055 /*
1056 * special case for GET_STATS:
1057 * on success - sending reply and stats from
1058 * inside of if_recv_msg(),
1059 * on error - fall through.
1060 */
1061 if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
1062 break;
1063 err = iscsi_if_send_reply(
1064 NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
1065 nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
7b8631b5
MC
1066 if (atomic_read(&z_reply->allocated) >=
1067 z_reply->hiwat)
0896b752
AA
1068 ev->iferror = -ENOMEM;
1069 } while (err < 0 && err != -ECONNREFUSED);
1070 skb_pull(skb, rlen);
1071 }
ee7f8e40 1072free_skb:
0896b752
AA
1073 kfree_skb(skb);
1074 }
0b950672 1075 mutex_unlock(&rx_queue_mutex);
0896b752 1076}
1da177e4 1077
7b8631b5
MC
1078#define iscsi_cdev_to_conn(_cdev) \
1079 iscsi_dev_to_conn(_cdev->dev)
1080
fd7255f5
MC
1081#define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \
1082struct class_device_attribute class_device_attr_##_prefix##_##_name = \
1083 __ATTR(_name,_mode,_show,_store)
1084
1da177e4 1085/*
0896b752 1086 * iSCSI connection attrs
1da177e4 1087 */
0896b752
AA
1088#define iscsi_conn_int_attr_show(param, format) \
1089static ssize_t \
1090show_conn_int_param_##param(struct class_device *cdev, char *buf) \
1091{ \
1092 uint32_t value = 0; \
7b8631b5
MC
1093 struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
1094 struct iscsi_transport *t = conn->transport; \
0896b752 1095 \
7b7232f3 1096 t->get_conn_param(conn, param, &value); \
0896b752
AA
1097 return snprintf(buf, 20, format"\n", value); \
1098}
1099
1100#define iscsi_conn_int_attr(field, param, format) \
1101 iscsi_conn_int_attr_show(param, format) \
fd7255f5
MC
1102static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_int_param_##param, \
1103 NULL);
0896b752
AA
1104
1105iscsi_conn_int_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH, "%u");
1106iscsi_conn_int_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH, "%u");
1107iscsi_conn_int_attr(header_digest, ISCSI_PARAM_HDRDGST_EN, "%d");
1108iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d");
1109iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d");
1110iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d");
fd7255f5
MC
1111iscsi_conn_int_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT, "%d");
1112iscsi_conn_int_attr(port, ISCSI_PARAM_CONN_PORT, "%d");
1113
1114#define iscsi_conn_str_attr_show(param) \
1115static ssize_t \
1116show_conn_str_param_##param(struct class_device *cdev, char *buf) \
1117{ \
1118 struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
1119 struct iscsi_transport *t = conn->transport; \
1120 return t->get_conn_str_param(conn, param, buf); \
1121}
1122
1123#define iscsi_conn_str_attr(field, param) \
1124 iscsi_conn_str_attr_show(param) \
1125static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_str_param_##param, \
1126 NULL);
1127
1128iscsi_conn_str_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
1129iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS);
1da177e4 1130
7b8631b5
MC
1131#define iscsi_cdev_to_session(_cdev) \
1132 iscsi_dev_to_session(_cdev->dev)
1133
1da177e4 1134/*
0896b752 1135 * iSCSI session attrs
1da177e4 1136 */
0896b752 1137#define iscsi_session_int_attr_show(param, format) \
1da177e4 1138static ssize_t \
0896b752 1139show_session_int_param_##param(struct class_device *cdev, char *buf) \
1da177e4 1140{ \
0896b752 1141 uint32_t value = 0; \
7b8631b5 1142 struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
7b8631b5 1143 struct iscsi_transport *t = session->transport; \
1da177e4 1144 \
7b7232f3 1145 t->get_session_param(session, param, &value); \
0896b752 1146 return snprintf(buf, 20, format"\n", value); \
1da177e4
LT
1147}
1148
0896b752
AA
1149#define iscsi_session_int_attr(field, param, format) \
1150 iscsi_session_int_attr_show(param, format) \
fd7255f5
MC
1151static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_int_param_##param, \
1152 NULL);
1da177e4 1153
0896b752
AA
1154iscsi_session_int_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, "%d");
1155iscsi_session_int_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, "%hu");
1156iscsi_session_int_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, "%d");
1157iscsi_session_int_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, "%u");
1158iscsi_session_int_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, "%u");
1159iscsi_session_int_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, "%d");
1160iscsi_session_int_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, "%d");
1161iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d");
fd7255f5 1162iscsi_session_int_attr(tpgt, ISCSI_PARAM_TPGT, "%d");
1da177e4 1163
fd7255f5
MC
1164#define iscsi_session_str_attr_show(param) \
1165static ssize_t \
1166show_session_str_param_##param(struct class_device *cdev, char *buf) \
1167{ \
1168 struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
1169 struct iscsi_transport *t = session->transport; \
1170 return t->get_session_str_param(session, param, buf); \
1171}
1172
1173#define iscsi_session_str_attr(field, param) \
1174 iscsi_session_str_attr_show(param) \
1175static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_str_param_##param, \
1176 NULL);
1177
1178iscsi_session_str_attr(targetname, ISCSI_PARAM_TARGET_NAME);
1da177e4 1179
fd7255f5
MC
1180/*
1181 * Private session and conn attrs. userspace uses several iscsi values
1182 * to identify each session between reboots. Some of these values may not
1183 * be present in the iscsi_transport/LLD driver becuase userspace handles
1184 * login (and failback for login redirect) so for these type of drivers
1185 * the class manages the attrs and values for the iscsi_transport/LLD
1186 */
1187#define iscsi_priv_session_attr_show(field, format) \
1188static ssize_t \
1189show_priv_session_##field(struct class_device *cdev, char *buf) \
1190{ \
1191 struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
1192 return sprintf(buf, format"\n", session->field); \
1193}
1194
1195#define iscsi_priv_session_attr(field, format) \
1196 iscsi_priv_session_attr_show(field, format) \
1197static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \
1198 NULL)
1199iscsi_priv_session_attr(targetname, "%s");
1200iscsi_priv_session_attr(tpgt, "%d");
1201
1202#define iscsi_priv_conn_attr_show(field, format) \
1203static ssize_t \
1204show_priv_conn_##field(struct class_device *cdev, char *buf) \
1205{ \
1206 struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
1207 return sprintf(buf, format"\n", conn->field); \
1208}
1209
1210#define iscsi_priv_conn_attr(field, format) \
1211 iscsi_priv_conn_attr_show(field, format) \
1212static ISCSI_CLASS_ATTR(priv_conn, field, S_IRUGO, show_priv_conn_##field, \
1213 NULL)
1214iscsi_priv_conn_attr(persistent_address, "%s");
1215iscsi_priv_conn_attr(persistent_port, "%d");
1216
1217#define SETUP_PRIV_SESSION_RD_ATTR(field) \
1218do { \
1219 priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
1220 count++; \
1221} while (0)
1222
1223#define SETUP_SESSION_RD_ATTR(field, param_flag) \
1224do { \
1225 if (tt->param_mask & param_flag) { \
1226 priv->session_attrs[count] = &class_device_attr_sess_##field; \
1da177e4 1227 count++; \
fd7255f5
MC
1228 } \
1229} while (0)
1230
1231#define SETUP_PRIV_CONN_RD_ATTR(field) \
1232do { \
1233 priv->conn_attrs[count] = &class_device_attr_priv_conn_##field; \
1234 count++; \
1235} while (0)
1236
1237#define SETUP_CONN_RD_ATTR(field, param_flag) \
1238do { \
1239 if (tt->param_mask & param_flag) { \
1240 priv->conn_attrs[count] = &class_device_attr_conn_##field; \
1241 count++; \
1242 } \
1243} while (0)
1da177e4 1244
0896b752
AA
1245static int iscsi_session_match(struct attribute_container *cont,
1246 struct device *dev)
1da177e4 1247{
7b8631b5 1248 struct iscsi_cls_session *session;
1da177e4 1249 struct Scsi_Host *shost;
0896b752
AA
1250 struct iscsi_internal *priv;
1251
1252 if (!iscsi_is_session_dev(dev))
1253 return 0;
1da177e4 1254
7b8631b5
MC
1255 session = iscsi_dev_to_session(dev);
1256 shost = iscsi_session_to_shost(session);
0896b752 1257 if (!shost->transportt)
1da177e4
LT
1258 return 0;
1259
0896b752
AA
1260 priv = to_iscsi_internal(shost->transportt);
1261 if (priv->session_cont.ac.class != &iscsi_session_class.class)
1da177e4
LT
1262 return 0;
1263
0896b752 1264 return &priv->session_cont.ac == cont;
1da177e4
LT
1265}
1266
0896b752
AA
1267static int iscsi_conn_match(struct attribute_container *cont,
1268 struct device *dev)
1269{
7b8631b5
MC
1270 struct iscsi_cls_session *session;
1271 struct iscsi_cls_conn *conn;
1da177e4 1272 struct Scsi_Host *shost;
0896b752 1273 struct iscsi_internal *priv;
1da177e4 1274
0896b752 1275 if (!iscsi_is_conn_dev(dev))
1da177e4
LT
1276 return 0;
1277
7b8631b5
MC
1278 conn = iscsi_dev_to_conn(dev);
1279 session = iscsi_dev_to_session(conn->dev.parent);
1280 shost = iscsi_session_to_shost(session);
1281
0896b752 1282 if (!shost->transportt)
1da177e4
LT
1283 return 0;
1284
0896b752
AA
1285 priv = to_iscsi_internal(shost->transportt);
1286 if (priv->conn_cont.ac.class != &iscsi_connection_class.class)
1287 return 0;
1da177e4 1288
0896b752
AA
1289 return &priv->conn_cont.ac == cont;
1290}
1291
7b8631b5
MC
1292struct scsi_transport_template *
1293iscsi_register_transport(struct iscsi_transport *tt)
0896b752
AA
1294{
1295 struct iscsi_internal *priv;
1296 unsigned long flags;
1297 int count = 0, err;
1298
1299 BUG_ON(!tt);
1300
1301 priv = iscsi_if_transport_lookup(tt);
1302 if (priv)
7b8631b5 1303 return NULL;
0896b752 1304
24669f75 1305 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0896b752 1306 if (!priv)
7b8631b5 1307 return NULL;
0896b752 1308 INIT_LIST_HEAD(&priv->list);
0896b752
AA
1309 priv->iscsi_transport = tt;
1310
1311 priv->cdev.class = &iscsi_transport_class;
1312 snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
1313 err = class_device_register(&priv->cdev);
1314 if (err)
1315 goto free_priv;
1316
1317 err = sysfs_create_group(&priv->cdev.kobj, &iscsi_transport_group);
1318 if (err)
1319 goto unregister_cdev;
1320
0896b752
AA
1321 /* connection parameters */
1322 priv->conn_cont.ac.attrs = &priv->conn_attrs[0];
1323 priv->conn_cont.ac.class = &iscsi_connection_class.class;
1324 priv->conn_cont.ac.match = iscsi_conn_match;
1325 transport_container_register(&priv->conn_cont);
1da177e4 1326
fd7255f5
MC
1327 SETUP_CONN_RD_ATTR(max_recv_dlength, ISCSI_MAX_RECV_DLENGTH);
1328 SETUP_CONN_RD_ATTR(max_xmit_dlength, ISCSI_MAX_XMIT_DLENGTH);
1329 SETUP_CONN_RD_ATTR(header_digest, ISCSI_HDRDGST_EN);
1330 SETUP_CONN_RD_ATTR(data_digest, ISCSI_DATADGST_EN);
1331 SETUP_CONN_RD_ATTR(ifmarker, ISCSI_IFMARKER_EN);
1332 SETUP_CONN_RD_ATTR(ofmarker, ISCSI_OFMARKER_EN);
1333 SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS);
1334 SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT);
1335
1336 if (tt->param_mask & ISCSI_PERSISTENT_ADDRESS)
1337 SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
1338 else
1339 SETUP_PRIV_CONN_RD_ATTR(persistent_address);
1340
1341 if (tt->param_mask & ISCSI_PERSISTENT_PORT)
1342 SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
1343 else
1344 SETUP_PRIV_CONN_RD_ATTR(persistent_port);
0896b752
AA
1345
1346 BUG_ON(count > ISCSI_CONN_ATTRS);
1347 priv->conn_attrs[count] = NULL;
1da177e4 1348 count = 0;
1da177e4 1349
0896b752
AA
1350 /* session parameters */
1351 priv->session_cont.ac.attrs = &priv->session_attrs[0];
1352 priv->session_cont.ac.class = &iscsi_session_class.class;
1353 priv->session_cont.ac.match = iscsi_session_match;
1354 transport_container_register(&priv->session_cont);
1355
fd7255f5
MC
1356 SETUP_SESSION_RD_ATTR(initial_r2t, ISCSI_INITIAL_R2T_EN);
1357 SETUP_SESSION_RD_ATTR(max_outstanding_r2t, ISCSI_MAX_R2T);
1358 SETUP_SESSION_RD_ATTR(immediate_data, ISCSI_IMM_DATA_EN);
1359 SETUP_SESSION_RD_ATTR(first_burst_len, ISCSI_FIRST_BURST);
1360 SETUP_SESSION_RD_ATTR(max_burst_len, ISCSI_MAX_BURST);
1361 SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN);
1362 SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN);
1363 SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL);
1364
1365 if (tt->param_mask & ISCSI_TARGET_NAME)
1366 SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
1367 else
1368 SETUP_PRIV_SESSION_RD_ATTR(targetname);
1369
1370 if (tt->param_mask & ISCSI_TPGT)
1371 SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT);
1372 else
1373 SETUP_PRIV_SESSION_RD_ATTR(tpgt);
0896b752
AA
1374
1375 BUG_ON(count > ISCSI_SESSION_ATTRS);
1376 priv->session_attrs[count] = NULL;
1377
1378 spin_lock_irqsave(&iscsi_transport_lock, flags);
1379 list_add(&priv->list, &iscsi_transports);
1380 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
1381
1382 printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
7b8631b5 1383 return &priv->t;
1da177e4 1384
0896b752
AA
1385unregister_cdev:
1386 class_device_unregister(&priv->cdev);
1387free_priv:
1388 kfree(priv);
7b8631b5 1389 return NULL;
1da177e4 1390}
0896b752
AA
1391EXPORT_SYMBOL_GPL(iscsi_register_transport);
1392
1393int iscsi_unregister_transport(struct iscsi_transport *tt)
1394{
1395 struct iscsi_internal *priv;
1396 unsigned long flags;
1397
1398 BUG_ON(!tt);
1399
0b950672 1400 mutex_lock(&rx_queue_mutex);
0896b752
AA
1401
1402 priv = iscsi_if_transport_lookup(tt);
1403 BUG_ON (!priv);
1404
0896b752
AA
1405 spin_lock_irqsave(&iscsi_transport_lock, flags);
1406 list_del(&priv->list);
1407 spin_unlock_irqrestore(&iscsi_transport_lock, flags);
1408
1409 transport_container_unregister(&priv->conn_cont);
1410 transport_container_unregister(&priv->session_cont);
1411
1412 sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
1413 class_device_unregister(&priv->cdev);
0b950672 1414 mutex_unlock(&rx_queue_mutex);
1da177e4 1415
0896b752
AA
1416 return 0;
1417}
1418EXPORT_SYMBOL_GPL(iscsi_unregister_transport);
1da177e4 1419
0896b752
AA
1420static int
1421iscsi_rcv_nl_event(struct notifier_block *this, unsigned long event, void *ptr)
1da177e4 1422{
0896b752
AA
1423 struct netlink_notify *n = ptr;
1424
1425 if (event == NETLINK_URELEASE &&
1426 n->protocol == NETLINK_ISCSI && n->pid) {
7b8631b5 1427 struct iscsi_cls_conn *conn;
0896b752
AA
1428 unsigned long flags;
1429
7b8631b5 1430 mempool_zone_complete(z_reply);
0896b752
AA
1431 spin_lock_irqsave(&connlock, flags);
1432 list_for_each_entry(conn, &connlist, conn_list) {
7b8631b5
MC
1433 mempool_zone_complete(conn->z_error);
1434 mempool_zone_complete(conn->z_pdu);
0896b752
AA
1435 }
1436 spin_unlock_irqrestore(&connlock, flags);
1437 }
1da177e4 1438
0896b752 1439 return NOTIFY_DONE;
1da177e4
LT
1440}
1441
0896b752
AA
1442static struct notifier_block iscsi_nl_notifier = {
1443 .notifier_call = iscsi_rcv_nl_event,
1444};
1da177e4
LT
1445
1446static __init int iscsi_transport_init(void)
1447{
0896b752 1448 int err;
1da177e4 1449
0896b752 1450 err = class_register(&iscsi_transport_class);
1da177e4
LT
1451 if (err)
1452 return err;
0896b752
AA
1453
1454 err = transport_class_register(&iscsi_connection_class);
1455 if (err)
1456 goto unregister_transport_class;
1457
1458 err = transport_class_register(&iscsi_session_class);
1459 if (err)
1460 goto unregister_conn_class;
1461
1462 err = netlink_register_notifier(&iscsi_nl_notifier);
1463 if (err)
1464 goto unregister_session_class;
1465
2290d2b6 1466 nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx,
7b8631b5 1467 THIS_MODULE);
0896b752
AA
1468 if (!nls) {
1469 err = -ENOBUFS;
1470 goto unregister_notifier;
1471 }
1472
7b8631b5 1473 z_reply = mempool_zone_init(Z_MAX_REPLY,
0896b752 1474 NLMSG_SPACE(sizeof(struct iscsi_uevent)), Z_HIWAT_REPLY);
7b8631b5 1475 if (z_reply)
0896b752
AA
1476 return 0;
1477
1478 sock_release(nls->sk_socket);
1479unregister_notifier:
1480 netlink_unregister_notifier(&iscsi_nl_notifier);
1481unregister_session_class:
1482 transport_class_unregister(&iscsi_session_class);
1483unregister_conn_class:
1484 transport_class_unregister(&iscsi_connection_class);
1485unregister_transport_class:
1486 class_unregister(&iscsi_transport_class);
1487 return err;
1da177e4
LT
1488}
1489
1490static void __exit iscsi_transport_exit(void)
1491{
7b8631b5 1492 mempool_zone_destroy(z_reply);
0896b752
AA
1493 sock_release(nls->sk_socket);
1494 netlink_unregister_notifier(&iscsi_nl_notifier);
1495 transport_class_unregister(&iscsi_connection_class);
1496 transport_class_unregister(&iscsi_session_class);
1497 class_unregister(&iscsi_transport_class);
1da177e4
LT
1498}
1499
1500module_init(iscsi_transport_init);
1501module_exit(iscsi_transport_exit);
1502
0896b752
AA
1503MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
1504 "Dmitry Yusupov <dmitry_yus@yahoo.com>, "
1505 "Alex Aizman <itn780@yahoo.com>");
1506MODULE_DESCRIPTION("iSCSI Transport Interface");
1da177e4 1507MODULE_LICENSE("GPL");
This page took 0.200113 seconds and 5 git commands to generate.