aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2008-01-31 14:36:43 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-02-07 19:02:34 -0500
commit6eabafbe6616266e8de61980a7dac5ecc1ba1113 (patch)
treef5533027fac576acf4db08210ea5815db3a15e50 /drivers/scsi
parent84ac86ca8c6787f9efff28bc04b1b65fe0a5c310 (diff)
[SCSI] iscsi class, libiscsi: add iscsi sysfs session state file
This adds a iscsi session state file which exports the session state for both software and hardware iscsi. It also hooks libiscsi in. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/libiscsi.c41
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c107
2 files changed, 130 insertions, 18 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index e7942628ac4a..c8c00e173414 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -996,6 +996,7 @@ enum {
996 FAILURE_SESSION_IN_RECOVERY, 996 FAILURE_SESSION_IN_RECOVERY,
997 FAILURE_SESSION_RECOVERY_TIMEOUT, 997 FAILURE_SESSION_RECOVERY_TIMEOUT,
998 FAILURE_SESSION_LOGGING_OUT, 998 FAILURE_SESSION_LOGGING_OUT,
999 FAILURE_SESSION_NOT_READY,
999}; 1000};
1000 1001
1001int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) 1002int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
@@ -1016,6 +1017,12 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
1016 session = iscsi_hostdata(host->hostdata); 1017 session = iscsi_hostdata(host->hostdata);
1017 spin_lock(&session->lock); 1018 spin_lock(&session->lock);
1018 1019
1020 reason = iscsi_session_chkready(session_to_cls(session));
1021 if (reason) {
1022 sc->result = reason;
1023 goto fault;
1024 }
1025
1019 /* 1026 /*
1020 * ISCSI_STATE_FAILED is a temp. state. The recovery 1027 * ISCSI_STATE_FAILED is a temp. state. The recovery
1021 * code will decide what is best to do with command queued 1028 * code will decide what is best to do with command queued
@@ -1032,18 +1039,23 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
1032 switch (session->state) { 1039 switch (session->state) {
1033 case ISCSI_STATE_IN_RECOVERY: 1040 case ISCSI_STATE_IN_RECOVERY:
1034 reason = FAILURE_SESSION_IN_RECOVERY; 1041 reason = FAILURE_SESSION_IN_RECOVERY;
1035 goto reject; 1042 sc->result = DID_IMM_RETRY << 16;
1043 break;
1036 case ISCSI_STATE_LOGGING_OUT: 1044 case ISCSI_STATE_LOGGING_OUT:
1037 reason = FAILURE_SESSION_LOGGING_OUT; 1045 reason = FAILURE_SESSION_LOGGING_OUT;
1038 goto reject; 1046 sc->result = DID_IMM_RETRY << 16;
1047 break;
1039 case ISCSI_STATE_RECOVERY_FAILED: 1048 case ISCSI_STATE_RECOVERY_FAILED:
1040 reason = FAILURE_SESSION_RECOVERY_TIMEOUT; 1049 reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
1050 sc->result = DID_NO_CONNECT << 16;
1041 break; 1051 break;
1042 case ISCSI_STATE_TERMINATE: 1052 case ISCSI_STATE_TERMINATE:
1043 reason = FAILURE_SESSION_TERMINATE; 1053 reason = FAILURE_SESSION_TERMINATE;
1054 sc->result = DID_NO_CONNECT << 16;
1044 break; 1055 break;
1045 default: 1056 default:
1046 reason = FAILURE_SESSION_FREED; 1057 reason = FAILURE_SESSION_FREED;
1058 sc->result = DID_NO_CONNECT << 16;
1047 } 1059 }
1048 goto fault; 1060 goto fault;
1049 } 1061 }
@@ -1051,6 +1063,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
1051 conn = session->leadconn; 1063 conn = session->leadconn;
1052 if (!conn) { 1064 if (!conn) {
1053 reason = FAILURE_SESSION_FREED; 1065 reason = FAILURE_SESSION_FREED;
1066 sc->result = DID_NO_CONNECT << 16;
1054 goto fault; 1067 goto fault;
1055 } 1068 }
1056 1069
@@ -1090,9 +1103,7 @@ reject:
1090 1103
1091fault: 1104fault:
1092 spin_unlock(&session->lock); 1105 spin_unlock(&session->lock);
1093 printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", 1106 debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
1094 sc->cmnd[0], reason);
1095 sc->result = (DID_NO_CONNECT << 16);
1096 scsi_set_resid(sc, scsi_bufflen(sc)); 1107 scsi_set_resid(sc, scsi_bufflen(sc));
1097 sc->scsi_done(sc); 1108 sc->scsi_done(sc);
1098 spin_lock(host->host_lock); 1109 spin_lock(host->host_lock);
@@ -1238,7 +1249,8 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
1238 * Fail commands. session lock held and recv side suspended and xmit 1249 * Fail commands. session lock held and recv side suspended and xmit
1239 * thread flushed 1250 * thread flushed
1240 */ 1251 */
1241static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) 1252static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
1253 int error)
1242{ 1254{
1243 struct iscsi_cmd_task *ctask, *tmp; 1255 struct iscsi_cmd_task *ctask, *tmp;
1244 1256
@@ -1250,7 +1262,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)
1250 if (lun == ctask->sc->device->lun || lun == -1) { 1262 if (lun == ctask->sc->device->lun || lun == -1) {
1251 debug_scsi("failing pending sc %p itt 0x%x\n", 1263 debug_scsi("failing pending sc %p itt 0x%x\n",
1252 ctask->sc, ctask->itt); 1264 ctask->sc, ctask->itt);
1253 fail_command(conn, ctask, DID_BUS_BUSY << 16); 1265 fail_command(conn, ctask, error << 16);
1254 } 1266 }
1255 } 1267 }
1256 1268
@@ -1258,7 +1270,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)
1258 if (lun == ctask->sc->device->lun || lun == -1) { 1270 if (lun == ctask->sc->device->lun || lun == -1) {
1259 debug_scsi("failing requeued sc %p itt 0x%x\n", 1271 debug_scsi("failing requeued sc %p itt 0x%x\n",
1260 ctask->sc, ctask->itt); 1272 ctask->sc, ctask->itt);
1261 fail_command(conn, ctask, DID_BUS_BUSY << 16); 1273 fail_command(conn, ctask, error << 16);
1262 } 1274 }
1263 } 1275 }
1264 1276
@@ -1572,7 +1584,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
1572 /* need to grab the recv lock then session lock */ 1584 /* need to grab the recv lock then session lock */
1573 write_lock_bh(conn->recv_lock); 1585 write_lock_bh(conn->recv_lock);
1574 spin_lock(&session->lock); 1586 spin_lock(&session->lock);
1575 fail_all_commands(conn, sc->device->lun); 1587 fail_all_commands(conn, sc->device->lun, DID_ERROR);
1576 conn->tmf_state = TMF_INITIAL; 1588 conn->tmf_state = TMF_INITIAL;
1577 spin_unlock(&session->lock); 1589 spin_unlock(&session->lock);
1578 write_unlock_bh(conn->recv_lock); 1590 write_unlock_bh(conn->recv_lock);
@@ -2018,11 +2030,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
2018 conn->stop_stage = 0; 2030 conn->stop_stage = 0;
2019 conn->tmf_state = TMF_INITIAL; 2031 conn->tmf_state = TMF_INITIAL;
2020 session->age++; 2032 session->age++;
2021 spin_unlock_bh(&session->lock); 2033 break;
2022
2023 iscsi_unblock_session(session_to_cls(session));
2024 wake_up(&conn->ehwait);
2025 return 0;
2026 case STOP_CONN_TERM: 2034 case STOP_CONN_TERM:
2027 conn->stop_stage = 0; 2035 conn->stop_stage = 0;
2028 break; 2036 break;
@@ -2031,6 +2039,8 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
2031 } 2039 }
2032 spin_unlock_bh(&session->lock); 2040 spin_unlock_bh(&session->lock);
2033 2041
2042 iscsi_unblock_session(session_to_cls(session));
2043 wake_up(&conn->ehwait);
2034 return 0; 2044 return 0;
2035} 2045}
2036EXPORT_SYMBOL_GPL(iscsi_conn_start); 2046EXPORT_SYMBOL_GPL(iscsi_conn_start);
@@ -2122,7 +2132,8 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
2122 * flush queues. 2132 * flush queues.
2123 */ 2133 */
2124 spin_lock_bh(&session->lock); 2134 spin_lock_bh(&session->lock);
2125 fail_all_commands(conn, -1); 2135 fail_all_commands(conn, -1,
2136 STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR);
2126 flush_control_queues(session, conn); 2137 flush_control_queues(session, conn);
2127 spin_unlock_bh(&session->lock); 2138 spin_unlock_bh(&session->lock);
2128 mutex_unlock(&session->eh_mutex); 2139 mutex_unlock(&session->eh_mutex);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 0d7b4e79415c..f876b0ae521a 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -30,7 +30,7 @@
30#include <scsi/scsi_transport_iscsi.h> 30#include <scsi/scsi_transport_iscsi.h>
31#include <scsi/iscsi_if.h> 31#include <scsi/iscsi_if.h>
32 32
33#define ISCSI_SESSION_ATTRS 18 33#define ISCSI_SESSION_ATTRS 19
34#define ISCSI_CONN_ATTRS 11 34#define ISCSI_CONN_ATTRS 11
35#define ISCSI_HOST_ATTRS 4 35#define ISCSI_HOST_ATTRS 4
36#define ISCSI_TRANSPORT_VERSION "2.0-867" 36#define ISCSI_TRANSPORT_VERSION "2.0-867"
@@ -221,6 +221,54 @@ static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid)
221 * The following functions can be used by LLDs that allocate 221 * The following functions can be used by LLDs that allocate
222 * their own scsi_hosts or by software iscsi LLDs 222 * their own scsi_hosts or by software iscsi LLDs
223 */ 223 */
224static struct {
225 int value;
226 char *name;
227} iscsi_session_state_names[] = {
228 { ISCSI_SESSION_LOGGED_IN, "LOGGED_IN" },
229 { ISCSI_SESSION_FAILED, "FAILED" },
230 { ISCSI_SESSION_FREE, "FREE" },
231};
232
233const char *iscsi_session_state_name(int state)
234{
235 int i;
236 char *name = NULL;
237
238 for (i = 0; i < ARRAY_SIZE(iscsi_session_state_names); i++) {
239 if (iscsi_session_state_names[i].value == state) {
240 name = iscsi_session_state_names[i].name;
241 break;
242 }
243 }
244 return name;
245}
246
247int iscsi_session_chkready(struct iscsi_cls_session *session)
248{
249 unsigned long flags;
250 int err;
251
252 spin_lock_irqsave(&session->lock, flags);
253 switch (session->state) {
254 case ISCSI_SESSION_LOGGED_IN:
255 err = 0;
256 break;
257 case ISCSI_SESSION_FAILED:
258 err = DID_IMM_RETRY << 16;
259 break;
260 case ISCSI_SESSION_FREE:
261 err = DID_NO_CONNECT << 16;
262 break;
263 default:
264 err = DID_NO_CONNECT << 16;
265 break;
266 }
267 spin_unlock_irqrestore(&session->lock, flags);
268 return err;
269}
270EXPORT_SYMBOL_GPL(iscsi_session_chkready);
271
224static void iscsi_session_release(struct device *dev) 272static void iscsi_session_release(struct device *dev)
225{ 273{
226 struct iscsi_cls_session *session = iscsi_dev_to_session(dev); 274 struct iscsi_cls_session *session = iscsi_dev_to_session(dev);
@@ -259,26 +307,57 @@ static void session_recovery_timedout(struct work_struct *work)
259 struct iscsi_cls_session *session = 307 struct iscsi_cls_session *session =
260 container_of(work, struct iscsi_cls_session, 308 container_of(work, struct iscsi_cls_session,
261 recovery_work.work); 309 recovery_work.work);
310 unsigned long flags;
262 311
263 dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed " 312 dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed "
264 "out after %d secs\n", session->recovery_tmo); 313 "out after %d secs\n", session->recovery_tmo);
265 314
315 spin_lock_irqsave(&session->lock, flags);
316 switch (session->state) {
317 case ISCSI_SESSION_FAILED:
318 session->state = ISCSI_SESSION_FREE;
319 break;
320 case ISCSI_SESSION_LOGGED_IN:
321 case ISCSI_SESSION_FREE:
322 /* we raced with the unblock's flush */
323 spin_unlock_irqrestore(&session->lock, flags);
324 return;
325 }
326 spin_unlock_irqrestore(&session->lock, flags);
327
266 if (session->transport->session_recovery_timedout) 328 if (session->transport->session_recovery_timedout)
267 session->transport->session_recovery_timedout(session); 329 session->transport->session_recovery_timedout(session);
268 330
269 scsi_target_unblock(&session->dev); 331 scsi_target_unblock(&session->dev);
270} 332}
271 333
272void iscsi_unblock_session(struct iscsi_cls_session *session) 334void __iscsi_unblock_session(struct iscsi_cls_session *session)
273{ 335{
274 if (!cancel_delayed_work(&session->recovery_work)) 336 if (!cancel_delayed_work(&session->recovery_work))
275 flush_workqueue(iscsi_eh_timer_workq); 337 flush_workqueue(iscsi_eh_timer_workq);
276 scsi_target_unblock(&session->dev); 338 scsi_target_unblock(&session->dev);
277} 339}
340
341void iscsi_unblock_session(struct iscsi_cls_session *session)
342{
343 unsigned long flags;
344
345 spin_lock_irqsave(&session->lock, flags);
346 session->state = ISCSI_SESSION_LOGGED_IN;
347 spin_unlock_irqrestore(&session->lock, flags);
348
349 __iscsi_unblock_session(session);
350}
278EXPORT_SYMBOL_GPL(iscsi_unblock_session); 351EXPORT_SYMBOL_GPL(iscsi_unblock_session);
279 352
280void iscsi_block_session(struct iscsi_cls_session *session) 353void iscsi_block_session(struct iscsi_cls_session *session)
281{ 354{
355 unsigned long flags;
356
357 spin_lock_irqsave(&session->lock, flags);
358 session->state = ISCSI_SESSION_FAILED;
359 spin_unlock_irqrestore(&session->lock, flags);
360
282 scsi_target_block(&session->dev); 361 scsi_target_block(&session->dev);
283 queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work, 362 queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work,
284 session->recovery_tmo * HZ); 363 session->recovery_tmo * HZ);
@@ -327,10 +406,12 @@ iscsi_alloc_session(struct Scsi_Host *shost,
327 406
328 session->transport = transport; 407 session->transport = transport;
329 session->recovery_tmo = 120; 408 session->recovery_tmo = 120;
409 session->state = ISCSI_SESSION_FREE;
330 INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); 410 INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
331 INIT_LIST_HEAD(&session->host_list); 411 INIT_LIST_HEAD(&session->host_list);
332 INIT_LIST_HEAD(&session->sess_list); 412 INIT_LIST_HEAD(&session->sess_list);
333 INIT_WORK(&session->unbind_work, __iscsi_unbind_session); 413 INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
414 spin_lock_init(&session->lock);
334 415
335 /* this is released in the dev's release function */ 416 /* this is released in the dev's release function */
336 scsi_host_get(shost); 417 scsi_host_get(shost);
@@ -444,7 +525,10 @@ void iscsi_remove_session(struct iscsi_cls_session *session)
444 * If we are blocked let commands flow again. The lld or iscsi 525 * If we are blocked let commands flow again. The lld or iscsi
445 * layer should set up the queuecommand to fail commands. 526 * layer should set up the queuecommand to fail commands.
446 */ 527 */
447 iscsi_unblock_session(session); 528 spin_lock_irqsave(&session->lock, flags);
529 session->state = ISCSI_SESSION_FREE;
530 spin_unlock_irqrestore(&session->lock, flags);
531 __iscsi_unblock_session(session);
448 iscsi_unbind_session(session); 532 iscsi_unbind_session(session);
449 /* 533 /*
450 * If the session dropped while removing devices then we need to make 534 * If the session dropped while removing devices then we need to make
@@ -661,16 +745,23 @@ EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
661 745
662void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) 746void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error)
663{ 747{
748 struct iscsi_cls_session *session = iscsi_conn_to_session(conn);
664 struct nlmsghdr *nlh; 749 struct nlmsghdr *nlh;
665 struct sk_buff *skb; 750 struct sk_buff *skb;
666 struct iscsi_uevent *ev; 751 struct iscsi_uevent *ev;
667 struct iscsi_internal *priv; 752 struct iscsi_internal *priv;
668 int len = NLMSG_SPACE(sizeof(*ev)); 753 int len = NLMSG_SPACE(sizeof(*ev));
754 unsigned long flags;
669 755
670 priv = iscsi_if_transport_lookup(conn->transport); 756 priv = iscsi_if_transport_lookup(conn->transport);
671 if (!priv) 757 if (!priv)
672 return; 758 return;
673 759
760 spin_lock_irqsave(&session->lock, flags);
761 if (session->state == ISCSI_SESSION_LOGGED_IN)
762 session->state = ISCSI_SESSION_FAILED;
763 spin_unlock_irqrestore(&session->lock, flags);
764
674 skb = alloc_skb(len, GFP_ATOMIC); 765 skb = alloc_skb(len, GFP_ATOMIC);
675 if (!skb) { 766 if (!skb) {
676 dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored " 767 dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored "
@@ -1246,6 +1337,15 @@ iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
1246iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); 1337iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
1247iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); 1338iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
1248 1339
1340static ssize_t
1341show_priv_session_state(struct class_device *cdev, char *buf)
1342{
1343 struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);
1344 return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
1345}
1346static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
1347 NULL);
1348
1249#define iscsi_priv_session_attr_show(field, format) \ 1349#define iscsi_priv_session_attr_show(field, format) \
1250static ssize_t \ 1350static ssize_t \
1251show_priv_session_##field(struct class_device *cdev, char *buf) \ 1351show_priv_session_##field(struct class_device *cdev, char *buf) \
@@ -1472,6 +1572,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
1472 SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); 1572 SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO);
1473 SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); 1573 SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO);
1474 SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); 1574 SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
1575 SETUP_PRIV_SESSION_RD_ATTR(state);
1475 1576
1476 BUG_ON(count > ISCSI_SESSION_ATTRS); 1577 BUG_ON(count > ISCSI_SESSION_ATTRS);
1477 priv->session_attrs[count] = NULL; 1578 priv->session_attrs[count] = NULL;