]> err.no Git - linux-2.6/blobdiff - drivers/scsi/libiscsi.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[linux-2.6] / drivers / scsi / libiscsi.c
index d810acae45f70d4629bef38faab21fac8bce350f..2673a11a9495ef2297ada1591cf65cfcbd94c0a1 100644 (file)
@@ -492,7 +492,7 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
                return;
        }
 
-       if (session->conn_cnt == 1 || session->leadconn == conn)
+       if (conn->stop_stage == 0)
                session->state = ISCSI_STATE_FAILED;
        spin_unlock_irqrestore(&session->lock, flags);
        set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
@@ -513,10 +513,11 @@ EXPORT_SYMBOL_GPL(iscsi_conn_failure);
 static int iscsi_data_xmit(struct iscsi_conn *conn)
 {
        struct iscsi_transport *tt;
+       int rc = 0;
 
        if (unlikely(conn->suspend_tx)) {
                debug_scsi("conn %d Tx suspended!\n", conn->id);
-               return 0;
+               return -ENODATA;
        }
        tt = conn->session->tt;
 
@@ -536,13 +537,15 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
        BUG_ON(conn->ctask && conn->mtask);
 
        if (conn->ctask) {
-               if (tt->xmit_cmd_task(conn, conn->ctask))
+               rc = tt->xmit_cmd_task(conn, conn->ctask);
+               if (rc)
                        goto again;
                /* done with this in-progress ctask */
                conn->ctask = NULL;
        }
        if (conn->mtask) {
-               if (tt->xmit_mgmt_task(conn, conn->mtask))
+               rc = tt->xmit_mgmt_task(conn, conn->mtask);
+               if (rc)
                        goto again;
                /* done with this in-progress mtask */
                conn->mtask = NULL;
@@ -552,9 +555,12 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
         if (unlikely(__kfifo_len(conn->immqueue))) {
                while (__kfifo_get(conn->immqueue, (void*)&conn->mtask,
                                   sizeof(void*))) {
+                       spin_lock_bh(&conn->session->lock);
                        list_add_tail(&conn->mtask->running,
                                      &conn->mgmt_run_list);
-                       if (tt->xmit_mgmt_task(conn, conn->mtask))
+                       spin_unlock_bh(&conn->session->lock);
+                       rc = tt->xmit_mgmt_task(conn, conn->mtask);
+                       if (rc)
                                goto again;
                }
                /* done with this mtask */
@@ -568,9 +574,12 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
                 * iscsi tcp may readd the task to the xmitqueue to send
                 * write data
                 */
+               spin_lock_bh(&conn->session->lock);
                if (list_empty(&conn->ctask->running))
                        list_add_tail(&conn->ctask->running, &conn->run_list);
-               if (tt->xmit_cmd_task(conn, conn->ctask))
+               spin_unlock_bh(&conn->session->lock);
+               rc = tt->xmit_cmd_task(conn, conn->ctask);
+               if (rc)
                        goto again;
        }
        /* done with this ctask */
@@ -580,34 +589,38 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
         if (unlikely(__kfifo_len(conn->mgmtqueue))) {
                while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask,
                                   sizeof(void*))) {
+                       spin_lock_bh(&conn->session->lock);
                        list_add_tail(&conn->mtask->running,
                                      &conn->mgmt_run_list);
-                       if (tt->xmit_mgmt_task(conn, conn->mtask))
+                       spin_unlock_bh(&conn->session->lock);
+                       rc = tt->xmit_mgmt_task(conn, conn->mtask);
+                       if (rc)
                                goto again;
                }
                /* done with this mtask */
                conn->mtask = NULL;
        }
 
-       return 0;
+       return -ENODATA;
 
 again:
        if (unlikely(conn->suspend_tx))
-               return 0;
+               return -ENODATA;
 
-       return -EAGAIN;
+       return rc;
 }
 
 static void iscsi_xmitworker(void *data)
 {
        struct iscsi_conn *conn = data;
-
+       int rc;
        /*
         * serialize Xmit worker on a per-connection basis.
         */
        mutex_lock(&conn->xmitmutex);
-       if (iscsi_data_xmit(conn))
-               scsi_queue_work(conn->session->host, &conn->xmitwork);
+       do {
+               rc = iscsi_data_xmit(conn);
+       } while (rc >= 0 || rc == -EAGAIN);
        mutex_unlock(&conn->xmitmutex);
 }
 
