aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/iscsi_tcp.c659
-rw-r--r--drivers/scsi/iscsi_tcp.h3
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c152
-rw-r--r--include/scsi/iscsi_if.h2
-rw-r--r--include/scsi/scsi_transport_iscsi.h19
5 files changed, 561 insertions, 274 deletions
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 6e510f3cfbf6..aca3e23b1b9e 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -82,6 +82,9 @@ module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
82/* global data */ 82/* global data */
83static kmem_cache_t *taskcache; 83static kmem_cache_t *taskcache;
84 84
85#define session_to_cls(_sess) \
86 hostdata_session(_sess->host->hostdata)
87
85static inline void 88static inline void
86iscsi_buf_init_virt(struct iscsi_buf *ibuf, char *vbuf, int size) 89iscsi_buf_init_virt(struct iscsi_buf *ibuf, char *vbuf, int size)
87{ 90{
@@ -230,17 +233,19 @@ iscsi_hdr_extract(struct iscsi_conn *conn)
230 return 0; 233 return 0;
231} 234}
232 235
233static inline void 236/*
234iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) 237 * must be called with session lock
238 */
239static void
240__iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
235{ 241{
236 struct scsi_cmnd *sc = ctask->sc;
237 struct iscsi_session *session = conn->session; 242 struct iscsi_session *session = conn->session;
243 struct scsi_cmnd *sc;
238 244
239 spin_lock(&session->lock); 245 sc = ctask->sc;
240 if (unlikely(!sc)) { 246 if (unlikely(!sc))
241 spin_unlock(&session->lock);
242 return; 247 return;
243 } 248
244 if (sc->sc_data_direction == DMA_TO_DEVICE) { 249 if (sc->sc_data_direction == DMA_TO_DEVICE) {
245 struct iscsi_data_task *dtask, *n; 250 struct iscsi_data_task *dtask, *n;
246 /* WRITE: cleanup Data-Out's if any */ 251 /* WRITE: cleanup Data-Out's if any */
@@ -252,7 +257,20 @@ iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
252 ctask->xmstate = XMSTATE_IDLE; 257 ctask->xmstate = XMSTATE_IDLE;
253 ctask->r2t = NULL; 258 ctask->r2t = NULL;
254 ctask->sc = NULL; 259 ctask->sc = NULL;
260 list_del(&ctask->running);
261
255 __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); 262 __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
263
264 sc->scsi_done(sc);
265}
266
267static void
268iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
269{
270 struct iscsi_session *session = conn->session;
271
272 spin_lock(&session->lock);
273 __iscsi_ctask_cleanup(conn, ctask);
256 spin_unlock(&session->lock); 274 spin_unlock(&session->lock);
257} 275}
258 276
@@ -311,7 +329,6 @@ out:
311 (long)sc, sc->result, ctask->itt); 329 (long)sc, sc->result, ctask->itt);
312 conn->scsirsp_pdus_cnt++; 330 conn->scsirsp_pdus_cnt++;
313 iscsi_ctask_cleanup(conn, ctask); 331 iscsi_ctask_cleanup(conn, ctask);
314 sc->scsi_done(sc);
315 return rc; 332 return rc;
316} 333}
317 334
@@ -395,6 +412,7 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
395 412
396 dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC); 413 dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC);
397 BUG_ON(!dtask); 414 BUG_ON(!dtask);
415 INIT_LIST_HEAD(&dtask->item);
398 hdr = &dtask->hdr; 416 hdr = &dtask->hdr;
399 memset(hdr, 0, sizeof(struct iscsi_data)); 417 memset(hdr, 0, sizeof(struct iscsi_data));
400 hdr->ttt = r2t->ttt; 418 hdr->ttt = r2t->ttt;
@@ -710,8 +728,6 @@ iscsi_hdr_recv(struct iscsi_conn *conn)
710 conn->tmfrsp_pdus_cnt++; 728 conn->tmfrsp_pdus_cnt++;
711 spin_lock(&session->lock); 729 spin_lock(&session->lock);
712 if (conn->tmabort_state == TMABORT_INITIAL) { 730 if (conn->tmabort_state == TMABORT_INITIAL) {
713 __kfifo_put(session->mgmtpool.queue,
714 (void*)&mtask, sizeof(void*));
715 conn->tmabort_state = 731 conn->tmabort_state =
716 ((struct iscsi_tm_rsp *)hdr)-> 732 ((struct iscsi_tm_rsp *)hdr)->
717 response == ISCSI_TMF_RSP_COMPLETE ? 733 response == ISCSI_TMF_RSP_COMPLETE ?
@@ -986,7 +1002,6 @@ done:
986 (long)sc, sc->result, ctask->itt); 1002 (long)sc, sc->result, ctask->itt);
987 conn->scsirsp_pdus_cnt++; 1003 conn->scsirsp_pdus_cnt++;
988 iscsi_ctask_cleanup(conn, ctask); 1004 iscsi_ctask_cleanup(conn, ctask);
989 sc->scsi_done(sc);
990 } 1005 }
991 1006
992 return rc; 1007 return rc;
@@ -1460,6 +1475,7 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
1460 1475
1461 dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC); 1476 dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC);
1462 BUG_ON(!dtask); 1477 BUG_ON(!dtask);
1478 INIT_LIST_HEAD(&dtask->item);
1463 hdr = &dtask->hdr; 1479 hdr = &dtask->hdr;
1464 memset(hdr, 0, sizeof(struct iscsi_data)); 1480 memset(hdr, 0, sizeof(struct iscsi_data));
1465 hdr->ttt = r2t->ttt; 1481 hdr->ttt = r2t->ttt;
@@ -1506,6 +1522,7 @@ iscsi_unsolicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
1506 1522
1507 dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC); 1523 dtask = mempool_alloc(ctask->datapool, GFP_ATOMIC);
1508 BUG_ON(!dtask); 1524 BUG_ON(!dtask);
1525 INIT_LIST_HEAD(&dtask->item);
1509 hdr = &dtask->hdr; 1526 hdr = &dtask->hdr;
1510 memset(hdr, 0, sizeof(struct iscsi_data)); 1527 memset(hdr, 0, sizeof(struct iscsi_data));
1511 hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); 1528 hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
@@ -1550,6 +1567,7 @@ iscsi_cmd_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
1550 1567
1551 BUG_ON(__kfifo_len(ctask->r2tqueue)); 1568 BUG_ON(__kfifo_len(ctask->r2tqueue));
1552 1569
1570 INIT_LIST_HEAD(&ctask->running);
1553 ctask->sc = sc; 1571 ctask->sc = sc;
1554 ctask->conn = conn; 1572 ctask->conn = conn;
1555 ctask->hdr.opcode = ISCSI_OP_SCSI_CMD; 1573 ctask->hdr.opcode = ISCSI_OP_SCSI_CMD;
@@ -1680,7 +1698,7 @@ iscsi_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
1680 if (mtask->data_count) 1698 if (mtask->data_count)
1681 mtask->xmstate |= XMSTATE_IMM_DATA; 1699 mtask->xmstate |= XMSTATE_IMM_DATA;
1682 if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE && 1700 if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE &&
1683 conn->stop_stage != STOP_CONN_RECOVER && 1701 conn->stop_stage != STOP_CONN_RECOVER &&
1684 conn->hdrdgst_en) 1702 conn->hdrdgst_en)
1685 iscsi_hdr_digest(conn, &mtask->headbuf, 1703 iscsi_hdr_digest(conn, &mtask->headbuf,
1686 (u8*)mtask->hdrext); 1704 (u8*)mtask->hdrext);
@@ -2226,6 +2244,7 @@ iscsi_data_xmit(struct iscsi_conn *conn)
2226 /* process command queue */ 2244 /* process command queue */
2227 while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask, 2245 while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask,
2228 sizeof(void*))) { 2246 sizeof(void*))) {
2247 list_add_tail(&conn->ctask->running, &conn->run_list);
2229 if (iscsi_ctask_xmit(conn, conn->ctask)) 2248 if (iscsi_ctask_xmit(conn, conn->ctask))
2230 goto again; 2249 goto again;
2231 } 2250 }
@@ -2277,11 +2296,14 @@ iscsi_xmitworker(void *data)
2277 mutex_unlock(&conn->xmitmutex); 2296 mutex_unlock(&conn->xmitmutex);
2278} 2297}
2279 2298
2280#define FAILURE_BAD_HOST 1 2299enum {
2281#define FAILURE_SESSION_FAILED 2 2300 FAILURE_BAD_HOST = 1,
2282#define FAILURE_SESSION_FREED 3 2301 FAILURE_SESSION_FAILED,
2283#define FAILURE_WINDOW_CLOSED 4 2302 FAILURE_SESSION_FREED,
2284#define FAILURE_SESSION_TERMINATE 5 2303 FAILURE_WINDOW_CLOSED,
2304 FAILURE_SESSION_TERMINATE,
2305 FAILURE_SESSION_RECOVERY_TIMEOUT,
2306};
2285 2307
2286static int 2308static int
2287iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) 2309iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
@@ -2297,12 +2319,14 @@ iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
2297 2319
2298 host = sc->device->host; 2320 host = sc->device->host;
2299 session = iscsi_hostdata(host->hostdata); 2321 session = iscsi_hostdata(host->hostdata);
2300 BUG_ON(host != session->host);
2301 2322
2302 spin_lock(&session->lock); 2323 spin_lock(&session->lock);
2303 2324
2304 if (session->state != ISCSI_STATE_LOGGED_IN) { 2325 if (session->state != ISCSI_STATE_LOGGED_IN) {
2305 if (session->state == ISCSI_STATE_FAILED) { 2326 if (session->recovery_failed) {
2327 reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
2328 goto fault;
2329 } else if (session->state == ISCSI_STATE_FAILED) {
2306 reason = FAILURE_SESSION_FAILED; 2330 reason = FAILURE_SESSION_FAILED;
2307 goto reject; 2331 goto reject;
2308 } else if (session->state == ISCSI_STATE_TERMINATE) { 2332 } else if (session->state == ISCSI_STATE_TERMINATE) {
@@ -2350,11 +2374,6 @@ fault:
2350 spin_unlock(&session->lock); 2374 spin_unlock(&session->lock);
2351 printk(KERN_ERR "iscsi_tcp: cmd 0x%x is not queued (%d)\n", 2375 printk(KERN_ERR "iscsi_tcp: cmd 0x%x is not queued (%d)\n",
2352 sc->cmnd[0], reason); 2376 sc->cmnd[0], reason);
2353 sc->sense_buffer[0] = 0x70;
2354 sc->sense_buffer[2] = NOT_READY;
2355 sc->sense_buffer[7] = 0x6;
2356 sc->sense_buffer[12] = 0x08;
2357 sc->sense_buffer[13] = 0x00;
2358 sc->result = (DID_NO_CONNECT << 16); 2377 sc->result = (DID_NO_CONNECT << 16);
2359 sc->resid = sc->request_bufflen; 2378 sc->resid = sc->request_bufflen;
2360 sc->scsi_done(sc); 2379 sc->scsi_done(sc);
@@ -2445,6 +2464,7 @@ iscsi_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
2445 conn->id = conn_idx; 2464 conn->id = conn_idx;
2446 conn->exp_statsn = 0; 2465 conn->exp_statsn = 0;
2447 conn->tmabort_state = TMABORT_INITIAL; 2466 conn->tmabort_state = TMABORT_INITIAL;
2467 INIT_LIST_HEAD(&conn->run_list);
2448 2468
2449 /* initial operational parameters */ 2469 /* initial operational parameters */
2450 conn->hdr_size = sizeof(struct iscsi_hdr); 2470 conn->hdr_size = sizeof(struct iscsi_hdr);
@@ -2701,6 +2721,22 @@ iscsi_conn_bind(struct iscsi_cls_session *cls_session,
2701 return 0; 2721 return 0;
2702} 2722}
2703 2723
2724static void
2725iscsi_session_recovery_timedout(struct iscsi_cls_session *csession)
2726{
2727 struct Scsi_Host *shost = iscsi_session_to_shost(csession);
2728 struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
2729 struct iscsi_conn *conn = session->leadconn;
2730
2731 spin_lock_bh(&session->lock);
2732 if (session->state != ISCSI_STATE_LOGGED_IN) {
2733 session->recovery_failed = 1;
2734 if (conn)
2735 wake_up(&conn->ehwait);
2736 }
2737 spin_unlock_bh(&session->lock);
2738}
2739
2704static int 2740static int
2705iscsi_conn_start(struct iscsi_cls_conn *cls_conn) 2741iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
2706{ 2742{
@@ -2716,7 +2752,6 @@ iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
2716 } 2752 }
2717 2753
2718 sk = conn->sock->sk; 2754 sk = conn->sock->sk;
2719
2720 write_lock_bh(&sk->sk_callback_lock); 2755 write_lock_bh(&sk->sk_callback_lock);
2721 spin_lock_bh(&session->lock); 2756 spin_lock_bh(&session->lock);
2722 conn->c_stage = ISCSI_CONN_STARTED; 2757 conn->c_stage = ISCSI_CONN_STARTED;
@@ -2732,8 +2767,13 @@ iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
2732 conn->stop_stage = 0; 2767 conn->stop_stage = 0;
2733 conn->tmabort_state = TMABORT_INITIAL; 2768 conn->tmabort_state = TMABORT_INITIAL;
2734 session->age++; 2769 session->age++;
2770 session->recovery_failed = 0;
2771 spin_unlock_bh(&session->lock);
2772 write_unlock_bh(&sk->sk_callback_lock);
2773
2774 iscsi_unblock_session(session_to_cls(session));
2735 wake_up(&conn->ehwait); 2775 wake_up(&conn->ehwait);
2736 break; 2776 return 0;
2737 case STOP_CONN_TERM: 2777 case STOP_CONN_TERM:
2738 session->conn_cnt++; 2778 session->conn_cnt++;
2739 conn->stop_stage = 0; 2779 conn->stop_stage = 0;
@@ -2752,105 +2792,199 @@ iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
2752 return 0; 2792 return 0;
2753} 2793}
2754 2794
2755static void 2795static int
2756iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) 2796iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask)
2757{ 2797{
2758 struct iscsi_conn *conn = cls_conn->dd_data; 2798 struct iscsi_conn *conn = ctask->conn;
2759 struct iscsi_session *session = conn->session; 2799 struct iscsi_session *session = conn->session;
2800 struct iscsi_mgmt_task *mtask;
2801
2802 if (!ctask->mtask)
2803 return -EINVAL;
2804
2805 while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*))) {
2806 if (mtask == ctask->mtask)
2807 break;
2808 __kfifo_put(conn->immqueue, (void*)&mtask, sizeof(void*));
2809 }
2810
2811 __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask,
2812 sizeof(void*));
2813 ctask->mtask = NULL;
2814 return 0;
2815}
2816
2817static void
2818fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, int err)
2819{
2820 struct iscsi_r2t_info *r2t;
2821 struct scsi_cmnd *sc;
2822
2823 /* flush ctask's r2t queues */
2824 while (__kfifo_get(ctask->r2tqueue, (void*)&r2t, sizeof(void*)))
2825 __kfifo_put(ctask->r2tpool.queue, (void*)&r2t, sizeof(void*));
2826
2827 iscsi_ctask_mtask_cleanup(ctask);
2828
2829 sc = ctask->sc;
2830 if (!sc)
2831 return;
2832
2833 sc->result = err;
2834 sc->resid = sc->request_bufflen;
2835
2836 __iscsi_ctask_cleanup(conn, ctask);
2837}
2838
2839/* Fail commands. Mutex and session lock held */
2840static void
2841fail_all_commands(struct iscsi_session *session, struct iscsi_conn *conn)
2842{
2843 struct iscsi_cmd_task *ctask, *tmp;
2844
2845 /* flush pending */
2846 while (__kfifo_get(conn->xmitqueue, (void*)&ctask, sizeof(void*))) {
2847 debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc,
2848 ctask->itt);
2849 fail_command(conn, ctask, DID_BUS_BUSY << 16);
2850 }
2851
2852 /* fail running */
2853 list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
2854 debug_scsi("failing in progress sc %p itt 0x%x\n",
2855 ctask->sc, ctask->itt);
2856 fail_command(conn, ctask, DID_BUS_BUSY << 16);
2857 }
2858
2859 conn->ctask = NULL;
2860}
2861
2862static void
2863flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
2864{
2865 struct iscsi_mgmt_task *mtask;
2866
2867 /* TODO: handle running pdus */
2868 while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*)) ||
2869 __kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) {
2870 if (mtask == conn->login_mtask)
2871 continue;
2872 __kfifo_put(session->mgmtpool.queue, (void*)&mtask,
2873 sizeof(void*));
2874 }
2875
2876 if (conn->mtask && conn->mtask != conn->login_mtask)
2877 __kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask,
2878 sizeof(void*));
2879 conn->mtask = NULL;
2880}
2881
2882static void
2883iscsi_suspend_conn_rx(struct iscsi_conn *conn)
2884{
2760 struct sock *sk; 2885 struct sock *sk;
2761 unsigned long flags;
2762 2886
2763 BUG_ON(!conn->sock); 2887 BUG_ON(!conn->sock);
2764 sk = conn->sock->sk; 2888 sk = conn->sock->sk;
2765 write_lock_bh(&sk->sk_callback_lock); 2889 write_lock_bh(&sk->sk_callback_lock);
2766 set_bit(SUSPEND_BIT, &conn->suspend_rx); 2890 set_bit(SUSPEND_BIT, &conn->suspend_rx);
2767 write_unlock_bh(&sk->sk_callback_lock); 2891 write_unlock_bh(&sk->sk_callback_lock);
2892}
2768 2893
2769 mutex_lock(&conn->xmitmutex); 2894static void
2770 2895iscsi_start_session_recovery(struct iscsi_session *session,
2771 spin_lock_irqsave(session->host->host_lock, flags); 2896 struct iscsi_conn *conn, int flag)
2772 spin_lock(&session->lock); 2897{
2898 spin_lock_bh(&session->lock);
2899 if (conn->stop_stage == STOP_CONN_RECOVER ||
2900 conn->stop_stage == STOP_CONN_TERM) {
2901 spin_unlock_bh(&session->lock);
2902 return;
2903 }
2773 conn->stop_stage = flag; 2904 conn->stop_stage = flag;
2905 spin_unlock_bh(&session->lock);
2906
2907 iscsi_suspend_conn_rx(conn);
2908
2909 mutex_lock(&conn->xmitmutex);
2910 spin_lock_bh(&session->lock);
2774 conn->c_stage = ISCSI_CONN_STOPPED; 2911 conn->c_stage = ISCSI_CONN_STOPPED;
2775 set_bit(SUSPEND_BIT, &conn->suspend_tx); 2912 set_bit(SUSPEND_BIT, &conn->suspend_tx);
2776 2913
2777 if (flag != STOP_CONN_SUSPEND) 2914 session->conn_cnt--;
2778 session->conn_cnt--;
2779
2780 if (session->conn_cnt == 0 || session->leadconn == conn) 2915 if (session->conn_cnt == 0 || session->leadconn == conn)
2781 session->state = ISCSI_STATE_FAILED; 2916 session->state = ISCSI_STATE_FAILED;
2782 2917
2783 spin_unlock(&session->lock); 2918 spin_unlock_bh(&session->lock);
2784 spin_unlock_irqrestore(session->host->host_lock, flags);
2785
2786 if (flag == STOP_CONN_TERM || flag == STOP_CONN_RECOVER) {
2787 struct iscsi_cmd_task *ctask;
2788 struct iscsi_mgmt_task *mtask;
2789 2919
2790 /* 2920 /*
2791 * Socket must go now. 2921 * Socket must go now.
2792 */ 2922 */
2793 sock_hold(conn->sock->sk); 2923 sock_hold(conn->sock->sk);
2794 iscsi_conn_restore_callbacks(conn); 2924 iscsi_conn_restore_callbacks(conn);
2795 sock_put(conn->sock->sk); 2925 sock_put(conn->sock->sk);
2796 2926
2797 /* 2927 /*
2798 * flush xmit queues. 2928 * flush queues.
2799 */ 2929 */
2800 spin_lock_bh(&session->lock); 2930 spin_lock_bh(&session->lock);
2801 while (__kfifo_get(conn->writequeue, (void*)&ctask, 2931 fail_all_commands(session, conn);
2802 sizeof(void*)) || 2932 flush_control_queues(session, conn);
2803 __kfifo_get(conn->xmitqueue, (void*)&ctask, 2933 spin_unlock_bh(&session->lock);
2804 sizeof(void*))) {
2805 struct iscsi_r2t_info *r2t;
2806
2807 /*
2808 * flush ctask's r2t queues
2809 */
2810 while (__kfifo_get(ctask->r2tqueue, (void*)&r2t,
2811 sizeof(void*)))
2812 __kfifo_put(ctask->r2tpool.queue, (void*)&r2t,
2813 sizeof(void*));
2814 2934
2815 spin_unlock_bh(&session->lock); 2935 /*
2816 local_bh_disable(); 2936 * release socket only after we stopped data_xmit()
2817 iscsi_ctask_cleanup(conn, ctask); 2937 * activity and flushed all outstandings
2818 local_bh_enable(); 2938 */
2819 spin_lock_bh(&session->lock); 2939 sock_release(conn->sock);
2820 } 2940 conn->sock = NULL;
2821 conn->ctask = NULL;
2822 while (__kfifo_get(conn->immqueue, (void*)&mtask,
2823 sizeof(void*)) ||
2824 __kfifo_get(conn->mgmtqueue, (void*)&mtask,
2825 sizeof(void*))) {
2826 __kfifo_put(session->mgmtpool.queue,
2827 (void*)&mtask, sizeof(void*));
2828 }
2829 conn->mtask = NULL;
2830 spin_unlock_bh(&session->lock);
2831 2941
2832 /* 2942 /*
2833 * release socket only after we stopped data_xmit() 2943 * for connection level recovery we should not calculate
2834 * activity and flushed all outstandings 2944 * header digest. conn->hdr_size used for optimization
2835 */ 2945 * in hdr_extract() and will be re-negotiated at
2836 sock_release(conn->sock); 2946 * set_param() time.
2837 conn->sock = NULL; 2947 */
2948 if (flag == STOP_CONN_RECOVER) {
2949 conn->hdr_size = sizeof(struct iscsi_hdr);
2950 conn->hdrdgst_en = 0;
2951 conn->datadgst_en = 0;
2838 2952
2839 /* 2953 if (session->state == ISCSI_STATE_FAILED)
2840 * for connection level recovery we should not calculate 2954 iscsi_block_session(session_to_cls(session));
2841 * header digest. conn->hdr_size used for optimization
2842 * in hdr_extract() and will be re-negotiated at
2843 * set_param() time.
2844 */
2845 if (flag == STOP_CONN_RECOVER) {
2846 conn->hdr_size = sizeof(struct iscsi_hdr);
2847 conn->hdrdgst_en = 0;
2848 conn->datadgst_en = 0;
2849 }
2850 } 2955 }
2851 mutex_unlock(&conn->xmitmutex); 2956 mutex_unlock(&conn->xmitmutex);
2852} 2957}
2853 2958
2959static void
2960iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
2961{
2962 struct iscsi_conn *conn = cls_conn->dd_data;
2963 struct iscsi_session *session = conn->session;
2964
2965 switch (flag) {
2966 case STOP_CONN_RECOVER:
2967 case STOP_CONN_TERM:
2968 iscsi_start_session_recovery(session, conn, flag);
2969 return;
2970 case STOP_CONN_SUSPEND:
2971 iscsi_suspend_conn_rx(conn);
2972
2973 mutex_lock(&conn->xmitmutex);
2974 spin_lock_bh(&session->lock);
2975
2976 conn->stop_stage = flag;
2977 conn->c_stage = ISCSI_CONN_STOPPED;
2978 set_bit(SUSPEND_BIT, &conn->suspend_tx);
2979
2980 spin_unlock_bh(&session->lock);
2981 mutex_unlock(&conn->xmitmutex);
2982 break;
2983 default:
2984 printk(KERN_ERR "invalid stop flag %d\n", flag);
2985 }
2986}
2987
2854static int 2988static int
2855iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 2989iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
2856 char *data, uint32_t data_size) 2990 char *data, uint32_t data_size)
@@ -2940,23 +3074,54 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
2940static int 3074static int
2941iscsi_eh_host_reset(struct scsi_cmnd *sc) 3075iscsi_eh_host_reset(struct scsi_cmnd *sc)
2942{ 3076{
2943 struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; 3077 struct Scsi_Host *host = sc->device->host;
2944 struct iscsi_conn *conn = ctask->conn; 3078 struct iscsi_session *session = iscsi_hostdata(host->hostdata);
2945 struct iscsi_session *session = conn->session; 3079 struct iscsi_conn *conn = session->leadconn;
3080 int fail_session = 0;
2946 3081
2947 spin_lock_bh(&session->lock); 3082 spin_lock_bh(&session->lock);
2948 if (session->state == ISCSI_STATE_TERMINATE) { 3083 if (session->state == ISCSI_STATE_TERMINATE) {
3084failed:
2949 debug_scsi("failing host reset: session terminated " 3085 debug_scsi("failing host reset: session terminated "
2950 "[CID %d age %d]", conn->id, session->age); 3086 "[CID %d age %d]", conn->id, session->age);
2951 spin_unlock_bh(&session->lock); 3087 spin_unlock_bh(&session->lock);
2952 return FAILED; 3088 return FAILED;
2953 } 3089 }
3090
3091 if (sc->SCp.phase == session->age) {
3092 debug_scsi("failing connection CID %d due to SCSI host reset",
3093 conn->id);
3094 fail_session = 1;
3095 }
2954 spin_unlock_bh(&session->lock); 3096 spin_unlock_bh(&session->lock);
2955 3097
2956 debug_scsi("failing connection CID %d due to SCSI host reset " 3098 /*
2957 "[itt 0x%x age %d]", conn->id, ctask->itt, 3099 * we drop the lock here but the leadconn cannot be destoyed while
2958 session->age); 3100 * we are in the scsi eh
2959 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 3101 */
3102 if (fail_session) {
3103 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
3104 /*
3105 * if userspace cannot respond then we must kick this off
3106 * here for it
3107 */
3108 iscsi_start_session_recovery(session, conn, STOP_CONN_RECOVER);
3109 }
3110
3111 debug_scsi("iscsi_eh_host_reset wait for relogin\n");
3112 wait_event_interruptible(conn->ehwait,
3113 session->state == ISCSI_STATE_TERMINATE ||
3114 session->state == ISCSI_STATE_LOGGED_IN ||
3115 session->recovery_failed);
3116 if (signal_pending(current))
3117 flush_signals(current);
3118
3119 spin_lock_bh(&session->lock);
3120 if (session->state == ISCSI_STATE_LOGGED_IN)
3121 printk(KERN_INFO "host reset succeeded\n");
3122 else
3123 goto failed;
3124 spin_unlock_bh(&session->lock);
2960 3125
2961 return SUCCESS; 3126 return SUCCESS;
2962} 3127}
@@ -2970,8 +3135,6 @@ iscsi_tmabort_timedout(unsigned long data)
2970 3135
2971 spin_lock(&session->lock); 3136 spin_lock(&session->lock);
2972 if (conn->tmabort_state == TMABORT_INITIAL) { 3137 if (conn->tmabort_state == TMABORT_INITIAL) {
2973 __kfifo_put(session->mgmtpool.queue,
2974 (void*)&ctask->mtask, sizeof(void*));
2975 conn->tmabort_state = TMABORT_TIMEDOUT; 3138 conn->tmabort_state = TMABORT_TIMEDOUT;
2976 debug_scsi("tmabort timedout [sc %lx itt 0x%x]\n", 3139 debug_scsi("tmabort timedout [sc %lx itt 0x%x]\n",
2977 (long)ctask->sc, ctask->itt); 3140 (long)ctask->sc, ctask->itt);
@@ -2981,186 +3144,163 @@ iscsi_tmabort_timedout(unsigned long data)
2981 spin_unlock(&session->lock); 3144 spin_unlock(&session->lock);
2982} 3145}
2983 3146
3147/* must be called with the mutex lock */
2984static int 3148static int
2985iscsi_eh_abort(struct scsi_cmnd *sc) 3149iscsi_exec_abort_task(struct scsi_cmnd *sc, struct iscsi_cmd_task *ctask)
2986{ 3150{
2987 int rc;
2988 struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
2989 struct iscsi_conn *conn = ctask->conn; 3151 struct iscsi_conn *conn = ctask->conn;
2990 struct iscsi_session *session = conn->session; 3152 struct iscsi_session *session = conn->session;
2991 3153 struct iscsi_tm *hdr = &conn->tmhdr;
2992 conn->eh_abort_cnt++; 3154 int rc;
2993 debug_scsi("aborting [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
2994 3155
2995 /* 3156 /*
2996 * two cases for ERL=0 here: 3157 * ctask timed out but session is OK requests must be serialized.
2997 *
2998 * 1) connection-level failure;
2999 * 2) recovery due protocol error;
3000 */ 3158 */
3001 mutex_lock(&conn->xmitmutex); 3159 memset(hdr, 0, sizeof(struct iscsi_tm));
3002 spin_lock_bh(&session->lock); 3160 hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
3003 if (session->state != ISCSI_STATE_LOGGED_IN) { 3161 hdr->flags = ISCSI_TM_FUNC_ABORT_TASK;
3004 if (session->state == ISCSI_STATE_TERMINATE) { 3162 hdr->flags |= ISCSI_FLAG_CMD_FINAL;
3005 spin_unlock_bh(&session->lock); 3163 memcpy(hdr->lun, ctask->hdr.lun, sizeof(hdr->lun));
3006 mutex_unlock(&conn->xmitmutex); 3164 hdr->rtt = ctask->hdr.itt;
3007 goto failed; 3165 hdr->refcmdsn = ctask->hdr.cmdsn;
3008 }
3009 spin_unlock_bh(&session->lock);
3010 } else {
3011 struct iscsi_tm *hdr = &conn->tmhdr;
3012 3166
3013 /* 3167 rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr,
3014 * Still LOGGED_IN... 3168 NULL, 0);
3015 */ 3169 if (rc) {
3170 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
3171 debug_scsi("abort sent failure [itt 0x%x] %d", ctask->itt, rc);
3172 return rc;
3173 }
3016 3174
3017 if (!ctask->sc || sc->SCp.phase != session->age) { 3175 debug_scsi("abort sent [itt 0x%x]\n", ctask->itt);
3018 /*
3019 * 1) ctask completed before time out. But session
3020 * is still ok => Happy Retry.
3021 * 2) session was re-open during time out of ctask.
3022 */
3023 spin_unlock_bh(&session->lock);
3024 mutex_unlock(&conn->xmitmutex);
3025 goto success;
3026 }
3027 conn->tmabort_state = TMABORT_INITIAL;
3028 spin_unlock_bh(&session->lock);
3029 3176
3030 /* 3177 spin_lock_bh(&session->lock);
3031 * ctask timed out but session is OK 3178 ctask->mtask = (struct iscsi_mgmt_task *)
3032 * ERL=0 requires task mgmt abort to be issued on each 3179 session->mgmt_cmds[(hdr->itt & ITT_MASK) -
3033 * failed command. requests must be serialized. 3180 ISCSI_MGMT_ITT_OFFSET];
3034 */ 3181
3035 memset(hdr, 0, sizeof(struct iscsi_tm)); 3182 if (conn->tmabort_state == TMABORT_INITIAL) {
3036 hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; 3183 conn->tmfcmd_pdus_cnt++;
3037 hdr->flags = ISCSI_TM_FUNC_ABORT_TASK; 3184 conn->tmabort_timer.expires = 10*HZ + jiffies;
3038 hdr->flags |= ISCSI_FLAG_CMD_FINAL; 3185 conn->tmabort_timer.function = iscsi_tmabort_timedout;
3039 memcpy(hdr->lun, ctask->hdr.lun, sizeof(hdr->lun)); 3186 conn->tmabort_timer.data = (unsigned long)ctask;
3040 hdr->rtt = ctask->hdr.itt; 3187 add_timer(&conn->tmabort_timer);
3041 hdr->refcmdsn = ctask->hdr.cmdsn; 3188 debug_scsi("abort set timeout [itt 0x%x]", ctask->itt);
3042
3043 rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr,
3044 NULL, 0);
3045 if (rc) {
3046 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
3047 debug_scsi("abort sent failure [itt 0x%x]", ctask->itt);
3048 } else {
3049 struct iscsi_r2t_info *r2t;
3050
3051 /*
3052 * TMF abort vs. TMF response race logic
3053 */
3054 spin_lock_bh(&session->lock);
3055 ctask->mtask = (struct iscsi_mgmt_task *)
3056 session->mgmt_cmds[(hdr->itt & ITT_MASK) -
3057 ISCSI_MGMT_ITT_OFFSET];
3058 /*
3059 * have to flush r2tqueue to avoid r2t leaks
3060 */
3061 while (__kfifo_get(ctask->r2tqueue, (void*)&r2t,
3062 sizeof(void*))) {
3063 __kfifo_put(ctask->r2tpool.queue, (void*)&r2t,
3064 sizeof(void*));
3065 }
3066 if (conn->tmabort_state == TMABORT_INITIAL) {
3067 conn->tmfcmd_pdus_cnt++;
3068 conn->tmabort_timer.expires = 3*HZ + jiffies;
3069 conn->tmabort_timer.function =
3070 iscsi_tmabort_timedout;
3071 conn->tmabort_timer.data = (unsigned long)ctask;
3072 add_timer(&conn->tmabort_timer);
3073 debug_scsi("abort sent [itt 0x%x]", ctask->itt);
3074 } else {
3075 if (!ctask->sc ||
3076 conn->tmabort_state == TMABORT_SUCCESS) {
3077 conn->tmabort_state = TMABORT_INITIAL;
3078 spin_unlock_bh(&session->lock);
3079 mutex_unlock(&conn->xmitmutex);
3080 goto success;
3081 }
3082 conn->tmabort_state = TMABORT_INITIAL;
3083 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
3084 }
3085 spin_unlock_bh(&session->lock);
3086 }
3087 } 3189 }
3190 spin_unlock_bh(&session->lock);
3088 mutex_unlock(&conn->xmitmutex); 3191 mutex_unlock(&conn->xmitmutex);
3089 3192
3090
3091 /* 3193 /*
3092 * block eh thread until: 3194 * block eh thread until:
3093 * 3195 *
3094 * 1) abort response; 3196 * 1) abort response
3095 * 2) abort timeout; 3197 * 2) abort timeout
3096 * 3) session re-opened; 3198 * 3) session is terminated or restarted or userspace has
3097 * 4) session terminated; 3199 * given up on recovery
3098 */ 3200 */
3099 for (;;) { 3201 wait_event_interruptible(conn->ehwait,
3100 int p_state = session->state; 3202 sc->SCp.phase != session->age ||
3101 3203 session->state != ISCSI_STATE_LOGGED_IN ||
3102 rc = wait_event_interruptible(conn->ehwait, 3204 conn->tmabort_state != TMABORT_INITIAL ||
3103 (p_state == ISCSI_STATE_LOGGED_IN ? 3205 session->recovery_failed);
3104 (session->state == ISCSI_STATE_TERMINATE || 3206 if (signal_pending(current))
3105 conn->tmabort_state != TMABORT_INITIAL) : 3207 flush_signals(current);
3106 (session->state == ISCSI_STATE_TERMINATE || 3208 del_timer_sync(&conn->tmabort_timer);
3107 session->state == ISCSI_STATE_LOGGED_IN)));
3108 if (rc) {
3109 /* shutdown.. */
3110 session->state = ISCSI_STATE_TERMINATE;
3111 goto failed;
3112 }
3113 3209
3114 if (signal_pending(current)) 3210 mutex_lock(&conn->xmitmutex);
3115 flush_signals(current); 3211 return 0;
3212}
3116 3213
3117 if (session->state == ISCSI_STATE_TERMINATE) 3214static int
3118 goto failed; 3215iscsi_eh_abort(struct scsi_cmnd *sc)
3216{
3217 struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
3218 struct iscsi_cmd_task *tmp_ctask;
3219 struct iscsi_conn *conn = ctask->conn;
3220 struct iscsi_session *session = conn->session;
3221 int rc;
3119 3222
3120 spin_lock_bh(&session->lock); 3223 conn->eh_abort_cnt++;
3121 if (sc->SCp.phase == session->age && 3224 debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
3122 (conn->tmabort_state == TMABORT_TIMEDOUT || 3225
3123 conn->tmabort_state == TMABORT_FAILED)) { 3226 mutex_lock(&conn->xmitmutex);
3124 conn->tmabort_state = TMABORT_INITIAL; 3227 spin_lock_bh(&session->lock);
3125 if (!ctask->sc) { 3228
3126 /* 3229 /*
3127 * ctask completed before tmf abort response or 3230 * If we are not logged in or we have started a new session
3128 * time out. 3231 * then let the host reset code handle this
3129 * But session is still ok => Happy Retry. 3232 */
3130 */ 3233 if (session->state != ISCSI_STATE_LOGGED_IN ||
3131 spin_unlock_bh(&session->lock); 3234 sc->SCp.phase != session->age)
3132 break; 3235 goto failed;
3133 } 3236
3134 spin_unlock_bh(&session->lock); 3237 /* ctask completed before time out */
3135 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 3238 if (!ctask->sc)
3136 continue; 3239 goto success;
3240
3241 /* what should we do here ? */
3242 if (conn->ctask == ctask) {
3243 printk(KERN_INFO "sc %p itt 0x%x partially sent. Failing "
3244 "abort\n", sc, ctask->itt);
3245 goto failed;
3246 }
3247
3248 /* check for the easy pending cmd abort */
3249 while (__kfifo_get(conn->xmitqueue, (void*)&tmp_ctask, sizeof(void*))) {
3250 if (tmp_ctask->itt == ctask->itt) {
3251 debug_scsi("found pending task\n");
3252 goto success;
3137 } 3253 }
3254 __kfifo_put(conn->xmitqueue, (void*)&tmp_ctask, sizeof(void*));
3255 }
3256
3257 conn->tmabort_state = TMABORT_INITIAL;
3258
3259 spin_unlock_bh(&session->lock);
3260 rc = iscsi_exec_abort_task(sc, ctask);
3261 spin_lock_bh(&session->lock);
3262
3263 iscsi_ctask_mtask_cleanup(ctask);
3264 if (rc || sc->SCp.phase != session->age ||
3265 session->state != ISCSI_STATE_LOGGED_IN)
3266 goto failed;
3267
3268 /* ctask completed before tmf abort response */
3269 if (!ctask->sc) {
3270 debug_scsi("sc completed while abort in progress\n");
3271 goto success;
3272 }
3273
3274 if (conn->tmabort_state != TMABORT_SUCCESS) {
3138 spin_unlock_bh(&session->lock); 3275 spin_unlock_bh(&session->lock);
3139 break; 3276 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
3277 spin_lock_bh(&session->lock);
3278 goto failed;
3140 } 3279 }
3141 3280
3142success: 3281success:
3143 debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); 3282 debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
3144 rc = SUCCESS; 3283 spin_unlock_bh(&session->lock);
3145 goto exit;
3146
3147failed:
3148 debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
3149 rc = FAILED;
3150
3151exit:
3152 del_timer_sync(&conn->tmabort_timer);
3153 3284
3154 mutex_lock(&conn->xmitmutex); 3285 /* clean up task if aborted */
3155 if (conn->sock) { 3286 if (conn->sock) {
3156 struct sock *sk = conn->sock->sk; 3287 struct sock *sk = conn->sock->sk;
3157 3288
3158 write_lock_bh(&sk->sk_callback_lock); 3289 write_lock_bh(&sk->sk_callback_lock);
3159 iscsi_ctask_cleanup(conn, ctask); 3290 spin_lock(&session->lock);
3291 fail_command(conn, ctask, DRIVER_TIMEOUT << 24);
3292 spin_unlock(&session->lock);
3160 write_unlock_bh(&sk->sk_callback_lock); 3293 write_unlock_bh(&sk->sk_callback_lock);
3161 } 3294 }
3162 mutex_unlock(&conn->xmitmutex); 3295 mutex_unlock(&conn->xmitmutex);
3163 return rc; 3296 return SUCCESS;
3297
3298failed:
3299 spin_unlock_bh(&session->lock);
3300 mutex_unlock(&conn->xmitmutex);
3301
3302 debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
3303 return FAILED;
3164} 3304}
3165 3305
3166static int 3306static int
@@ -3359,16 +3499,6 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
3359 struct iscsi_conn *conn = cls_conn->dd_data; 3499 struct iscsi_conn *conn = cls_conn->dd_data;
3360 struct iscsi_session *session = conn->session; 3500 struct iscsi_session *session = conn->session;
3361 3501
3362 spin_lock_bh(&session->lock);
3363 if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE &&
3364 conn->stop_stage != STOP_CONN_RECOVER) {
3365 printk(KERN_ERR "iscsi_tcp: can not change parameter [%d]\n",
3366 param);
3367 spin_unlock_bh(&session->lock);
3368 return 0;
3369 }
3370 spin_unlock_bh(&session->lock);
3371
3372 switch(param) { 3502 switch(param) {
3373 case ISCSI_PARAM_MAX_RECV_DLENGTH: { 3503 case ISCSI_PARAM_MAX_RECV_DLENGTH: {
3374 char *saveptr = conn->data; 3504 char *saveptr = conn->data;
@@ -3691,6 +3821,7 @@ static struct iscsi_transport iscsi_tcp_transport = {
3691 .stop_conn = iscsi_conn_stop, 3821 .stop_conn = iscsi_conn_stop,
3692 .send_pdu = iscsi_conn_send_pdu, 3822 .send_pdu = iscsi_conn_send_pdu,
3693 .get_stats = iscsi_conn_get_stats, 3823 .get_stats = iscsi_conn_get_stats,
3824 .session_recovery_timedout = iscsi_session_recovery_timedout,
3694}; 3825};
3695 3826
3696static int __init 3827static int __init
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index ba26741ac154..12ef64179b4c 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -159,6 +159,7 @@ struct iscsi_conn {
159 struct kfifo *immqueue; /* immediate xmit queue */ 159 struct kfifo *immqueue; /* immediate xmit queue */
160 struct kfifo *mgmtqueue; /* mgmt (control) xmit queue */ 160 struct kfifo *mgmtqueue; /* mgmt (control) xmit queue */
161 struct kfifo *xmitqueue; /* data-path cmd queue */ 161 struct kfifo *xmitqueue; /* data-path cmd queue */
162 struct list_head run_list; /* list of cmds in progress */
162 struct work_struct xmitwork; /* per-conn. xmit workqueue */ 163 struct work_struct xmitwork; /* per-conn. xmit workqueue */
163 struct mutex xmitmutex; /* serializes connection xmit, 164 struct mutex xmitmutex; /* serializes connection xmit,
164 * access to kfifos: * 165 * access to kfifos: *
@@ -228,6 +229,7 @@ struct iscsi_session {
228 * - mgmtpool, * 229 * - mgmtpool, *
229 * - r2tpool */ 230 * - r2tpool */
230 int state; /* session state */ 231 int state; /* session state */
232 int recovery_failed;
231 struct list_head item; 233 struct list_head item;
232 void *auth_client; 234 void *auth_client;
233 int conn_cnt; 235 int conn_cnt;
@@ -310,6 +312,7 @@ struct iscsi_cmd_task {
310 struct iscsi_conn *conn; /* used connection */ 312 struct iscsi_conn *conn; /* used connection */
311 struct iscsi_mgmt_task *mtask; /* tmf mtask in progr */ 313 struct iscsi_mgmt_task *mtask; /* tmf mtask in progr */
312 314
315 struct list_head running; /* running cmd list */
313 struct iscsi_r2t_info *r2t; /* in progress R2T */ 316 struct iscsi_r2t_info *r2t; /* in progress R2T */
314 struct iscsi_queue r2tpool; 317 struct iscsi_queue r2tpool;
315 struct kfifo *r2tqueue; 318 struct kfifo *r2tqueue;
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 72a71ebc9d03..e2b67e34d92e 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -31,17 +31,17 @@
31#include <scsi/scsi_transport_iscsi.h> 31#include <scsi/scsi_transport_iscsi.h>
32#include <scsi/iscsi_if.h> 32#include <scsi/iscsi_if.h>
33 33
34#define ISCSI_SESSION_ATTRS 10 34#define ISCSI_SESSION_ATTRS 11
35#define ISCSI_CONN_ATTRS 10 35#define ISCSI_CONN_ATTRS 10
36#define ISCSI_HOST_ATTRS 0
36 37
37struct iscsi_internal { 38struct iscsi_internal {
38 struct scsi_transport_template t; 39 struct scsi_transport_template t;
39 struct iscsi_transport *iscsi_transport; 40 struct iscsi_transport *iscsi_transport;
40 struct list_head list; 41 struct list_head list;
41 struct class_device cdev; 42 struct class_device cdev;
42 /* 43
43 * We do not have any private or other attrs. 44 struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
44 */
45 struct transport_container conn_cont; 45 struct transport_container conn_cont;
46 struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1]; 46 struct class_device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
47 struct transport_container session_cont; 47 struct transport_container session_cont;
@@ -114,6 +114,24 @@ static struct attribute_group iscsi_transport_group = {
114 .attrs = iscsi_transport_attrs, 114 .attrs = iscsi_transport_attrs,
115}; 115};
116 116
117static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
118 struct class_device *cdev)
119{
120 struct Scsi_Host *shost = dev_to_shost(dev);
121 struct iscsi_host *ihost = shost->shost_data;
122
123 memset(ihost, 0, sizeof(*ihost));
124 INIT_LIST_HEAD(&ihost->sessions);
125 mutex_init(&ihost->mutex);
126 return 0;
127}
128
129static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
130 "iscsi_host",
131 iscsi_setup_host,
132 NULL,
133 NULL);
134
117static DECLARE_TRANSPORT_CLASS(iscsi_session_class, 135static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
118 "iscsi_session", 136 "iscsi_session",
119 NULL, 137 NULL,
@@ -225,6 +243,54 @@ static int iscsi_is_session_dev(const struct device *dev)
225 return dev->release == iscsi_session_release; 243 return dev->release == iscsi_session_release;
226} 244}
227 245
246static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
247 uint id, uint lun)
248{
249 struct iscsi_host *ihost = shost->shost_data;
250 struct iscsi_cls_session *session;
251
252 mutex_lock(&ihost->mutex);
253 list_for_each_entry(session, &ihost->sessions, host_list) {
254 if ((channel == SCAN_WILD_CARD ||
255 channel == session->channel) &&
256 (id == SCAN_WILD_CARD || id == session->target_id))
257 scsi_scan_target(&session->dev, session->channel,
258 session->target_id, lun, 1);
259 }
260 mutex_unlock(&ihost->mutex);
261
262 return 0;
263}
264
265static void session_recovery_timedout(void *data)
266{
267 struct iscsi_cls_session *session = data;
268
269 dev_printk(KERN_INFO, &session->dev, "session recovery timed out "
270 "after %d secs\n", session->recovery_tmo);
271
272 if (session->transport->session_recovery_timedout)
273 session->transport->session_recovery_timedout(session);
274
275 scsi_target_unblock(&session->dev);
276}
277
278void iscsi_unblock_session(struct iscsi_cls_session *session)
279{
280 if (!cancel_delayed_work(&session->recovery_work))
281 flush_scheduled_work();
282 scsi_target_unblock(&session->dev);
283}
284EXPORT_SYMBOL_GPL(iscsi_unblock_session);
285
286void iscsi_block_session(struct iscsi_cls_session *session)
287{
288 scsi_target_block(&session->dev);
289 schedule_delayed_work(&session->recovery_work,
290 session->recovery_tmo * HZ);
291}
292EXPORT_SYMBOL_GPL(iscsi_block_session);
293
228/** 294/**
229 * iscsi_create_session - create iscsi class session 295 * iscsi_create_session - create iscsi class session
230 * @shost: scsi host 296 * @shost: scsi host
@@ -233,8 +299,10 @@ static int iscsi_is_session_dev(const struct device *dev)
233 * This can be called from a LLD or iscsi_transport. 299 * This can be called from a LLD or iscsi_transport.
234 **/ 300 **/
235struct iscsi_cls_session * 301struct iscsi_cls_session *
236iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport) 302iscsi_create_session(struct Scsi_Host *shost,
303 struct iscsi_transport *transport, int channel)
237{ 304{
305 struct iscsi_host *ihost;
238 struct iscsi_cls_session *session; 306 struct iscsi_cls_session *session;
239 int err; 307 int err;
240 308
@@ -246,13 +314,22 @@ iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport)
246 if (!session) 314 if (!session)
247 goto module_put; 315 goto module_put;
248 session->transport = transport; 316 session->transport = transport;
317 session->recovery_tmo = 120;
318 INIT_WORK(&session->recovery_work, session_recovery_timedout, session);
319 INIT_LIST_HEAD(&session->host_list);
320 INIT_LIST_HEAD(&session->sess_list);
249 321
250 if (transport->sessiondata_size) 322 if (transport->sessiondata_size)
251 session->dd_data = &session[1]; 323 session->dd_data = &session[1];
252 324
253 /* this is released in the dev's release function */ 325 /* this is released in the dev's release function */
254 scsi_host_get(shost); 326 scsi_host_get(shost);
327 ihost = shost->shost_data;
328
255 session->sid = iscsi_session_nr++; 329 session->sid = iscsi_session_nr++;
330 session->channel = channel;
331 session->target_id = ihost->next_target_id++;
332
256 snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", 333 snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
257 session->sid); 334 session->sid);
258 session->dev.parent = &shost->shost_gendev; 335 session->dev.parent = &shost->shost_gendev;
@@ -265,6 +342,10 @@ iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport)
265 } 342 }
266 transport_register_device(&session->dev); 343 transport_register_device(&session->dev);
267 344
345 mutex_lock(&ihost->mutex);
346 list_add(&session->host_list, &ihost->sessions);
347 mutex_unlock(&ihost->mutex);
348
268 return session; 349 return session;
269 350
270free_session: 351free_session:
@@ -285,6 +366,16 @@ EXPORT_SYMBOL_GPL(iscsi_create_session);
285 **/ 366 **/
286int iscsi_destroy_session(struct iscsi_cls_session *session) 367int iscsi_destroy_session(struct iscsi_cls_session *session)
287{ 368{
369 struct Scsi_Host *shost = iscsi_session_to_shost(session);
370 struct iscsi_host *ihost = shost->shost_data;
371
372 if (!cancel_delayed_work(&session->recovery_work))
373 flush_scheduled_work();
374
375 mutex_lock(&ihost->mutex);
376 list_del(&session->host_list);
377 mutex_unlock(&ihost->mutex);
378
288 transport_unregister_device(&session->dev); 379 transport_unregister_device(&session->dev);
289 device_unregister(&session->dev); 380 device_unregister(&session->dev);
290 return 0; 381 return 0;
@@ -435,7 +526,7 @@ iscsi_transport_create_session(struct scsi_transport_template *scsit,
435 if (scsi_add_host(shost, NULL)) 526 if (scsi_add_host(shost, NULL))
436 goto free_host; 527 goto free_host;
437 528
438 session = iscsi_create_session(shost, transport); 529 session = iscsi_create_session(shost, transport, 0);
439 if (!session) 530 if (!session)
440 goto remove_host; 531 goto remove_host;
441 532
@@ -466,12 +557,13 @@ int iscsi_transport_destroy_session(struct Scsi_Host *shost)
466 struct iscsi_cls_session *session; 557 struct iscsi_cls_session *session;
467 unsigned long flags; 558 unsigned long flags;
468 559
469 scsi_remove_host(shost);
470 session = hostdata_session(shost->hostdata); 560 session = hostdata_session(shost->hostdata);
471 spin_lock_irqsave(&sesslock, flags); 561 spin_lock_irqsave(&sesslock, flags);
472 list_del(&session->sess_list); 562 list_del(&session->sess_list);
473 spin_unlock_irqrestore(&sesslock, flags); 563 spin_unlock_irqrestore(&sesslock, flags);
474 iscsi_destroy_session(session); 564 iscsi_destroy_session(session);
565
566 scsi_remove_host(shost);
475 /* ref from host alloc */ 567 /* ref from host alloc */
476 scsi_host_put(shost); 568 scsi_host_put(shost);
477 return 0; 569 return 0;
@@ -594,6 +686,7 @@ iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb)
594 } 686 }
595 687
596 spin_lock_irqsave(&zone->freelock, flags); 688 spin_lock_irqsave(&zone->freelock, flags);
689 INIT_LIST_HEAD(skb_to_lh(skb));
597 list_add(skb_to_lh(skb), &zone->freequeue); 690 list_add(skb_to_lh(skb), &zone->freequeue);
598 spin_unlock_irqrestore(&zone->freelock, flags); 691 spin_unlock_irqrestore(&zone->freelock, flags);
599 692
@@ -888,6 +981,11 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
888 return -EINVAL; 981 return -EINVAL;
889 982
890 switch (ev->u.set_param.param) { 983 switch (ev->u.set_param.param) {
984 case ISCSI_PARAM_SESS_RECOVERY_TMO:
985 iscsi_copy_param(ev, &value, data);
986 if (value != 0)
987 session->recovery_tmo = value;
988 break;
891 case ISCSI_PARAM_TARGET_NAME: 989 case ISCSI_PARAM_TARGET_NAME:
892 /* this should not change between logins */ 990 /* this should not change between logins */
893 if (session->targetname) 991 if (session->targetname)
@@ -980,7 +1078,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
980 ev->r.retcode = transport->start_conn(conn); 1078 ev->r.retcode = transport->start_conn(conn);
981 else 1079 else
982 err = -EINVAL; 1080 err = -EINVAL;
983
984 break; 1081 break;
985 case ISCSI_UEVENT_STOP_CONN: 1082 case ISCSI_UEVENT_STOP_CONN:
986 conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid); 1083 conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid);
@@ -1198,6 +1295,7 @@ static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \
1198 NULL) 1295 NULL)
1199iscsi_priv_session_attr(targetname, "%s"); 1296iscsi_priv_session_attr(targetname, "%s");
1200iscsi_priv_session_attr(tpgt, "%d"); 1297iscsi_priv_session_attr(tpgt, "%d");
1298iscsi_priv_session_attr(recovery_tmo, "%d");
1201 1299
1202#define iscsi_priv_conn_attr_show(field, format) \ 1300#define iscsi_priv_conn_attr_show(field, format) \
1203static ssize_t \ 1301static ssize_t \
@@ -1289,6 +1387,24 @@ static int iscsi_conn_match(struct attribute_container *cont,
1289 return &priv->conn_cont.ac == cont; 1387 return &priv->conn_cont.ac == cont;
1290} 1388}
1291 1389
1390static int iscsi_host_match(struct attribute_container *cont,
1391 struct device *dev)
1392{
1393 struct Scsi_Host *shost;
1394 struct iscsi_internal *priv;
1395
1396 if (!scsi_is_host_device(dev))
1397 return 0;
1398
1399 shost = dev_to_shost(dev);
1400 if (!shost->transportt ||
1401 shost->transportt->host_attrs.ac.class != &iscsi_host_class.class)
1402 return 0;
1403
1404 priv = to_iscsi_internal(shost->transportt);
1405 return &priv->t.host_attrs.ac == cont;
1406}
1407
1292struct scsi_transport_template * 1408struct scsi_transport_template *
1293iscsi_register_transport(struct iscsi_transport *tt) 1409iscsi_register_transport(struct iscsi_transport *tt)
1294{ 1410{
@@ -1307,6 +1423,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
1307 return NULL; 1423 return NULL;
1308 INIT_LIST_HEAD(&priv->list); 1424 INIT_LIST_HEAD(&priv->list);
1309 priv->iscsi_transport = tt; 1425 priv->iscsi_transport = tt;
1426 priv->t.user_scan = iscsi_user_scan;
1310 1427
1311 priv->cdev.class = &iscsi_transport_class; 1428 priv->cdev.class = &iscsi_transport_class;
1312 snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name); 1429 snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name);
@@ -1318,6 +1435,14 @@ iscsi_register_transport(struct iscsi_transport *tt)
1318 if (err) 1435 if (err)
1319 goto unregister_cdev; 1436 goto unregister_cdev;
1320 1437
1438 /* host parameters */
1439 priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
1440 priv->t.host_attrs.ac.class = &iscsi_host_class.class;
1441 priv->t.host_attrs.ac.match = iscsi_host_match;
1442 priv->t.host_size = sizeof(struct iscsi_host);
1443 priv->host_attrs[0] = NULL;
1444 transport_container_register(&priv->t.host_attrs);
1445
1321 /* connection parameters */ 1446 /* connection parameters */
1322 priv->conn_cont.ac.attrs = &priv->conn_attrs[0]; 1447 priv->conn_cont.ac.attrs = &priv->conn_attrs[0];
1323 priv->conn_cont.ac.class = &iscsi_connection_class.class; 1448 priv->conn_cont.ac.class = &iscsi_connection_class.class;
@@ -1361,6 +1486,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
1361 SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN); 1486 SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN);
1362 SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN); 1487 SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN);
1363 SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL); 1488 SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL);
1489 SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
1364 1490
1365 if (tt->param_mask & ISCSI_TARGET_NAME) 1491 if (tt->param_mask & ISCSI_TARGET_NAME)
1366 SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME); 1492 SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
@@ -1408,6 +1534,7 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
1408 1534
1409 transport_container_unregister(&priv->conn_cont); 1535 transport_container_unregister(&priv->conn_cont);
1410 transport_container_unregister(&priv->session_cont); 1536 transport_container_unregister(&priv->session_cont);
1537 transport_container_unregister(&priv->t.host_attrs);
1411 1538
1412 sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group); 1539 sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
1413 class_device_unregister(&priv->cdev); 1540 class_device_unregister(&priv->cdev);
@@ -1451,10 +1578,14 @@ static __init int iscsi_transport_init(void)
1451 if (err) 1578 if (err)
1452 return err; 1579 return err;
1453 1580
1454 err = transport_class_register(&iscsi_connection_class); 1581 err = transport_class_register(&iscsi_host_class);
1455 if (err) 1582 if (err)
1456 goto unregister_transport_class; 1583 goto unregister_transport_class;
1457 1584
1585 err = transport_class_register(&iscsi_connection_class);
1586 if (err)
1587 goto unregister_host_class;
1588
1458 err = transport_class_register(&iscsi_session_class); 1589 err = transport_class_register(&iscsi_session_class);
1459 if (err) 1590 if (err)
1460 goto unregister_conn_class; 1591 goto unregister_conn_class;
@@ -1482,6 +1613,8 @@ unregister_session_class:
1482 transport_class_unregister(&iscsi_session_class); 1613 transport_class_unregister(&iscsi_session_class);
1483unregister_conn_class: 1614unregister_conn_class:
1484 transport_class_unregister(&iscsi_connection_class); 1615 transport_class_unregister(&iscsi_connection_class);
1616unregister_host_class:
1617 transport_class_unregister(&iscsi_host_class);
1485unregister_transport_class: 1618unregister_transport_class:
1486 class_unregister(&iscsi_transport_class); 1619 class_unregister(&iscsi_transport_class);
1487 return err; 1620 return err;
@@ -1494,6 +1627,7 @@ static void __exit iscsi_transport_exit(void)
1494 netlink_unregister_notifier(&iscsi_nl_notifier); 1627 netlink_unregister_notifier(&iscsi_nl_notifier);
1495 transport_class_unregister(&iscsi_connection_class); 1628 transport_class_unregister(&iscsi_connection_class);
1496 transport_class_unregister(&iscsi_session_class); 1629 transport_class_unregister(&iscsi_session_class);
1630 transport_class_unregister(&iscsi_host_class);
1497 class_unregister(&iscsi_transport_class); 1631 class_unregister(&iscsi_transport_class);
1498} 1632}
1499 1633
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 2c3a89b64e71..eebe2b15161b 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -174,6 +174,7 @@ enum iscsi_param {
174 ISCSI_PARAM_TPGT, 174 ISCSI_PARAM_TPGT,
175 ISCSI_PARAM_PERSISTENT_ADDRESS, 175 ISCSI_PARAM_PERSISTENT_ADDRESS,
176 ISCSI_PARAM_PERSISTENT_PORT, 176 ISCSI_PARAM_PERSISTENT_PORT,
177 ISCSI_PARAM_SESS_RECOVERY_TMO,
177 178
178 /* pased in through bind conn using transport_fd */ 179 /* pased in through bind conn using transport_fd */
179 ISCSI_PARAM_CONN_PORT, 180 ISCSI_PARAM_CONN_PORT,
@@ -201,6 +202,7 @@ enum iscsi_param {
201#define ISCSI_TPGT (1 << ISCSI_PARAM_TPGT) 202#define ISCSI_TPGT (1 << ISCSI_PARAM_TPGT)
202#define ISCSI_PERSISTENT_ADDRESS (1 << ISCSI_PARAM_PERSISTENT_ADDRESS) 203#define ISCSI_PERSISTENT_ADDRESS (1 << ISCSI_PARAM_PERSISTENT_ADDRESS)
203#define ISCSI_PERSISTENT_PORT (1 << ISCSI_PARAM_PERSISTENT_PORT) 204#define ISCSI_PERSISTENT_PORT (1 << ISCSI_PARAM_PERSISTENT_PORT)
205#define ISCSI_SESS_RECOVERY_TMO (1 << ISCSI_PARAM_SESS_RECOVERY_TMO)
204#define ISCSI_CONN_PORT (1 << ISCSI_PARAM_CONN_PORT) 206#define ISCSI_CONN_PORT (1 << ISCSI_PARAM_CONN_PORT)
205#define ISCSI_CONN_ADDRESS (1 << ISCSI_PARAM_CONN_ADDRESS) 207#define ISCSI_CONN_ADDRESS (1 << ISCSI_PARAM_CONN_ADDRESS)
206 208
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 4b200645c84b..9d2b99159ee7 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -90,6 +90,7 @@ struct iscsi_transport {
90 char *data, uint32_t data_size); 90 char *data, uint32_t data_size);
91 void (*get_stats) (struct iscsi_cls_conn *conn, 91 void (*get_stats) (struct iscsi_cls_conn *conn,
92 struct iscsi_stats *stats); 92 struct iscsi_stats *stats);
93 void (*session_recovery_timedout) (struct iscsi_cls_session *session);
93}; 94};
94 95
95/* 96/*
@@ -130,12 +131,20 @@ struct iscsi_cls_conn {
130 131
131struct iscsi_cls_session { 132struct iscsi_cls_session {
132 struct list_head sess_list; /* item in session_list */ 133 struct list_head sess_list; /* item in session_list */
134 struct list_head host_list;
133 struct iscsi_transport *transport; 135 struct iscsi_transport *transport;
134 136
135 /* iSCSI values used as unique id by userspace. */ 137 /* iSCSI values used as unique id by userspace. */
136 char *targetname; 138 char *targetname;
137 int tpgt; 139 int tpgt;
138 140
141 /* recovery fields */
142 int recovery_tmo;
143 struct work_struct recovery_work;
144
145 int target_id;
146 int channel;
147
139 int sid; /* session id */ 148 int sid; /* session id */
140 void *dd_data; /* LLD private data */ 149 void *dd_data; /* LLD private data */
141 struct device dev; /* sysfs transport/container device */ 150 struct device dev; /* sysfs transport/container device */
@@ -147,15 +156,23 @@ struct iscsi_cls_session {
147#define iscsi_session_to_shost(_session) \ 156#define iscsi_session_to_shost(_session) \
148 dev_to_shost(_session->dev.parent) 157 dev_to_shost(_session->dev.parent)
149 158
159struct iscsi_host {
160 int next_target_id;
161 struct list_head sessions;
162 struct mutex mutex;
163};
164
150/* 165/*
151 * session and connection functions that can be used by HW iSCSI LLDs 166 * session and connection functions that can be used by HW iSCSI LLDs
152 */ 167 */
153extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, 168extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
154 struct iscsi_transport *t); 169 struct iscsi_transport *t, int channel);
155extern int iscsi_destroy_session(struct iscsi_cls_session *session); 170extern int iscsi_destroy_session(struct iscsi_cls_session *session);
156extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, 171extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess,
157 uint32_t cid); 172 uint32_t cid);
158extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); 173extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn);
174extern void iscsi_unblock_session(struct iscsi_cls_session *session);
175extern void iscsi_block_session(struct iscsi_cls_session *session);
159 176
160/* 177/*
161 * session functions used by software iscsi 178 * session functions used by software iscsi