aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2006-06-28 13:00:32 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-06-29 11:14:42 -0400
commit53cb8a1f45e06a2627a6d89b151cccb95fa45cbf (patch)
tree272c8bfb7a3e8a9a9af55e2e6b76e0ecd757410b
parent6a8a0d3621745279a131d95f0204dc9ddac60d55 (diff)
[SCSI] iscsi: add async notification of session events
This patch adds or modifies the transport class functions used to notify userspace of session state events. We modify the session addition up event and add a destruction event to notify userspace of session creation, relogin and destruction. And we modify the conn error event to be sent by broadcast since multiple listeners may want to listen for it. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c309
-rw-r--r--include/scsi/iscsi_if.h23
-rw-r--r--include/scsi/scsi_transport_iscsi.h3
3 files changed, 235 insertions, 100 deletions
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 7963c0538de5..7b9e8fa1a4e0 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -413,11 +413,59 @@ int iscsi_destroy_session(struct iscsi_cls_session *session)
413} 413}
414EXPORT_SYMBOL_GPL(iscsi_destroy_session); 414EXPORT_SYMBOL_GPL(iscsi_destroy_session);
415 415
416static void mempool_zone_destroy(struct mempool_zone *zp)
417{
418 mempool_destroy(zp->pool);
419 kfree(zp);
420}
421
422static void*
423mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data)
424{
425 struct mempool_zone *zone = pool_data;
426
427 return alloc_skb(zone->size, gfp_mask);
428}
429
430static void
431mempool_zone_free_skb(void *element, void *pool_data)
432{
433 kfree_skb(element);
434}
435
436static struct mempool_zone *
437mempool_zone_init(unsigned max, unsigned size, unsigned hiwat)
438{
439 struct mempool_zone *zp;
440
441 zp = kzalloc(sizeof(*zp), GFP_KERNEL);
442 if (!zp)
443 return NULL;
444
445 zp->size = size;
446 zp->hiwat = hiwat;
447 INIT_LIST_HEAD(&zp->freequeue);
448 spin_lock_init(&zp->freelock);
449 atomic_set(&zp->allocated, 0);
450
451 zp->pool = mempool_create(max, mempool_zone_alloc_skb,
452 mempool_zone_free_skb, zp);
453 if (!zp->pool) {
454 kfree(zp);
455 return NULL;
456 }
457
458 return zp;
459}
460
416static void iscsi_conn_release(struct device *dev) 461static void iscsi_conn_release(struct device *dev)
417{ 462{
418 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); 463 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
419 struct device *parent = conn->dev.parent; 464 struct device *parent = conn->dev.parent;
420 465
466 mempool_zone_destroy(conn->z_pdu);
467 mempool_zone_destroy(conn->z_error);
468
421 kfree(conn); 469 kfree(conn);
422 put_device(parent); 470 put_device(parent);
423} 471}
@@ -427,6 +475,31 @@ static int iscsi_is_conn_dev(const struct device *dev)
427 return dev->release == iscsi_conn_release; 475 return dev->release == iscsi_conn_release;
428} 476}
429 477
478static int iscsi_create_event_pools(struct iscsi_cls_conn *conn)
479{
480 conn->z_pdu = mempool_zone_init(Z_MAX_PDU,
481 NLMSG_SPACE(sizeof(struct iscsi_uevent) +
482 sizeof(struct iscsi_hdr) +
483 DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH),
484 Z_HIWAT_PDU);
485 if (!conn->z_pdu) {
486 dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
487 "pdu zone for new conn\n");
488 return -ENOMEM;
489 }
490
491 conn->z_error = mempool_zone_init(Z_MAX_ERROR,
492 NLMSG_SPACE(sizeof(struct iscsi_uevent)),
493 Z_HIWAT_ERROR);
494 if (!conn->z_error) {
495 dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
496 "error zone for new conn\n");
497 mempool_zone_destroy(conn->z_pdu);
498 return -ENOMEM;
499 }
500 return 0;
501}
502
430/** 503/**
431 * iscsi_create_conn - create iscsi class connection 504 * iscsi_create_conn - create iscsi class connection
432 * @session: iscsi cls session 505 * @session: iscsi cls session
@@ -459,9 +532,12 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
459 conn->transport = transport; 532 conn->transport = transport;
460 conn->cid = cid; 533 conn->cid = cid;
461 534
535 if (iscsi_create_event_pools(conn))
536 goto free_conn;
537
462 /* this is released in the dev's release function */ 538 /* this is released in the dev's release function */
463 if (!get_device(&session->dev)) 539 if (!get_device(&session->dev))
464 goto free_conn; 540 goto free_conn_pools;
465 541
466 snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u", 542 snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
467 session->sid, cid); 543 session->sid, cid);
@@ -478,6 +554,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
478 554
479release_parent_ref: 555release_parent_ref:
480 put_device(&session->dev); 556 put_device(&session->dev);
557free_conn_pools:
558
481free_conn: 559free_conn:
482 kfree(conn); 560 kfree(conn);
483 return NULL; 561 return NULL;
@@ -525,20 +603,6 @@ static inline struct list_head *skb_to_lh(struct sk_buff *skb)
525 return (struct list_head *)&skb->cb; 603 return (struct list_head *)&skb->cb;
526} 604}
527 605
528static void*
529mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data)
530{
531 struct mempool_zone *zone = pool_data;
532
533 return alloc_skb(zone->size, gfp_mask);
534}
535
536static void
537mempool_zone_free_skb(void *element, void *pool_data)
538{
539 kfree_skb(element);
540}
541
542static void 606static void
543mempool_zone_complete(struct mempool_zone *zone) 607mempool_zone_complete(struct mempool_zone *zone)
544{ 608{
@@ -558,37 +622,6 @@ mempool_zone_complete(struct mempool_zone *zone)
558 spin_unlock_irqrestore(&zone->freelock, flags); 622 spin_unlock_irqrestore(&zone->freelock, flags);
559} 623}
560 624
561static struct mempool_zone *
562mempool_zone_init(unsigned max, unsigned size, unsigned hiwat)
563{
564 struct mempool_zone *zp;
565
566 zp = kzalloc(sizeof(*zp), GFP_KERNEL);
567 if (!zp)
568 return NULL;
569
570 zp->size = size;
571 zp->hiwat = hiwat;
572 INIT_LIST_HEAD(&zp->freequeue);
573 spin_lock_init(&zp->freelock);
574 atomic_set(&zp->allocated, 0);
575
576 zp->pool = mempool_create(max, mempool_zone_alloc_skb,
577 mempool_zone_free_skb, zp);
578 if (!zp->pool) {
579 kfree(zp);
580 return NULL;
581 }
582
583 return zp;
584}
585
586static void mempool_zone_destroy(struct mempool_zone *zp)
587{
588 mempool_destroy(zp->pool);
589 kfree(zp);
590}
591
592static struct sk_buff* 625static struct sk_buff*
593mempool_zone_get_skb(struct mempool_zone *zone) 626mempool_zone_get_skb(struct mempool_zone *zone)
594{ 627{
@@ -601,6 +634,27 @@ mempool_zone_get_skb(struct mempool_zone *zone)
601} 634}
602 635
603static int 636static int
637iscsi_broadcast_skb(struct mempool_zone *zone, struct sk_buff *skb)
638{
639 unsigned long flags;
640 int rc;
641
642 skb_get(skb);
643 rc = netlink_broadcast(nls, skb, 0, 1, GFP_KERNEL);
644 if (rc < 0) {
645 mempool_free(skb, zone->pool);
646 printk(KERN_ERR "iscsi: can not broadcast skb (%d)\n", rc);
647 return rc;
648 }
649
650 spin_lock_irqsave(&zone->freelock, flags);
651 INIT_LIST_HEAD(skb_to_lh(skb));
652 list_add(skb_to_lh(skb), &zone->freequeue);
653 spin_unlock_irqrestore(&zone->freelock, flags);
654 return 0;
655}
656
657static int
604iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb, int pid) 658iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb, int pid)
605{ 659{
606 unsigned long flags; 660 unsigned long flags;
@@ -695,7 +749,7 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error)
695 ev->r.connerror.cid = conn->cid; 749 ev->r.connerror.cid = conn->cid;
696 ev->r.connerror.sid = iscsi_conn_get_sid(conn); 750 ev->r.connerror.sid = iscsi_conn_get_sid(conn);
697 751
698 iscsi_unicast_skb(conn->z_error, skb, priv->daemon_pid); 752 iscsi_broadcast_skb(conn->z_error, skb);
699 753
700 dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", 754 dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n",
701 error); 755 error);
@@ -796,6 +850,131 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
796 return err; 850 return err;
797} 851}
798 852
853/**
854 * iscsi_if_destroy_session_done - send session destr. completion event
855 * @conn: last connection for session
856 *
857 * This is called by HW iscsi LLDs to notify userpsace that its HW has
858 * removed a session.
859 **/
860int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn)
861{
862 struct iscsi_internal *priv;
863 struct iscsi_cls_session *session;
864 struct Scsi_Host *shost;
865 struct iscsi_uevent *ev;
866 struct sk_buff *skb;
867 struct nlmsghdr *nlh;
868 unsigned long flags;
869 int rc, len = NLMSG_SPACE(sizeof(*ev));
870
871 priv = iscsi_if_transport_lookup(conn->transport);
872 if (!priv)
873 return -EINVAL;
874
875 session = iscsi_dev_to_session(conn->dev.parent);
876 shost = iscsi_session_to_shost(session);
877
878 mempool_zone_complete(conn->z_pdu);
879
880 skb = mempool_zone_get_skb(conn->z_pdu);
881 if (!skb) {
882 dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
883 "session creation event\n");
884 return -ENOMEM;
885 }
886
887 nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
888 ev = NLMSG_DATA(nlh);
889 ev->transport_handle = iscsi_handle(conn->transport);
890 ev->type = ISCSI_KEVENT_DESTROY_SESSION;
891 ev->r.d_session.host_no = shost->host_no;
892 ev->r.d_session.sid = session->sid;
893
894 /*
895 * this will occur if the daemon is not up, so we just warn
896 * the user and when the daemon is restarted it will handle it
897 */
898 rc = iscsi_broadcast_skb(conn->z_pdu, skb);
899 if (rc < 0)
900 dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
901 "session destruction event. Check iscsi daemon\n");
902
903 spin_lock_irqsave(&sesslock, flags);
904 list_del(&session->sess_list);
905 spin_unlock_irqrestore(&sesslock, flags);
906
907 spin_lock_irqsave(&connlock, flags);
908 conn->active = 0;
909 list_del(&conn->conn_list);
910 spin_unlock_irqrestore(&connlock, flags);
911
912 return rc;
913}
914EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done);
915
916/**
917 * iscsi_if_create_session_done - send session creation completion event
918 * @conn: leading connection for session
919 *
920 * This is called by HW iscsi LLDs to notify userpsace that its HW has
921 * created a session or a existing session is back in the logged in state.
922 **/
923int iscsi_if_create_session_done(struct iscsi_cls_conn *conn)
924{
925 struct iscsi_internal *priv;
926 struct iscsi_cls_session *session;
927 struct Scsi_Host *shost;
928 struct iscsi_uevent *ev;
929 struct sk_buff *skb;
930 struct nlmsghdr *nlh;
931 unsigned long flags;
932 int rc, len = NLMSG_SPACE(sizeof(*ev));
933
934 priv = iscsi_if_transport_lookup(conn->transport);
935 if (!priv)
936 return -EINVAL;
937
938 session = iscsi_dev_to_session(conn->dev.parent);
939 shost = iscsi_session_to_shost(session);
940
941 mempool_zone_complete(conn->z_pdu);
942
943 skb = mempool_zone_get_skb(conn->z_pdu);
944 if (!skb) {
945 dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
946 "session creation event\n");
947 return -ENOMEM;
948 }
949
950 nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
951 ev = NLMSG_DATA(nlh);
952 ev->transport_handle = iscsi_handle(conn->transport);
953 ev->type = ISCSI_UEVENT_CREATE_SESSION;
954 ev->r.c_session_ret.host_no = shost->host_no;
955 ev->r.c_session_ret.sid = session->sid;
956
957 /*
958 * this will occur if the daemon is not up, so we just warn
959 * the user and when the daemon is restarted it will handle it
960 */
961 rc = iscsi_broadcast_skb(conn->z_pdu, skb);
962 if (rc < 0)
963 dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
964 "session creation event. Check iscsi daemon\n");
965
966 spin_lock_irqsave(&sesslock, flags);
967 list_add(&session->sess_list, &sesslist);
968 spin_unlock_irqrestore(&sesslock, flags);
969
970 spin_lock_irqsave(&connlock, flags);
971 list_add(&conn->conn_list, &connlist);
972 conn->active = 1;
973 spin_unlock_irqrestore(&connlock, flags);
974 return rc;
975}
976EXPORT_SYMBOL_GPL(iscsi_if_create_session_done);
977
799static int 978static int
800iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) 979iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
801{ 980{
@@ -841,26 +1020,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
841 return -ENOMEM; 1020 return -ENOMEM;
842 } 1021 }
843 1022
844 conn->z_pdu = mempool_zone_init(Z_MAX_PDU,
845 NLMSG_SPACE(sizeof(struct iscsi_uevent) +
846 sizeof(struct iscsi_hdr) +
847 DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH),
848 Z_HIWAT_PDU);
849 if (!conn->z_pdu) {
850 dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
851 "pdu zone for new conn\n");
852 goto destroy_conn;
853 }
854
855 conn->z_error = mempool_zone_init(Z_MAX_ERROR,
856 NLMSG_SPACE(sizeof(struct iscsi_uevent)),
857 Z_HIWAT_ERROR);
858 if (!conn->z_error) {
859 dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
860 "error zone for new conn\n");
861 goto free_pdu_pool;
862 }
863
864 ev->r.c_conn_ret.sid = session->sid; 1023 ev->r.c_conn_ret.sid = session->sid;
865 ev->r.c_conn_ret.cid = conn->cid; 1024 ev->r.c_conn_ret.cid = conn->cid;
866 1025
@@ -870,13 +1029,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
870 spin_unlock_irqrestore(&connlock, flags); 1029 spin_unlock_irqrestore(&connlock, flags);
871 1030
872 return 0; 1031 return 0;
873
874free_pdu_pool:
875 mempool_zone_destroy(conn->z_pdu);
876destroy_conn:
877 if (transport->destroy_conn)
878 transport->destroy_conn(conn->dd_data);
879 return -ENOMEM;
880} 1032}
881 1033
882static int 1034static int
@@ -884,7 +1036,6 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev
884{ 1036{
885 unsigned long flags; 1037 unsigned long flags;
886 struct iscsi_cls_conn *conn; 1038 struct iscsi_cls_conn *conn;
887 struct mempool_zone *z_error, *z_pdu;
888 1039
889 conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid); 1040 conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
890 if (!conn) 1041 if (!conn)
@@ -894,15 +1045,8 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev
894 list_del(&conn->conn_list); 1045 list_del(&conn->conn_list);
895 spin_unlock_irqrestore(&connlock, flags); 1046 spin_unlock_irqrestore(&connlock, flags);
896 1047
897 z_pdu = conn->z_pdu;
898 z_error = conn->z_error;
899
900 if (transport->destroy_conn) 1048 if (transport->destroy_conn)
901 transport->destroy_conn(conn); 1049 transport->destroy_conn(conn);
902
903 mempool_zone_destroy(z_pdu);
904 mempool_zone_destroy(z_error);
905
906 return 0; 1050 return 0;
907} 1051}
908 1052
@@ -1331,6 +1475,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
1331 if (!priv) 1475 if (!priv)
1332 return NULL; 1476 return NULL;
1333 INIT_LIST_HEAD(&priv->list); 1477 INIT_LIST_HEAD(&priv->list);
1478 priv->daemon_pid = -1;
1334 priv->iscsi_transport = tt; 1479 priv->iscsi_transport = tt;
1335 priv->t.user_scan = iscsi_user_scan; 1480 priv->t.user_scan = iscsi_user_scan;
1336 1481
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 8813f0f4c624..55ebf035e620 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -53,6 +53,7 @@ enum iscsi_uevent_e {
53 ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, 53 ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
54 ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2, 54 ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2,
55 ISCSI_KEVENT_IF_ERROR = KEVENT_BASE + 3, 55 ISCSI_KEVENT_IF_ERROR = KEVENT_BASE + 3,
56 ISCSI_KEVENT_DESTROY_SESSION = KEVENT_BASE + 4,
56}; 57};
57 58
58enum iscsi_tgt_dscvr { 59enum iscsi_tgt_dscvr {
@@ -157,27 +158,13 @@ struct iscsi_uevent {
157 uint32_t cid; 158 uint32_t cid;
158 uint32_t error; /* enum iscsi_err */ 159 uint32_t error; /* enum iscsi_err */
159 } connerror; 160 } connerror;
161 struct msg_session_destroyed {
162 uint32_t host_no;
163 uint32_t sid;
164 } d_session;
160 struct msg_transport_connect_ret { 165 struct msg_transport_connect_ret {
161 uint64_t handle; 166 uint64_t handle;
162 } ep_connect_ret; 167 } ep_connect_ret;
163 struct msg_tgt_dscvr_ret {
164 /*
165 * session/connection pair used to reference
166 * the connection to server
167 */
168 uint32_t sid;
169 uint32_t cid;
170 union {
171 struct isns {
172 /* port # for conn to iSNS server */
173 uint16_t isns_port;
174 /* listening port to receive SCNs */
175 uint16_t scn_port;
176 /* listening port to receive ESIs */
177 uint16_t esi_port;
178 } isns_attrib;
179 } u;
180 } tgt_dscvr_ret;
181 } r; 168 } r;
182} __attribute__ ((aligned (sizeof(uint64_t)))); 169} __attribute__ ((aligned (sizeof(uint64_t))));
183 170
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index f7b0db5f2f5b..5a3df1d7085f 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -214,6 +214,8 @@ extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost,
214 struct iscsi_transport *transport); 214 struct iscsi_transport *transport);
215extern int iscsi_add_session(struct iscsi_cls_session *session, 215extern int iscsi_add_session(struct iscsi_cls_session *session,
216 unsigned int target_id); 216 unsigned int target_id);
217extern int iscsi_if_create_session_done(struct iscsi_cls_conn *conn);
218extern int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn);
217extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, 219extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
218 struct iscsi_transport *t, 220 struct iscsi_transport *t,
219 unsigned int target_id); 221 unsigned int target_id);
@@ -226,4 +228,5 @@ extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn);
226extern void iscsi_unblock_session(struct iscsi_cls_session *session); 228extern void iscsi_unblock_session(struct iscsi_cls_session *session);
227extern void iscsi_block_session(struct iscsi_cls_session *session); 229extern void iscsi_block_session(struct iscsi_cls_session *session);
228 230
231
229#endif 232#endif