@@ -652,7 +665,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
                 */
                if (session->state == ISCSI_STATE_IN_RECOVERY) {
                        reason = FAILURE_SESSION_IN_RECOVERY;
-                       goto fault;
+                       goto reject;
                }
 
                if (session->state == ISCSI_STATE_RECOVERY_FAILED)
@@ -979,7 +992,7 @@ iscsi_remove_##tasktype(struct kfifo *fifo, uint32_t itt)           \
                                                                        \
                if (task->itt == itt) {                                 \
                        debug_scsi("matched task\n");                   \
-                       break;                                          \
+                       return task;                                    \
                }                                                       \
                                                                        \
                __kfifo_put(fifo, (void*)&task, sizeof(void*));         \
@@ -1411,8 +1424,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
        struct iscsi_session *session = conn->session;
        unsigned long flags;
 
-       mutex_lock(&conn->xmitmutex);
        set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+       mutex_lock(&conn->xmitmutex);
        if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE) {
                if (session->tt->suspend_conn_recv)
                        session->tt->suspend_conn_recv(conn);
@@ -1498,7 +1511,6 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
                 * unblock eh_abort() if it is blocked. re-try all
                 * commands after successful recovery
                 */
-               session->conn_cnt++;
                conn->stop_stage = 0;
                conn->tmabort_state = TMABORT_INITIAL;
                session->age++;
@@ -1508,13 +1520,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
                wake_up(&conn->ehwait);
                return 0;
        case STOP_CONN_TERM:
-               session->conn_cnt++;
-               conn->stop_stage = 0;
-               break;
-       case STOP_CONN_SUSPEND:
                conn->stop_stage = 0;
-               clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
-               clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
                break;
        default:
                break;
@@ -1589,28 +1595,24 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
 
        /*
         * When this is called for the in_login state, we only want to clean
-        * up the login task and connection.
+        * up the login task and connection. We do not need to block and set
+        * the recovery state again
         */
-       if (conn->stop_stage != STOP_CONN_RECOVER)
-               session->conn_cnt--;
+       if (flag == STOP_CONN_TERM)
+               session->state = ISCSI_STATE_TERMINATE;
+       else if (conn->stop_stage != STOP_CONN_RECOVER)
+               session->state = ISCSI_STATE_IN_RECOVERY;
 
        old_stop_stage = conn->stop_stage;
        conn->stop_stage = flag;
+       conn->c_stage = ISCSI_CONN_STOPPED;
+       set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
        spin_unlock_bh(&session->lock);
 
        if (session->tt->suspend_conn_recv)
                session->tt->suspend_conn_recv(conn);
 
        mutex_lock(&conn->xmitmutex);
-       spin_lock_bh(&session->lock);
-       conn->c_stage = ISCSI_CONN_STOPPED;
-       set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-
-       if (session->conn_cnt == 0 || session->leadconn == conn)
-               session->state = ISCSI_STATE_IN_RECOVERY;
-
-       spin_unlock_bh(&session->lock);
-
        /*
         * for connection level recovery we should not calculate
         * header digest. conn->hdr_size used for optimization
@@ -1620,13 +1622,11 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
        if (flag == STOP_CONN_RECOVER) {
                conn->hdrdgst_en = 0;
                conn->datadgst_en = 0;
-               /*
-                * if this is called from the eh and and from userspace
-                * then we only need to block once.
-                */
                if (session->state == ISCSI_STATE_IN_RECOVERY &&
-                   old_stop_stage != STOP_CONN_RECOVER)
+                   old_stop_stage != STOP_CONN_RECOVER) {
+                       debug_scsi("blocking session\n");
                        iscsi_block_session(session_to_cls(session));
+               }
        }
 
        session->tt->terminate_conn(conn);
@@ -1651,20 +1651,6 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
        case STOP_CONN_TERM:
                iscsi_start_session_recovery(session, conn, flag);
                break;
-       case STOP_CONN_SUSPEND:
-               if (session->tt->suspend_conn_recv)
-                       session->tt->suspend_conn_recv(conn);
-
-               mutex_lock(&conn->xmitmutex);
-               spin_lock_bh(&session->lock);
-
-               conn->stop_stage = flag;
-               conn->c_stage = ISCSI_CONN_STOPPED;
-               set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-
-               spin_unlock_bh(&session->lock);
-               mutex_unlock(&conn->xmitmutex);
-               break;
        default:
                printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);
        }