aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/libiscsi.c4
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c4
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c7
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c289
-rw-r--r--include/scsi/iscsi_if.h7
-rw-r--r--include/scsi/iscsi_proto.h2
-rw-r--r--include/scsi/scsi_transport_iscsi.h7
7 files changed, 176 insertions, 144 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 441e351b4456..5205ef2c29b2 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1662,7 +1662,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
1662 struct iscsi_session *session = iscsi_hostdata(shost->hostdata); 1662 struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
1663 struct module *owner = cls_session->transport->owner; 1663 struct module *owner = cls_session->transport->owner;
1664 1664
1665 iscsi_unblock_session(cls_session); 1665 iscsi_remove_session(cls_session);
1666 scsi_remove_host(shost); 1666 scsi_remove_host(shost);
1667 1667
1668 iscsi_pool_free(&session->mgmtpool); 1668 iscsi_pool_free(&session->mgmtpool);
@@ -1677,7 +1677,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
1677 kfree(session->hwaddress); 1677 kfree(session->hwaddress);
1678 kfree(session->initiatorname); 1678 kfree(session->initiatorname);
1679 1679
1680 iscsi_destroy_session(cls_session); 1680 iscsi_free_session(cls_session);
1681 scsi_host_put(shost); 1681 scsi_host_put(shost);
1682 module_put(owner); 1682 module_put(owner);
1683} 1683}
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index d692c713416a..cbe0a17ced5f 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -5,6 +5,7 @@
5 * See LICENSE.qla4xxx for copyright and licensing details. 5 * See LICENSE.qla4xxx for copyright and licensing details.
6 */ 6 */
7 7
8#include <scsi/iscsi_if.h>
8#include "ql4_def.h" 9#include "ql4_def.h"
9#include "ql4_glbl.h" 10#include "ql4_glbl.h"
10#include "ql4_dbg.h" 11#include "ql4_dbg.h"
@@ -1305,7 +1306,8 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
1305 atomic_set(&ddb_entry->relogin_timer, 0); 1306 atomic_set(&ddb_entry->relogin_timer, 0);
1306 clear_bit(DF_RELOGIN, &ddb_entry->flags); 1307 clear_bit(DF_RELOGIN, &ddb_entry->flags);
1307 clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); 1308 clear_bit(DF_NO_RELOGIN, &ddb_entry->flags);
1308 iscsi_if_create_session_done(ddb_entry->conn); 1309 iscsi_session_event(ddb_entry->sess,
1310 ISCSI_KEVENT_CREATE_SESSION);
1309 /* 1311 /*
1310 * Change the lun state to READY in case the lun TIMEOUT before 1312 * Change the lun state to READY in case the lun TIMEOUT before
1311 * the device came back. 1313 * the device came back.
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 89460d27c689..f55b9f7d9396 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -298,8 +298,7 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry)
298 return; 298 return;
299 299
300 if (ddb_entry->conn) { 300 if (ddb_entry->conn) {
301 iscsi_if_destroy_session_done(ddb_entry->conn); 301 atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
302 iscsi_destroy_conn(ddb_entry->conn);
303 iscsi_remove_session(ddb_entry->sess); 302 iscsi_remove_session(ddb_entry->sess);
304 } 303 }
305 iscsi_free_session(ddb_entry->sess); 304 iscsi_free_session(ddb_entry->sess);
@@ -309,6 +308,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
309{ 308{
310 int err; 309 int err;
311 310
311 ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
312 err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); 312 err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index);
313 if (err) { 313 if (err) {
314 DEBUG2(printk(KERN_ERR "Could not add session.\n")); 314 DEBUG2(printk(KERN_ERR "Could not add session.\n"));
@@ -321,9 +321,6 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
321 DEBUG2(printk(KERN_ERR "Could not add connection.\n")); 321 DEBUG2(printk(KERN_ERR "Could not add connection.\n"));
322 return -ENOMEM; 322 return -ENOMEM;
323 } 323 }
324
325 ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
326 iscsi_if_create_session_done(ddb_entry->conn);
327 return 0; 324 return 0;
328} 325}
329 326
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 9cc2cc8e87b3..b82139dc4830 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -116,6 +116,8 @@ static struct attribute_group iscsi_transport_group = {
116 .attrs = iscsi_transport_attrs, 116 .attrs = iscsi_transport_attrs,
117}; 117};
118 118
119
120
119static int iscsi_setup_host(struct transport_container *tc, struct device *dev, 121static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
120 struct class_device *cdev) 122 struct class_device *cdev)
121{ 123{
@@ -125,13 +127,30 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
125 memset(ihost, 0, sizeof(*ihost)); 127 memset(ihost, 0, sizeof(*ihost));
126 INIT_LIST_HEAD(&ihost->sessions); 128 INIT_LIST_HEAD(&ihost->sessions);
127 mutex_init(&ihost->mutex); 129 mutex_init(&ihost->mutex);
130
131 snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d",
132 shost->host_no);
133 ihost->unbind_workq = create_singlethread_workqueue(
134 ihost->unbind_workq_name);
135 if (!ihost->unbind_workq)
136 return -ENOMEM;
137 return 0;
138}
139
140static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
141 struct class_device *cdev)
142{
143 struct Scsi_Host *shost = dev_to_shost(dev);
144 struct iscsi_host *ihost = shost->shost_data;
145
146 destroy_workqueue(ihost->unbind_workq);
128 return 0; 147 return 0;
129} 148}
130 149
131static DECLARE_TRANSPORT_CLASS(iscsi_host_class, 150static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
132 "iscsi_host", 151 "iscsi_host",
133 iscsi_setup_host, 152 iscsi_setup_host,
134 NULL, 153 iscsi_remove_host,
135 NULL); 154 NULL);
136 155
137static DECLARE_TRANSPORT_CLASS(iscsi_session_class, 156static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
@@ -266,6 +285,35 @@ void iscsi_block_session(struct iscsi_cls_session *session)
266} 285}
267EXPORT_SYMBOL_GPL(iscsi_block_session); 286EXPORT_SYMBOL_GPL(iscsi_block_session);
268 287
288static void __iscsi_unbind_session(struct work_struct *work)
289{
290 struct iscsi_cls_session *session =
291 container_of(work, struct iscsi_cls_session,
292 unbind_work);
293 struct Scsi_Host *shost = iscsi_session_to_shost(session);
294 struct iscsi_host *ihost = shost->shost_data;
295
296 /* Prevent new scans and make sure scanning is not in progress */
297 mutex_lock(&ihost->mutex);
298 if (list_empty(&session->host_list)) {
299 mutex_unlock(&ihost->mutex);
300 return;
301 }
302 list_del_init(&session->host_list);
303 mutex_unlock(&ihost->mutex);
304
305 scsi_remove_target(&session->dev);
306 iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
307}
308
309static int iscsi_unbind_session(struct iscsi_cls_session *session)
310{
311 struct Scsi_Host *shost = iscsi_session_to_shost(session);
312 struct iscsi_host *ihost = shost->shost_data;
313
314 return queue_work(ihost->unbind_workq, &session->unbind_work);
315}
316
269struct iscsi_cls_session * 317struct iscsi_cls_session *
270iscsi_alloc_session(struct Scsi_Host *shost, 318iscsi_alloc_session(struct Scsi_Host *shost,
271 struct iscsi_transport *transport) 319 struct iscsi_transport *transport)
@@ -282,6 +330,7 @@ iscsi_alloc_session(struct Scsi_Host *shost,
282 INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); 330 INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
283 INIT_LIST_HEAD(&session->host_list); 331 INIT_LIST_HEAD(&session->host_list);
284 INIT_LIST_HEAD(&session->sess_list); 332 INIT_LIST_HEAD(&session->sess_list);
333 INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
285 334
286 /* this is released in the dev's release function */ 335 /* this is released in the dev's release function */
287 scsi_host_get(shost); 336 scsi_host_get(shost);
@@ -298,6 +347,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
298{ 347{
299 struct Scsi_Host *shost = iscsi_session_to_shost(session); 348 struct Scsi_Host *shost = iscsi_session_to_shost(session);
300 struct iscsi_host *ihost; 349 struct iscsi_host *ihost;
350 unsigned long flags;
301 int err; 351 int err;
302 352
303 ihost = shost->shost_data; 353 ihost = shost->shost_data;
@@ -314,9 +364,15 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
314 } 364 }
315 transport_register_device(&session->dev); 365 transport_register_device(&session->dev);
316 366
367 spin_lock_irqsave(&sesslock, flags);
368 list_add(&session->sess_list, &sesslist);
369 spin_unlock_irqrestore(&sesslock, flags);
370
317 mutex_lock(&ihost->mutex); 371 mutex_lock(&ihost->mutex);
318 list_add(&session->host_list, &ihost->sessions); 372 list_add(&session->host_list, &ihost->sessions);
319 mutex_unlock(&ihost->mutex); 373 mutex_unlock(&ihost->mutex);
374
375 iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
320 return 0; 376 return 0;
321 377
322release_host: 378release_host:
@@ -352,19 +408,58 @@ iscsi_create_session(struct Scsi_Host *shost,
352} 408}
353EXPORT_SYMBOL_GPL(iscsi_create_session); 409EXPORT_SYMBOL_GPL(iscsi_create_session);
354 410
411static void iscsi_conn_release(struct device *dev)
412{
413 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
414 struct device *parent = conn->dev.parent;
415
416 kfree(conn);
417 put_device(parent);
418}
419
420static int iscsi_is_conn_dev(const struct device *dev)
421{
422 return dev->release == iscsi_conn_release;
423}
424
425static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
426{
427 if (!iscsi_is_conn_dev(dev))
428 return 0;
429 return iscsi_destroy_conn(iscsi_dev_to_conn(dev));
430}
431
355void iscsi_remove_session(struct iscsi_cls_session *session) 432void iscsi_remove_session(struct iscsi_cls_session *session)
356{ 433{
357 struct Scsi_Host *shost = iscsi_session_to_shost(session); 434 struct Scsi_Host *shost = iscsi_session_to_shost(session);
358 struct iscsi_host *ihost = shost->shost_data; 435 struct iscsi_host *ihost = shost->shost_data;
436 unsigned long flags;
437 int err;
438
439 spin_lock_irqsave(&sesslock, flags);
440 list_del(&session->sess_list);
441 spin_unlock_irqrestore(&sesslock, flags);
359 442
443 /*
444 * If we are blocked let commands flow again. The lld or iscsi
445 * layer should set up the queuecommand to fail commands.
446 */
447 iscsi_unblock_session(session);
448 iscsi_unbind_session(session);
449 /*
450 * If the session dropped while removing devices then we need to make
451 * sure it is not blocked
452 */
360 if (!cancel_delayed_work(&session->recovery_work)) 453 if (!cancel_delayed_work(&session->recovery_work))
361 flush_workqueue(iscsi_eh_timer_workq); 454 flush_workqueue(iscsi_eh_timer_workq);
455 flush_workqueue(ihost->unbind_workq);
362 456
363 mutex_lock(&ihost->mutex); 457 /* hw iscsi may not have removed all connections from session */
364 list_del(&session->host_list); 458 err = device_for_each_child(&session->dev, NULL,
365 mutex_unlock(&ihost->mutex); 459 iscsi_iter_destroy_conn_fn);
366 460 if (err)
367 scsi_remove_target(&session->dev); 461 dev_printk(KERN_ERR, &session->dev, "iscsi: Could not delete "
462 "all connections for session. Error %d.\n", err);
368 463
369 transport_unregister_device(&session->dev); 464 transport_unregister_device(&session->dev);
370 device_del(&session->dev); 465 device_del(&session->dev);
@@ -373,9 +468,9 @@ EXPORT_SYMBOL_GPL(iscsi_remove_session);
373 468
374void iscsi_free_session(struct iscsi_cls_session *session) 469void iscsi_free_session(struct iscsi_cls_session *session)
375{ 470{
471 iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION);
376 put_device(&session->dev); 472 put_device(&session->dev);
377} 473}
378
379EXPORT_SYMBOL_GPL(iscsi_free_session); 474EXPORT_SYMBOL_GPL(iscsi_free_session);
380 475
381/** 476/**
@@ -393,20 +488,6 @@ int iscsi_destroy_session(struct iscsi_cls_session *session)
393} 488}
394EXPORT_SYMBOL_GPL(iscsi_destroy_session); 489EXPORT_SYMBOL_GPL(iscsi_destroy_session);
395 490
396static void iscsi_conn_release(struct device *dev)
397{
398 struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
399 struct device *parent = conn->dev.parent;
400
401 kfree(conn);
402 put_device(parent);
403}
404
405static int iscsi_is_conn_dev(const struct device *dev)
406{
407 return dev->release == iscsi_conn_release;
408}
409
410/** 491/**
411 * iscsi_create_conn - create iscsi class connection 492 * iscsi_create_conn - create iscsi class connection
412 * @session: iscsi cls session 493 * @session: iscsi cls session
@@ -426,6 +507,7 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
426{ 507{
427 struct iscsi_transport *transport = session->transport; 508 struct iscsi_transport *transport = session->transport;
428 struct iscsi_cls_conn *conn; 509 struct iscsi_cls_conn *conn;
510 unsigned long flags;
429 int err; 511 int err;
430 512
431 conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL); 513 conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL);
@@ -454,6 +536,11 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
454 goto release_parent_ref; 536 goto release_parent_ref;
455 } 537 }
456 transport_register_device(&conn->dev); 538 transport_register_device(&conn->dev);
539
540 spin_lock_irqsave(&connlock, flags);
541 list_add(&conn->conn_list, &connlist);
542 conn->active = 1;
543 spin_unlock_irqrestore(&connlock, flags);
457 return conn; 544 return conn;
458 545
459release_parent_ref: 546release_parent_ref:
@@ -469,15 +556,21 @@ EXPORT_SYMBOL_GPL(iscsi_create_conn);
469 * iscsi_destroy_conn - destroy iscsi class connection 556 * iscsi_destroy_conn - destroy iscsi class connection
470 * @conn: iscsi cls session 557 * @conn: iscsi cls session
471 * 558 *
472 * This can be called from an LLD or iscsi_transport. 559 * This can be called from a LLD or iscsi_transport.
473 */ 560 */
474int iscsi_destroy_conn(struct iscsi_cls_conn *conn) 561int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
475{ 562{
563 unsigned long flags;
564
565 spin_lock_irqsave(&connlock, flags);
566 conn->active = 0;
567 list_del(&conn->conn_list);
568 spin_unlock_irqrestore(&connlock, flags);
569
476 transport_unregister_device(&conn->dev); 570 transport_unregister_device(&conn->dev);
477 device_unregister(&conn->dev); 571 device_unregister(&conn->dev);
478 return 0; 572 return 0;
479} 573}
480
481EXPORT_SYMBOL_GPL(iscsi_destroy_conn); 574EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
482 575
483/* 576/*
@@ -687,132 +780,74 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
687} 780}
688 781
689/** 782/**
690 * iscsi_if_destroy_session_done - send session destr. completion event 783 * iscsi_session_event - send session destr. completion event
691 * @conn: last connection for session 784 * @session: iscsi class session
692 * 785 * @event: type of event
693 * This is called by HW iscsi LLDs to notify userpsace that its HW has
694 * removed a session.
695 */ 786 */
696int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn) 787int iscsi_session_event(struct iscsi_cls_session *session,
788 enum iscsi_uevent_e event)
697{ 789{
698 struct iscsi_internal *priv; 790 struct iscsi_internal *priv;
699 struct iscsi_cls_session *session;
700 struct Scsi_Host *shost; 791 struct Scsi_Host *shost;
701 struct iscsi_uevent *ev; 792 struct iscsi_uevent *ev;
702 struct sk_buff *skb; 793 struct sk_buff *skb;
703 struct nlmsghdr *nlh; 794 struct nlmsghdr *nlh;
704 unsigned long flags;
705 int rc, len = NLMSG_SPACE(sizeof(*ev)); 795 int rc, len = NLMSG_SPACE(sizeof(*ev));
706 796
707 priv = iscsi_if_transport_lookup(conn->transport); 797 priv = iscsi_if_transport_lookup(session->transport);
708 if (!priv) 798 if (!priv)
709 return -EINVAL; 799 return -EINVAL;
710
711 session = iscsi_dev_to_session(conn->dev.parent);
712 shost = iscsi_session_to_shost(session); 800 shost = iscsi_session_to_shost(session);
713 801
714 skb = alloc_skb(len, GFP_KERNEL); 802 skb = alloc_skb(len, GFP_KERNEL);
715 if (!skb) { 803 if (!skb) {
716 dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " 804 dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace "
717 "session creation event\n"); 805 "of session event %u\n", event);
718 return -ENOMEM; 806 return -ENOMEM;
719 } 807 }
720 808
721 nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); 809 nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
722 ev = NLMSG_DATA(nlh); 810 ev = NLMSG_DATA(nlh);
723 ev->transport_handle = iscsi_handle(conn->transport); 811 ev->transport_handle = iscsi_handle(session->transport);
724 ev->type = ISCSI_KEVENT_DESTROY_SESSION;
725 ev->r.d_session.host_no = shost->host_no;
726 ev->r.d_session.sid = session->sid;
727
728 /*
729 * this will occur if the daemon is not up, so we just warn
730 * the user and when the daemon is restarted it will handle it
731 */
732 rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
733 if (rc < 0)
734 dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
735 "session destruction event. Check iscsi daemon\n");
736
737 spin_lock_irqsave(&sesslock, flags);
738 list_del(&session->sess_list);
739 spin_unlock_irqrestore(&sesslock, flags);
740
741 spin_lock_irqsave(&connlock, flags);
742 conn->active = 0;
743 list_del(&conn->conn_list);
744 spin_unlock_irqrestore(&connlock, flags);
745
746 return rc;
747}
748EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done);
749
750/**
751 * iscsi_if_create_session_done - send session creation completion event
752 * @conn: leading connection for session
753 *
754 * This is called by HW iscsi LLDs to notify userpsace that its HW has
755 * created a session or a existing session is back in the logged in state.
756 */
757int iscsi_if_create_session_done(struct iscsi_cls_conn *conn)
758{
759 struct iscsi_internal *priv;
760 struct iscsi_cls_session *session;
761 struct Scsi_Host *shost;
762 struct iscsi_uevent *ev;
763 struct sk_buff *skb;
764 struct nlmsghdr *nlh;
765 unsigned long flags;
766 int rc, len = NLMSG_SPACE(sizeof(*ev));
767 812
768 priv = iscsi_if_transport_lookup(conn->transport); 813 ev->type = event;
769 if (!priv) 814 switch (event) {
815 case ISCSI_KEVENT_DESTROY_SESSION:
816 ev->r.d_session.host_no = shost->host_no;
817 ev->r.d_session.sid = session->sid;
818 break;
819 case ISCSI_KEVENT_CREATE_SESSION:
820 ev->r.c_session_ret.host_no = shost->host_no;
821 ev->r.c_session_ret.sid = session->sid;
822 break;
823 case ISCSI_KEVENT_UNBIND_SESSION:
824 ev->r.unbind_session.host_no = shost->host_no;
825 ev->r.unbind_session.sid = session->sid;
826 break;
827 default:
828 dev_printk(KERN_ERR, &session->dev, "Invalid event %u.\n",
829 event);
830 kfree_skb(skb);
770 return -EINVAL; 831 return -EINVAL;
771
772 session = iscsi_dev_to_session(conn->dev.parent);
773 shost = iscsi_session_to_shost(session);
774
775 skb = alloc_skb(len, GFP_KERNEL);
776 if (!skb) {
777 dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
778 "session creation event\n");
779 return -ENOMEM;
780 } 832 }
781 833
782 nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
783 ev = NLMSG_DATA(nlh);
784 ev->transport_handle = iscsi_handle(conn->transport);
785 ev->type = ISCSI_UEVENT_CREATE_SESSION;
786 ev->r.c_session_ret.host_no = shost->host_no;
787 ev->r.c_session_ret.sid = session->sid;
788
789 /* 834 /*
790 * this will occur if the daemon is not up, so we just warn 835 * this will occur if the daemon is not up, so we just warn
791 * the user and when the daemon is restarted it will handle it 836 * the user and when the daemon is restarted it will handle it
792 */ 837 */
793 rc = iscsi_broadcast_skb(skb, GFP_KERNEL); 838 rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
794 if (rc < 0) 839 if (rc < 0)
795 dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " 840 dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace "
796 "session creation event. Check iscsi daemon\n"); 841 "of session event %u. Check iscsi daemon\n", event);
797
798 spin_lock_irqsave(&sesslock, flags);
799 list_add(&session->sess_list, &sesslist);
800 spin_unlock_irqrestore(&sesslock, flags);
801
802 spin_lock_irqsave(&connlock, flags);
803 list_add(&conn->conn_list, &connlist);
804 conn->active = 1;
805 spin_unlock_irqrestore(&connlock, flags);
806 return rc; 842 return rc;
807} 843}
808EXPORT_SYMBOL_GPL(iscsi_if_create_session_done); 844EXPORT_SYMBOL_GPL(iscsi_session_event);
809 845
810static int 846static int
811iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) 847iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
812{ 848{
813 struct iscsi_transport *transport = priv->iscsi_transport; 849 struct iscsi_transport *transport = priv->iscsi_transport;
814 struct iscsi_cls_session *session; 850 struct iscsi_cls_session *session;
815 unsigned long flags;
816 uint32_t hostno; 851 uint32_t hostno;
817 852
818 session = transport->create_session(transport, &priv->t, 853 session = transport->create_session(transport, &priv->t,
@@ -823,10 +858,6 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
823 if (!session) 858 if (!session)
824 return -ENOMEM; 859 return -ENOMEM;
825 860
826 spin_lock_irqsave(&sesslock, flags);
827 list_add(&session->sess_list, &sesslist);
828 spin_unlock_irqrestore(&sesslock, flags);
829
830 ev->r.c_session_ret.host_no = hostno; 861 ev->r.c_session_ret.host_no = hostno;
831 ev->r.c_session_ret.sid = session->sid; 862 ev->r.c_session_ret.sid = session->sid;
832 return 0; 863 return 0;
@@ -837,7 +868,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
837{ 868{
838 struct iscsi_cls_conn *conn; 869 struct iscsi_cls_conn *conn;
839 struct iscsi_cls_session *session; 870 struct iscsi_cls_session *session;
840 unsigned long flags;
841 871
842 session = iscsi_session_lookup(ev->u.c_conn.sid); 872 session = iscsi_session_lookup(ev->u.c_conn.sid);
843 if (!session) { 873 if (!session) {
@@ -856,28 +886,17 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
856 886
857 ev->r.c_conn_ret.sid = session->sid; 887 ev->r.c_conn_ret.sid = session->sid;
858 ev->r.c_conn_ret.cid = conn->cid; 888 ev->r.c_conn_ret.cid = conn->cid;
859
860 spin_lock_irqsave(&connlock, flags);
861 list_add(&conn->conn_list, &connlist);
862 conn->active = 1;
863 spin_unlock_irqrestore(&connlock, flags);
864
865 return 0; 889 return 0;
866} 890}
867 891
868static int 892static int
869iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) 893iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
870{ 894{
871 unsigned long flags;
872 struct iscsi_cls_conn *conn; 895 struct iscsi_cls_conn *conn;
873 896
874 conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid); 897 conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
875 if (!conn) 898 if (!conn)
876 return -EINVAL; 899 return -EINVAL;
877 spin_lock_irqsave(&connlock, flags);
878 conn->active = 0;
879 list_del(&conn->conn_list);
880 spin_unlock_irqrestore(&connlock, flags);
881 900
882 if (transport->destroy_conn) 901 if (transport->destroy_conn)
883 transport->destroy_conn(conn); 902 transport->destroy_conn(conn);
@@ -1004,7 +1023,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1004 struct iscsi_internal *priv; 1023 struct iscsi_internal *priv;
1005 struct iscsi_cls_session *session; 1024 struct iscsi_cls_session *session;
1006 struct iscsi_cls_conn *conn; 1025 struct iscsi_cls_conn *conn;
1007 unsigned long flags;
1008 1026
1009 priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); 1027 priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
1010 if (!priv) 1028 if (!priv)
@@ -1022,13 +1040,16 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1022 break; 1040 break;
1023 case ISCSI_UEVENT_DESTROY_SESSION: 1041 case ISCSI_UEVENT_DESTROY_SESSION:
1024 session = iscsi_session_lookup(ev->u.d_session.sid); 1042 session = iscsi_session_lookup(ev->u.d_session.sid);
1025 if (session) { 1043 if (session)
1026 spin_lock_irqsave(&sesslock, flags);
1027 list_del(&session->sess_list);
1028 spin_unlock_irqrestore(&sesslock, flags);
1029
1030 transport->destroy_session(session); 1044 transport->destroy_session(session);
1031 } else 1045 else
1046 err = -EINVAL;
1047 break;
1048 case ISCSI_UEVENT_UNBIND_SESSION:
1049 session = iscsi_session_lookup(ev->u.d_session.sid);
1050 if (session)
1051 iscsi_unbind_session(session);
1052 else
1032 err = -EINVAL; 1053 err = -EINVAL;
1033 break; 1054 break;
1034 case ISCSI_UEVENT_CREATE_CONN: 1055 case ISCSI_UEVENT_CREATE_CONN:
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index bff0b1f7857b..8a4426df6c3a 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -49,12 +49,15 @@ enum iscsi_uevent_e {
49 49
50 ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15, 50 ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15,
51 ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16, 51 ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16,
52 ISCSI_UEVENT_UNBIND_SESSION = UEVENT_BASE + 17,
52 53
53 /* up events */ 54 /* up events */
54 ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, 55 ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
55 ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2, 56 ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2,
56 ISCSI_KEVENT_IF_ERROR = KEVENT_BASE + 3, 57 ISCSI_KEVENT_IF_ERROR = KEVENT_BASE + 3,
57 ISCSI_KEVENT_DESTROY_SESSION = KEVENT_BASE + 4, 58 ISCSI_KEVENT_DESTROY_SESSION = KEVENT_BASE + 4,
59 ISCSI_KEVENT_UNBIND_SESSION = KEVENT_BASE + 5,
60 ISCSI_KEVENT_CREATE_SESSION = KEVENT_BASE + 6,
58}; 61};
59 62
60enum iscsi_tgt_dscvr { 63enum iscsi_tgt_dscvr {
@@ -156,6 +159,10 @@ struct iscsi_uevent {
156 uint32_t sid; 159 uint32_t sid;
157 uint32_t cid; 160 uint32_t cid;
158 } c_conn_ret; 161 } c_conn_ret;
162 struct msg_unbind_session {
163 uint32_t sid;
164 uint32_t host_no;
165 } unbind_session;
159 struct msg_recv_req { 166 struct msg_recv_req {
160 uint32_t sid; 167 uint32_t sid;
161 uint32_t cid; 168 uint32_t cid;
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index 6947082eee6d..318a909e7ae1 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -21,6 +21,8 @@
21#ifndef ISCSI_PROTO_H 21#ifndef ISCSI_PROTO_H
22#define ISCSI_PROTO_H 22#define ISCSI_PROTO_H
23 23
24#include <linux/types.h>
25
24#define ISCSI_DRAFT20_VERSION 0x00 26#define ISCSI_DRAFT20_VERSION 0x00
25 27
26/* default iSCSI listen port for incoming connections */ 28/* default iSCSI listen port for incoming connections */
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index b8d97bd20f6e..093b4036f8db 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -186,6 +186,7 @@ struct iscsi_cls_session {
186 /* recovery fields */ 186 /* recovery fields */
187 int recovery_tmo; 187 int recovery_tmo;
188 struct delayed_work recovery_work; 188 struct delayed_work recovery_work;
189 struct work_struct unbind_work;
189 190
190 int target_id; 191 int target_id;
191 192
@@ -206,6 +207,8 @@ struct iscsi_cls_session {
206struct iscsi_host { 207struct iscsi_host {
207 struct list_head sessions; 208 struct list_head sessions;
208 struct mutex mutex; 209 struct mutex mutex;
210 struct workqueue_struct *unbind_workq;
211 char unbind_workq_name[KOBJ_NAME_LEN];
209}; 212};
210 213
211/* 214/*
@@ -215,8 +218,8 @@ extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost,
215 struct iscsi_transport *transport); 218 struct iscsi_transport *transport);
216extern int iscsi_add_session(struct iscsi_cls_session *session, 219extern int iscsi_add_session(struct iscsi_cls_session *session,
217 unsigned int target_id); 220 unsigned int target_id);
218extern int iscsi_if_create_session_done(struct iscsi_cls_conn *conn); 221extern int iscsi_session_event(struct iscsi_cls_session *session,
219extern int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn); 222 enum iscsi_uevent_e event);
220extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, 223extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
221 struct iscsi_transport *t, 224 struct iscsi_transport *t,
222 unsigned int target_id); 225 unsigned int target_id);