i2c: Document the message size limit
[safe/jmp/linux-2.6] / drivers / scsi / libiscsi.c
index cf0aa7e..703eb6a 100644 (file)
@@ -517,7 +517,7 @@ static void iscsi_free_task(struct iscsi_task *task)
        if (conn->login_task == task)
                return;
 
-       __kfifo_put(&session->cmdpool.queue, (void*)&task, sizeof(void*));
+       kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
 
        if (sc) {
                task->sc = NULL;
@@ -737,7 +737,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
                BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
 
-               if (!__kfifo_get(&session->cmdpool.queue,
+               if (!kfifo_out(&session->cmdpool.queue,
                                 (void*)&task, sizeof(void*)))
                        return NULL;
        }
@@ -1567,7 +1567,7 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
 {
        struct iscsi_task *task;
 
-       if (!__kfifo_get(&conn->session->cmdpool.queue,
+       if (!kfifo_out(&conn->session->cmdpool.queue,
                         (void *) &task, sizeof(void *)))
                return NULL;
 
@@ -1919,10 +1919,11 @@ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
 static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
 {
        enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
-       struct iscsi_task *task = NULL;
+       struct iscsi_task *task = NULL, *running_task;
        struct iscsi_cls_session *cls_session;
        struct iscsi_session *session;
        struct iscsi_conn *conn;
+       int i;
 
        cls_session = starget_to_session(scsi_target(sc->device));
        session = cls_session->dd_data;
@@ -1947,8 +1948,15 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
        }
 
        task = (struct iscsi_task *)sc->SCp.ptr;
-       if (!task)
+       if (!task) {
+               /*
+                * Raced with completion. Just reset timer, and let it
+                * complete normally
+                */
+               rc = BLK_EH_RESET_TIMER;
                goto done;
+       }
+
        /*
         * If we have sent (at least queued to the network layer) a pdu or
         * recvd one for the task since the last timeout ask for
@@ -1956,10 +1964,10 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
         * we can check if it is the task or connection when we send the
         * nop as a ping.
         */
-       if (time_after_eq(task->last_xfer, task->last_timeout)) {
+       if (time_after(task->last_xfer, task->last_timeout)) {
                ISCSI_DBG_EH(session, "Command making progress. Asking "
                             "scsi-ml for more time to complete. "
-                            "Last data recv at %lu. Last timeout was at "
+                            "Last data xfer at %lu. Last timeout was at "
                             "%lu\n.", task->last_xfer, task->last_timeout);
                task->have_checked_conn = false;
                rc = BLK_EH_RESET_TIMER;
@@ -1977,6 +1985,43 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
                goto done;
        }
 
+       for (i = 0; i < conn->session->cmds_max; i++) {
+               running_task = conn->session->cmds[i];
+               if (!running_task->sc || running_task == task ||
+                    running_task->state != ISCSI_TASK_RUNNING)
+                       continue;
+
+               /*
+                * Only check if cmds started before this one have made
+                * progress, or this could never fail
+                */
+               if (time_after(running_task->sc->jiffies_at_alloc,
+                              task->sc->jiffies_at_alloc))
+                       continue;
+
+               if (time_after(running_task->last_xfer, task->last_timeout)) {
+                       /*
+                        * This task has not made progress, but a task
+                        * started before us has transferred data since
+                        * we started/last-checked. We could be queueing
+                        * too many tasks or the LU is bad.
+                        *
+                        * If the device is bad the cmds ahead of us on
+                        * other devs will complete, and this loop will
+                        * eventually fail starting the scsi eh.
+                        */
+                       ISCSI_DBG_EH(session, "Command has not made progress "
+                                    "but commands ahead of it have. "
+                                    "Asking scsi-ml for more time to "
+                                    "complete. Our last xfer vs running task "
+                                    "last xfer %lu/%lu. Last check %lu.\n",
+                                    task->last_xfer, running_task->last_xfer,
+                                    task->last_timeout);
+                       rc = BLK_EH_RESET_TIMER;
+                       goto done;
+               }
+       }
+
        /* Assumes nop timeout is shorter than scsi cmd timeout */
        if (task->have_checked_conn)
                goto done;
@@ -2461,7 +2506,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
        if (q->pool == NULL)
                return -ENOMEM;
 
-       kfifo_init(&q->queue, (void*)q->pool, max * sizeof(void*), NULL);
+       kfifo_init(&q->queue, (void*)q->pool, max * sizeof(void*));
 
        for (i = 0; i < max; i++) {
                q->pool[i] = kzalloc(item_size, GFP_KERNEL);
@@ -2469,7 +2514,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
                        q->max = i;
                        goto enomem;
                }
-               __kfifo_put(&q->queue, (void*)&q->pool[i], sizeof(void*));
+               kfifo_in(&q->queue, (void*)&q->pool[i], sizeof(void*));
        }
 
        if (items) {
@@ -2819,7 +2864,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
 
        /* allocate login_task used for the login/text sequences */
        spin_lock_bh(&session->lock);
-       if (!__kfifo_get(&session->cmdpool.queue,
+       if (!kfifo_out(&session->cmdpool.queue,
                          (void*)&conn->login_task,
                         sizeof(void*))) {
                spin_unlock_bh(&session->lock);
@@ -2839,7 +2884,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
        return cls_conn;
 
 login_task_data_alloc_fail:
-       __kfifo_put(&session->cmdpool.queue, (void*)&conn->login_task,
+       kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
                    sizeof(void*));
 login_task_alloc_fail:
        iscsi_destroy_conn(cls_conn);
@@ -2902,7 +2947,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
        free_pages((unsigned long) conn->data,
                   get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
        kfree(conn->persistent_address);
-       __kfifo_put(&session->cmdpool.queue, (void*)&conn->login_task,
+       kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
                    sizeof(void*));
        if (session->leadconn == conn)
                session->leadconn = NULL;