aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2007-12-13 13:43:29 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-11 19:28:33 -0500
commit2697478903d0ad8bdbf868b1346ae4b891662bb1 (patch)
tree8b40d774c0a6f33f9320333a20e08fa920f154fc
parentbc436b278776d22eb10e7e75bf3e5257d14550a9 (diff)
[SCSI] libiscsi: fix shutdown
We were using the device delete sysfs file to remove each device then logout. Now in 2.6.21 this will not work because the sysfs delete file returns immediately and does not wait for the device removal to complete. This causes a hang if a cache sync is needed during shutdown. Before .21, that approach had other problems, so this patch fixes the shutdown code so that we remove the target and unbind the session before logging out and shut down the session Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-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);