aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2008-09-24 12:46:10 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-10-13 09:28:59 -0400
commite5bd7b54e93ef7151469a12b8c28d863b9f8a088 (patch)
treeb1e63758dc0272346b7d5e9af6435a87fd94a7ad
parent1d9edf0270cb5a434d32e95279ce9493581906b3 (diff)
[SCSI] libiscsi: Support drivers initiating session removal
If the driver knows when hardware is removed like with cxgb3i, bnx2i, qla4xxx and iser then we will want to remove the sessions/devices that are bound to that device before removing the host. cxgb3i and in the future bnx2i will remove the host and that will remove all the sessions on the hba. iser can call iscsi_kill_session when it gets an event that indicates that a hca is removed. And when qla4xxx is hooked in to the lib (it is only hooked into the class right now) it can call iscsi remove host like the partial offload card drivers. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-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