aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c1
-rw-r--r--drivers/scsi/iscsi_tcp.c1
-rw-r--r--drivers/scsi/libiscsi.c107
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c2
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c6
-rw-r--r--include/scsi/iscsi_if.h1
-rw-r--r--include/scsi/libiscsi.h13
-rw-r--r--include/scsi/scsi_transport_iscsi.h3
8 files changed, 121 insertions, 13 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 5a1cf2580e16..0474da173eb1 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -378,6 +378,7 @@ static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session)
378{ 378{
379 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); 379 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
380 380
381 iscsi_session_teardown(cls_session);
381 iscsi_host_remove(shost); 382 iscsi_host_remove(shost);
382 iscsi_host_free(shost); 383 iscsi_host_free(shost);
383} 384}
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index e960f00da93a..752f42884cc1 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -1885,6 +1885,7 @@ static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session)
1885 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); 1885 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
1886 1886
1887 iscsi_r2tpool_free(cls_session->dd_data); 1887 iscsi_r2tpool_free(cls_session->dd_data);
1888 iscsi_session_teardown(cls_session);
1888 1889
1889 iscsi_host_remove(shost); 1890 iscsi_host_remove(shost);
1890 iscsi_host_free(shost); 1891 iscsi_host_free(shost);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index f9539af28f02..390781894be9 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -983,6 +983,38 @@ struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
983} 983}
984EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask); 984EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask);
985 985
986void iscsi_session_failure(struct iscsi_cls_session *cls_session,
987 enum iscsi_err err)
988{
989 struct iscsi_session *session = cls_session->dd_data;
990 struct iscsi_conn *conn;
991 struct device *dev;
992 unsigned long flags;
993
994 spin_lock_irqsave(&session->lock, flags);
995 conn = session->leadconn;
996 if (session->state == ISCSI_STATE_TERMINATE || !conn) {
997 spin_unlock_irqrestore(&session->lock, flags);
998 return;
999 }
1000
1001 dev = get_device(&conn->cls_conn->dev);
1002 spin_unlock_irqrestore(&session->lock, flags);
1003 if (!dev)
1004 return;
1005 /*
1006 * if the host is being removed bypass the connection
1007 * recovery initialization because we are going to kill
1008 * the session.
1009 */
1010 if (err == ISCSI_ERR_INVALID_HOST)
1011 iscsi_conn_error_event(conn->cls_conn, err);
1012 else
1013 iscsi_conn_failure(conn, err);
1014 put_device(dev);
1015}
1016EXPORT_SYMBOL_GPL(iscsi_session_failure);
1017
986void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) 1018void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
987{ 1019{
988 struct iscsi_session *session = conn->session; 1020 struct iscsi_session *session = conn->session;
@@ -997,9 +1029,10 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
997 if (conn->stop_stage == 0) 1029 if (conn->stop_stage == 0)
998 session->state = ISCSI_STATE_FAILED; 1030 session->state = ISCSI_STATE_FAILED;
999 spin_unlock_irqrestore(&session->lock, flags); 1031 spin_unlock_irqrestore(&session->lock, flags);
1032
1000 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 1033 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1001 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); 1034 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
1002 iscsi_conn_error(conn->cls_conn, err); 1035 iscsi_conn_error_event(conn->cls_conn, err);
1003} 1036}
1004EXPORT_SYMBOL_GPL(iscsi_conn_failure); 1037EXPORT_SYMBOL_GPL(iscsi_conn_failure);
1005 1038
@@ -1905,6 +1938,7 @@ struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
1905 int dd_data_size, uint16_t qdepth) 1938 int dd_data_size, uint16_t qdepth)
1906{ 1939{
1907 struct Scsi_Host *shost; 1940 struct Scsi_Host *shost;
1941 struct iscsi_host *ihost;
1908 1942
1909 shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size); 1943 shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size);
1910 if (!shost) 1944 if (!shost)
@@ -1919,22 +1953,43 @@ struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
1919 qdepth = ISCSI_DEF_CMD_PER_LUN; 1953 qdepth = ISCSI_DEF_CMD_PER_LUN;
1920 } 1954 }
1921 shost->cmd_per_lun = qdepth; 1955 shost->cmd_per_lun = qdepth;
1956
1957 ihost = shost_priv(shost);
1958 spin_lock_init(&ihost->lock);
1959 ihost->state = ISCSI_HOST_SETUP;
1960 ihost->num_sessions = 0;
1961 init_waitqueue_head(&ihost->session_removal_wq);
1922 return shost; 1962 return shost;
1923} 1963}
1924EXPORT_SYMBOL_GPL(iscsi_host_alloc); 1964EXPORT_SYMBOL_GPL(iscsi_host_alloc);
1925 1965
1966static void iscsi_notify_host_removed(struct iscsi_cls_session *cls_session)
1967{
1968 iscsi_session_failure(cls_session, ISCSI_ERR_INVALID_HOST);
1969}
1970
1926/** 1971/**
1927 * iscsi_host_remove - remove host and sessions 1972 * iscsi_host_remove - remove host and sessions
1928 * @shost: scsi host 1973 * @shost: scsi host
1929 * 1974 *
1930 * This will also remove any sessions attached to the host, but if userspace 1975 * If there are any sessions left, this will initiate the removal and wait
1931 * is managing the session at the same time this will break. TODO: add 1976 * for the completion.
1932 * refcounting to the netlink iscsi interface so a rmmod or host hot unplug
1933 * does not remove the memory from under us.
1934 */ 1977 */
1935void iscsi_host_remove(struct Scsi_Host *shost) 1978void iscsi_host_remove(struct Scsi_Host *shost)
1936{ 1979{
1937 iscsi_host_for_each_session(shost, iscsi_session_teardown); 1980 struct iscsi_host *ihost = shost_priv(shost);
1981 unsigned long flags;
1982
1983 spin_lock_irqsave(&ihost->lock, flags);
1984 ihost->state = ISCSI_HOST_REMOVED;
1985 spin_unlock_irqrestore(&ihost->lock, flags);
1986
1987 iscsi_host_for_each_session(shost, iscsi_notify_host_removed);
1988 wait_event_interruptible(ihost->session_removal_wq,
1989 ihost->num_sessions == 0);
1990 if (signal_pending(current))
1991 flush_signals(current);
1992
1938 scsi_remove_host(shost); 1993 scsi_remove_host(shost);
1939} 1994}
1940EXPORT_SYMBOL_GPL(iscsi_host_remove); 1995EXPORT_SYMBOL_GPL(iscsi_host_remove);
@@ -1950,6 +2005,27 @@ void iscsi_host_free(struct Scsi_Host *shost)
1950} 2005}
1951EXPORT_SYMBOL_GPL(iscsi_host_free); 2006EXPORT_SYMBOL_GPL(iscsi_host_free);
1952 2007
2008static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost)
2009{
2010 struct iscsi_host *ihost = shost_priv(shost);
2011 unsigned long flags;
2012
2013 shost = scsi_host_get(shost);
2014 if (!shost) {
2015 printk(KERN_ERR "Invalid state. Cannot notify host removal "
2016 "of session teardown event because host already "
2017 "removed.\n");
2018 return;
2019 }
2020
2021 spin_lock_irqsave(&ihost->lock, flags);
2022 ihost->num_sessions--;
2023 if (ihost->num_sessions == 0)
2024 wake_up(&ihost->session_removal_wq);
2025 spin_unlock_irqrestore(&ihost->lock, flags);
2026 scsi_host_put(shost);
2027}
2028
1953/** 2029/**
1954 * iscsi_session_setup - create iscsi cls session and host and session 2030 * iscsi_session_setup - create iscsi cls session and host and session
1955 * @iscsit: iscsi transport template 2031 * @iscsit: iscsi transport template
@@ -1970,9 +2046,19 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
1970 uint16_t cmds_max, int cmd_task_size, 2046 uint16_t cmds_max, int cmd_task_size,
1971 uint32_t initial_cmdsn, unsigned int id) 2047 uint32_t initial_cmdsn, unsigned int id)
1972{ 2048{
2049 struct iscsi_host *ihost = shost_priv(shost);
1973 struct iscsi_session *session; 2050 struct iscsi_session *session;
1974 struct iscsi_cls_session *cls_session; 2051 struct iscsi_cls_session *cls_session;
1975 int cmd_i, scsi_cmds, total_cmds = cmds_max; 2052 int cmd_i, scsi_cmds, total_cmds = cmds_max;
2053 unsigned long flags;
2054
2055 spin_lock_irqsave(&ihost->lock, flags);
2056 if (ihost->state == ISCSI_HOST_REMOVED) {
2057 spin_unlock_irqrestore(&ihost->lock, flags);
2058 return NULL;
2059 }
2060 ihost->num_sessions++;
2061 spin_unlock_irqrestore(&ihost->lock, flags);
1976 2062
1977 if (!total_cmds) 2063 if (!total_cmds)
1978 total_cmds = ISCSI_DEF_XMIT_CMDS_MAX; 2064 total_cmds = ISCSI_DEF_XMIT_CMDS_MAX;
@@ -1985,7 +2071,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
1985 printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue " 2071 printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
1986 "must be a power of two that is at least %d.\n", 2072 "must be a power of two that is at least %d.\n",
1987 total_cmds, ISCSI_TOTAL_CMDS_MIN); 2073 total_cmds, ISCSI_TOTAL_CMDS_MIN);
1988 return NULL; 2074 goto dec_session_count;
1989 } 2075 }
1990 2076
1991 if (total_cmds > ISCSI_TOTAL_CMDS_MAX) { 2077 if (total_cmds > ISCSI_TOTAL_CMDS_MAX) {
@@ -2009,7 +2095,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
2009 cls_session = iscsi_alloc_session(shost, iscsit, 2095 cls_session = iscsi_alloc_session(shost, iscsit,
2010 sizeof(struct iscsi_session)); 2096 sizeof(struct iscsi_session));
2011 if (!cls_session) 2097 if (!cls_session)
2012 return NULL; 2098 goto dec_session_count;
2013 session = cls_session->dd_data; 2099 session = cls_session->dd_data;
2014 session->cls_session = cls_session; 2100 session->cls_session = cls_session;
2015 session->host = shost; 2101 session->host = shost;
@@ -2048,6 +2134,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
2048 2134
2049 if (iscsi_add_session(cls_session, id)) 2135 if (iscsi_add_session(cls_session, id))
2050 goto cls_session_fail; 2136 goto cls_session_fail;
2137
2051 return cls_session; 2138 return cls_session;
2052 2139
2053cls_session_fail: 2140cls_session_fail:
@@ -2056,6 +2143,8 @@ module_get_fail:
2056 iscsi_pool_free(&session->cmdpool); 2143 iscsi_pool_free(&session->cmdpool);
2057cmdpool_alloc_fail: 2144cmdpool_alloc_fail:
2058 iscsi_free_session(cls_session); 2145 iscsi_free_session(cls_session);
2146dec_session_count:
2147 iscsi_host_dec_session_cnt(shost);
2059 return NULL; 2148 return NULL;
2060} 2149}
2061EXPORT_SYMBOL_GPL(iscsi_session_setup); 2150EXPORT_SYMBOL_GPL(iscsi_session_setup);
@@ -2071,6 +2160,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
2071{ 2160{
2072 struct iscsi_session *session = cls_session->dd_data; 2161 struct iscsi_session *session = cls_session->dd_data;
2073 struct module *owner = cls_session->transport->owner; 2162 struct module *owner = cls_session->transport->owner;
2163 struct Scsi_Host *shost = session->host;
2074 2164
2075 iscsi_pool_free(&session->cmdpool); 2165 iscsi_pool_free(&session->cmdpool);
2076 2166
@@ -2083,6 +2173,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
2083 kfree(session->ifacename); 2173 kfree(session->ifacename);
2084 2174
2085 iscsi_destroy_session(cls_session); 2175 iscsi_destroy_session(cls_session);
2176 iscsi_host_dec_session_cnt(shost);
2086 module_put(owner); 2177 module_put(owner);
2087} 2178}
2088EXPORT_SYMBOL_GPL(iscsi_session_teardown); 2179EXPORT_SYMBOL_GPL(iscsi_session_teardown);
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 4255b36ff968..db7ea3bb4e83 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -353,7 +353,7 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
353 ha->host_no, ddb_entry->bus, ddb_entry->target, 353 ha->host_no, ddb_entry->bus, ddb_entry->target,
354 ddb_entry->fw_ddb_index)); 354 ddb_entry->fw_ddb_index));
355 iscsi_block_session(ddb_entry->sess); 355 iscsi_block_session(ddb_entry->sess);
356 iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED); 356 iscsi_conn_error_event(ddb_entry->conn, ISCSI_ERR_CONN_FAILED);
357} 357}
358 358
359static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, 359static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index cbaae48f47ed..f9e45f83e467 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1010,7 +1010,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
1010 1010
1011 skb = alloc_skb(len, GFP_ATOMIC); 1011 skb = alloc_skb(len, GFP_ATOMIC);
1012 if (!skb) { 1012 if (!skb) {
1013 iscsi_conn_error(conn, ISCSI_ERR_CONN_FAILED); 1013 iscsi_conn_error_event(conn, ISCSI_ERR_CONN_FAILED);
1014 iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver " 1014 iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver "
1015 "control PDU: OOM\n"); 1015 "control PDU: OOM\n");
1016 return -ENOMEM; 1016 return -ENOMEM;
@@ -1031,7 +1031,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
1031} 1031}
1032EXPORT_SYMBOL_GPL(iscsi_recv_pdu); 1032EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
1033 1033
1034void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) 1034void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
1035{ 1035{
1036 struct nlmsghdr *nlh; 1036 struct nlmsghdr *nlh;
1037 struct sk_buff *skb; 1037 struct sk_buff *skb;
@@ -1063,7 +1063,7 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error)
1063 iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n", 1063 iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n",
1064 error); 1064 error);
1065} 1065}
1066EXPORT_SYMBOL_GPL(iscsi_conn_error); 1066EXPORT_SYMBOL_GPL(iscsi_conn_error_event);
1067 1067
1068static int 1068static int
1069iscsi_if_send_reply(int pid, int seq, int type, int done, int multi, 1069iscsi_if_send_reply(int pid, int seq, int type, int done, int multi,
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 16be12f1cbe8..f274d248a91f 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -213,6 +213,7 @@ enum iscsi_err {
213 ISCSI_ERR_DATA_DGST = ISCSI_ERR_BASE + 15, 213 ISCSI_ERR_DATA_DGST = ISCSI_ERR_BASE + 15,
214 ISCSI_ERR_PARAM_NOT_FOUND = ISCSI_ERR_BASE + 16, 214 ISCSI_ERR_PARAM_NOT_FOUND = ISCSI_ERR_BASE + 16,
215 ISCSI_ERR_NO_SCSI_CMD = ISCSI_ERR_BASE + 17, 215 ISCSI_ERR_NO_SCSI_CMD = ISCSI_ERR_BASE + 17,
216 ISCSI_ERR_INVALID_HOST = ISCSI_ERR_BASE + 18,
216}; 217};
217 218
218/* 219/*
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 5e75bb7f311c..7d8cd159f592 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -287,6 +287,11 @@ struct iscsi_session {
287 struct iscsi_pool cmdpool; /* PDU's pool */ 287 struct iscsi_pool cmdpool; /* PDU's pool */
288}; 288};
289 289
290enum {
291 ISCSI_HOST_SETUP,
292 ISCSI_HOST_REMOVED,
293};
294
290struct iscsi_host { 295struct iscsi_host {
291 char *initiatorname; 296 char *initiatorname;
292 /* hw address or netdev iscsi connection is bound to */ 297 /* hw address or netdev iscsi connection is bound to */
@@ -295,6 +300,12 @@ struct iscsi_host {
295 /* local address */ 300 /* local address */
296 int local_port; 301 int local_port;
297 char local_address[ISCSI_ADDRESS_BUF_LEN]; 302 char local_address[ISCSI_ADDRESS_BUF_LEN];
303
304 wait_queue_head_t session_removal_wq;
305 /* protects sessions and state */
306 spinlock_t lock;
307 int num_sessions;
308 int state;
298}; 309};
299 310
300/* 311/*
@@ -351,6 +362,8 @@ extern void iscsi_conn_stop(struct iscsi_cls_conn *, int);
351extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *, 362extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *,
352 int); 363 int);
353extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err); 364extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err);
365extern void iscsi_session_failure(struct iscsi_cls_session *cls_session,
366 enum iscsi_err err);
354extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, 367extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
355 enum iscsi_param param, char *buf); 368 enum iscsi_param param, char *buf);
356extern void iscsi_suspend_tx(struct iscsi_conn *conn); 369extern void iscsi_suspend_tx(struct iscsi_conn *conn);
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 8b6c91df4c7a..8749d4d8e244 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -135,7 +135,8 @@ extern int iscsi_unregister_transport(struct iscsi_transport *tt);
135/* 135/*
136 * control plane upcalls 136 * control plane upcalls
137 */ 137 */
138extern void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error); 138extern void iscsi_conn_error_event(struct iscsi_cls_conn *conn,
139 enum iscsi_err error);
139extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, 140extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
140 char *data, uint32_t data_size); 141 char *data, uint32_t data_size);
141 142