Commit 26974789 authored by Mike Christie's avatar Mike Christie Committed by James Bottomley

[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: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent bc436b27
...@@ -1662,7 +1662,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) ...@@ -1662,7 +1662,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
struct iscsi_session *session = iscsi_hostdata(shost->hostdata); struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
struct module *owner = cls_session->transport->owner; struct module *owner = cls_session->transport->owner;
iscsi_unblock_session(cls_session); iscsi_remove_session(cls_session);
scsi_remove_host(shost); scsi_remove_host(shost);
iscsi_pool_free(&session->mgmtpool); iscsi_pool_free(&session->mgmtpool);
...@@ -1677,7 +1677,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) ...@@ -1677,7 +1677,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
kfree(session->hwaddress); kfree(session->hwaddress);
kfree(session->initiatorname); kfree(session->initiatorname);
iscsi_destroy_session(cls_session); iscsi_free_session(cls_session);
scsi_host_put(shost); scsi_host_put(shost);
module_put(owner); module_put(owner);
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* See LICENSE.qla4xxx for copyright and licensing details. * See LICENSE.qla4xxx for copyright and licensing details.
*/ */
#include <scsi/iscsi_if.h>
#include "ql4_def.h" #include "ql4_def.h"
#include "ql4_glbl.h" #include "ql4_glbl.h"
#include "ql4_dbg.h" #include "ql4_dbg.h"
...@@ -1305,7 +1306,8 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, ...@@ -1305,7 +1306,8 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
atomic_set(&ddb_entry->relogin_timer, 0); atomic_set(&ddb_entry->relogin_timer, 0);
clear_bit(DF_RELOGIN, &ddb_entry->flags); clear_bit(DF_RELOGIN, &ddb_entry->flags);
clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); clear_bit(DF_NO_RELOGIN, &ddb_entry->flags);
iscsi_if_create_session_done(ddb_entry->conn); iscsi_session_event(ddb_entry->sess,
ISCSI_KEVENT_CREATE_SESSION);
/* /*
* Change the lun state to READY in case the lun TIMEOUT before * Change the lun state to READY in case the lun TIMEOUT before
* the device came back. * the device came back.
......
...@@ -298,8 +298,7 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry) ...@@ -298,8 +298,7 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry)
return; return;
if (ddb_entry->conn) { if (ddb_entry->conn) {
iscsi_if_destroy_session_done(ddb_entry->conn); atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
iscsi_destroy_conn(ddb_entry->conn);
iscsi_remove_session(ddb_entry->sess); iscsi_remove_session(ddb_entry->sess);
} }
iscsi_free_session(ddb_entry->sess); iscsi_free_session(ddb_entry->sess);
...@@ -309,6 +308,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) ...@@ -309,6 +308,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
{ {
int err; int err;
ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index);
if (err) { if (err) {
DEBUG2(printk(KERN_ERR "Could not add session.\n")); DEBUG2(printk(KERN_ERR "Could not add session.\n"));
...@@ -321,9 +321,6 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) ...@@ -321,9 +321,6 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
DEBUG2(printk(KERN_ERR "Could not add connection.\n")); DEBUG2(printk(KERN_ERR "Could not add connection.\n"));
return -ENOMEM; return -ENOMEM;
} }
ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
iscsi_if_create_session_done(ddb_entry->conn);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -49,12 +49,15 @@ enum iscsi_uevent_e { ...@@ -49,12 +49,15 @@ enum iscsi_uevent_e {
ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15, ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15,
ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16, ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16,
ISCSI_UEVENT_UNBIND_SESSION = UEVENT_BASE + 17,
/* up events */ /* up events */
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2, ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2,
ISCSI_KEVENT_IF_ERROR = KEVENT_BASE + 3, ISCSI_KEVENT_IF_ERROR = KEVENT_BASE + 3,
ISCSI_KEVENT_DESTROY_SESSION = KEVENT_BASE + 4, ISCSI_KEVENT_DESTROY_SESSION = KEVENT_BASE + 4,
ISCSI_KEVENT_UNBIND_SESSION = KEVENT_BASE + 5,
ISCSI_KEVENT_CREATE_SESSION = KEVENT_BASE + 6,
}; };
enum iscsi_tgt_dscvr { enum iscsi_tgt_dscvr {
...@@ -156,6 +159,10 @@ struct iscsi_uevent { ...@@ -156,6 +159,10 @@ struct iscsi_uevent {
uint32_t sid; uint32_t sid;
uint32_t cid; uint32_t cid;
} c_conn_ret; } c_conn_ret;
struct msg_unbind_session {
uint32_t sid;
uint32_t host_no;
} unbind_session;
struct msg_recv_req { struct msg_recv_req {
uint32_t sid; uint32_t sid;
uint32_t cid; uint32_t cid;
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#ifndef ISCSI_PROTO_H #ifndef ISCSI_PROTO_H
#define ISCSI_PROTO_H #define ISCSI_PROTO_H
#include <linux/types.h>
#define ISCSI_DRAFT20_VERSION 0x00 #define ISCSI_DRAFT20_VERSION 0x00
/* default iSCSI listen port for incoming connections */ /* default iSCSI listen port for incoming connections */
......
...@@ -186,6 +186,7 @@ struct iscsi_cls_session { ...@@ -186,6 +186,7 @@ struct iscsi_cls_session {
/* recovery fields */ /* recovery fields */
int recovery_tmo; int recovery_tmo;
struct delayed_work recovery_work; struct delayed_work recovery_work;
struct work_struct unbind_work;
int target_id; int target_id;
...@@ -206,6 +207,8 @@ struct iscsi_cls_session { ...@@ -206,6 +207,8 @@ struct iscsi_cls_session {
struct iscsi_host { struct iscsi_host {
struct list_head sessions; struct list_head sessions;
struct mutex mutex; struct mutex mutex;
struct workqueue_struct *unbind_workq;
char unbind_workq_name[KOBJ_NAME_LEN];
}; };
/* /*
...@@ -215,8 +218,8 @@ extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost, ...@@ -215,8 +218,8 @@ extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost,
struct iscsi_transport *transport); struct iscsi_transport *transport);
extern int iscsi_add_session(struct iscsi_cls_session *session, extern int iscsi_add_session(struct iscsi_cls_session *session,
unsigned int target_id); unsigned int target_id);
extern int iscsi_if_create_session_done(struct iscsi_cls_conn *conn); extern int iscsi_session_event(struct iscsi_cls_session *session,
extern int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn); enum iscsi_uevent_e event);
extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
struct iscsi_transport *t, struct iscsi_transport *t,
unsigned int target_id); unsigned int target_id);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment