Merge branch 'master' into for_paulus
[linux-drm-fsl-dcu.git] / drivers / scsi / libiscsi.c
index c542d0e95e682ed4432baafb8f5a54770f2dbc58..7c75771c77ff4aa32559b0cfeab48626fe65d47e 100644 (file)
@@ -113,8 +113,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
         hdr->opcode = ISCSI_OP_SCSI_CMD;
         hdr->flags = ISCSI_ATTR_SIMPLE;
         int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
-        hdr->itt = ctask->itt | (conn->id << ISCSI_CID_SHIFT) |
-                         (session->age << ISCSI_AGE_SHIFT);
+        hdr->itt = build_itt(ctask->itt, conn->id, session->age);
         hdr->data_length = cpu_to_be32(sc->request_bufflen);
         hdr->cmdsn = cpu_to_be32(session->cmdsn);
         session->cmdsn++;
@@ -260,7 +259,7 @@ static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        }
 
        if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) {
-               int senselen;
+               uint16_t senselen;
 
                if (datalen < 2) {
 invalid_datalen:
@@ -270,12 +269,12 @@ invalid_datalen:
                        goto out;
                }
 
-               senselen = (data[0] << 8) | data[1];
+               senselen = be16_to_cpu(*(__be16 *)data);
                if (datalen < senselen)
                        goto invalid_datalen;
 
                memcpy(sc->sense_buffer, data + 2,
-                      min(senselen, SCSI_SENSE_BUFFERSIZE));
+                      min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
                debug_scsi("copied %d bytes of sense\n",
                           min(senselen, SCSI_SENSE_BUFFERSIZE));
        }
@@ -338,7 +337,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 
                if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
                        memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
-                       itt = rejected_pdu.itt & ISCSI_ITT_MASK;
+                       itt = get_itt(rejected_pdu.itt);
                        printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected "
                                "due to DataDigest error.\n", itt,
                                rejected_pdu.opcode);
@@ -367,10 +366,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        struct iscsi_mgmt_task *mtask;
        uint32_t itt;
 
-       if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG))
-               itt = hdr->itt & ISCSI_ITT_MASK;
+       if (hdr->itt != RESERVED_ITT)
+               itt = get_itt(hdr->itt);
        else
-               itt = hdr->itt;
+               itt = ~0U;
 
        if (itt < session->cmds_max) {
                ctask = session->cmds[itt];
@@ -440,7 +439,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                        iscsi_tmf_rsp(conn, hdr);
                        break;
                case ISCSI_OP_NOOP_IN:
-                       if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) {
+                       if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
                                rc = ISCSI_ERR_PROTO;
                                break;
                        }
@@ -457,7 +456,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                        rc = ISCSI_ERR_BAD_OPCODE;
                        break;
                }
-       } else if (itt == ISCSI_RESERVED_TAG) {
+       } else if (itt == ~0U) {
                rc = iscsi_check_assign_cmdsn(session,
                                             (struct iscsi_nopin*)hdr);
                if (rc)
@@ -470,7 +469,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                                break;
                        }
 
-                       if (hdr->ttt == ISCSI_RESERVED_TAG)
+                       if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
                                break;
 
                        if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
@@ -481,8 +480,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                        break;
                case ISCSI_OP_ASYNC_EVENT:
                        conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
-                       /* we need sth like iscsi_async_event_rsp() */
-                       rc = ISCSI_ERR_BAD_OPCODE;
+                       if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
+                               rc = ISCSI_ERR_CONN_FAILED;
                        break;
                default:
                        rc = ISCSI_ERR_BAD_OPCODE;
@@ -516,24 +515,24 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        struct iscsi_cmd_task *ctask;
        uint32_t itt;
 
-       if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
-               if ((hdr->itt & ISCSI_AGE_MASK) !=
+       if (hdr->itt != RESERVED_ITT) {
+               if (((__force u32)hdr->itt & ISCSI_AGE_MASK) !=
                    (session->age << ISCSI_AGE_SHIFT)) {
                        printk(KERN_ERR "iscsi: received itt %x expected "
-                               "session age (%x)\n", hdr->itt,
+                               "session age (%x)\n", (__force u32)hdr->itt,
                                session->age & ISCSI_AGE_MASK);
                        return ISCSI_ERR_BAD_ITT;
                }
 
-               if ((hdr->itt & ISCSI_CID_MASK) !=
+               if (((__force u32)hdr->itt & ISCSI_CID_MASK) !=
                    (conn->id << ISCSI_CID_SHIFT)) {
                        printk(KERN_ERR "iscsi: received itt %x, expected "
-                               "CID (%x)\n", hdr->itt, conn->id);
+                               "CID (%x)\n", (__force u32)hdr->itt, conn->id);
                        return ISCSI_ERR_BAD_ITT;
                }
-               itt = hdr->itt & ISCSI_ITT_MASK;
+               itt = get_itt(hdr->itt);
        } else
-               itt = hdr->itt;
+               itt = ~0U;
 
        if (itt < session->cmds_max) {
                ctask = session->cmds[itt];
@@ -578,6 +577,27 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_failure);
 
+static int iscsi_xmit_imm_task(struct iscsi_conn *conn)
+{
+       struct iscsi_hdr *hdr = conn->mtask->hdr;
+       int rc, was_logout = 0;
+
+       if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) {
+               conn->session->state = ISCSI_STATE_IN_RECOVERY;
+               iscsi_block_session(session_to_cls(conn->session));
+               was_logout = 1;
+       }
+       rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
+       if (rc)
+               return rc;
+
+       if (was_logout) {
+               set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+               return -ENODATA;
+       }
+       return 0;
+}
+
 /**
  * iscsi_data_xmit - xmit any command into the scheduled connection
  * @conn: iscsi connection
@@ -623,7 +643,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
                conn->ctask = NULL;
        }
        if (conn->mtask) {
-               rc = tt->xmit_mgmt_task(conn, conn->mtask);
+               rc = iscsi_xmit_imm_task(conn);
                if (rc)
                        goto again;
                /* done with this in-progress mtask */
@@ -638,7 +658,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
                        list_add_tail(&conn->mtask->running,
                                      &conn->mgmt_run_list);
                        spin_unlock_bh(&conn->session->lock);
-                       rc = tt->xmit_mgmt_task(conn, conn->mtask);
+                       rc = iscsi_xmit_imm_task(conn);
                        if (rc)
                                goto again;
                }
@@ -661,8 +681,6 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
                spin_unlock_bh(&conn->session->lock);
 
                rc = tt->xmit_cmd_task(conn, conn->ctask);
-               if (rc)
-                       goto again;
 
                spin_lock_bh(&conn->session->lock);
                __iscsi_put_ctask(conn->ctask);
@@ -700,9 +718,10 @@ again:
        return rc;
 }
 
-static void iscsi_xmitworker(void *data)
+static void iscsi_xmitworker(struct work_struct *work)
 {
-       struct iscsi_conn *conn = data;
+       struct iscsi_conn *conn =
+               container_of(work, struct iscsi_conn, xmitwork);
        int rc;
        /*
         * serialize Xmit worker on a per-connection basis.
@@ -778,6 +797,10 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
        }
 
        conn = session->leadconn;
+       if (!conn) {
+               reason = FAILURE_SESSION_FREED;
+               goto fault;
+       }
 
        if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask,
                         sizeof(void*))) {
@@ -872,9 +895,8 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        /*
         * pre-format CmdSN for outgoing PDU.
         */
-       if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
-               hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) |
-                          (session->age << ISCSI_AGE_SHIFT);
+       if (hdr->itt != RESERVED_ITT) {
+               hdr->itt = build_itt(mtask->itt, conn->id, session->age);
                nop->cmdsn = cpu_to_be32(session->cmdsn);
                if (conn->c_stage == ISCSI_CONN_STARTED &&
                    !(hdr->opcode & ISCSI_OP_IMMEDIATE))
@@ -952,13 +974,13 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc)
        if (session->state == ISCSI_STATE_TERMINATE) {
 failed:
                debug_scsi("failing host reset: session terminated "
-                          "[CID %d age %d]", conn->id, session->age);
+                          "[CID %d age %d]\n", conn->id, session->age);
                spin_unlock_bh(&session->lock);
                return FAILED;
        }
 
        if (sc->SCp.phase == session->age) {
-               debug_scsi("failing connection CID %d due to SCSI host reset",
+               debug_scsi("failing connection CID %d due to SCSI host reset\n",
                           conn->id);
                fail_session = 1;
        }
@@ -1031,7 +1053,8 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
                                     NULL, 0);
        if (rc) {
                iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-               debug_scsi("abort sent failure [itt 0x%x] %d", ctask->itt, rc);
+               debug_scsi("abort sent failure [itt 0x%x] %d\n", ctask->itt,
+                          rc);
                return rc;
        }
 
@@ -1039,7 +1062,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
 
        spin_lock_bh(&session->lock);
        ctask->mtask = (struct iscsi_mgmt_task *)
-                       session->mgmt_cmds[(hdr->itt & ISCSI_ITT_MASK) -
+                       session->mgmt_cmds[get_itt(hdr->itt) -
                                        ISCSI_MGMT_ITT_OFFSET];
 
        if (conn->tmabort_state == TMABORT_INITIAL) {
@@ -1048,7 +1071,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
                conn->tmabort_timer.function = iscsi_tmabort_timedout;
                conn->tmabort_timer.data = (unsigned long)ctask;
                add_timer(&conn->tmabort_timer);
-               debug_scsi("abort set timeout [itt 0x%x]", ctask->itt);
+               debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt);
        }
        spin_unlock_bh(&session->lock);
        mutex_unlock(&conn->xmitmutex);
@@ -1377,7 +1400,6 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
        }
 
        spin_lock_init(&session->lock);
-       INIT_LIST_HEAD(&session->connections);
 
        /* initialize immediate command pool */
        if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max,
@@ -1489,7 +1511,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
        if (conn->mgmtqueue == ERR_PTR(-ENOMEM))
                goto mgmtqueue_alloc_fail;
 
-       INIT_WORK(&conn->xmitwork, iscsi_xmitworker, conn);
+       INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
 
        /* allocate login_mtask used for the login/text sequences */
        spin_lock_bh(&session->lock);
@@ -1580,16 +1602,11 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
        kfree(conn->persistent_address);
        __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
                    sizeof(void*));
-       list_del(&conn->item);
-       if (list_empty(&session->connections))
+       if (session->leadconn == conn) {
                session->leadconn = NULL;
-       if (session->leadconn && session->leadconn == conn)
-               session->leadconn = container_of(session->connections.next,
-                       struct iscsi_conn, item);
-
-       if (session->leadconn == NULL)
                /* no connections exits.. reset sequencing */
                session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1;
+       }
        spin_unlock_bh(&session->lock);
 
        kfifo_free(conn->immqueue);
@@ -1777,32 +1794,12 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
                    struct iscsi_cls_conn *cls_conn, int is_leading)
 {
        struct iscsi_session *session = class_to_transport_session(cls_session);
-       struct iscsi_conn *tmp = ERR_PTR(-EEXIST), *conn = cls_conn->dd_data;
+       struct iscsi_conn *conn = cls_conn->dd_data;
 
-       /* lookup for existing connection */
        spin_lock_bh(&session->lock);
-       list_for_each_entry(tmp, &session->connections, item) {
-               if (tmp == conn) {
-                       if (conn->c_stage != ISCSI_CONN_STOPPED ||
-                           conn->stop_stage == STOP_CONN_TERM) {
-                               printk(KERN_ERR "iscsi: can't bind "
-                                      "non-stopped connection (%d:%d)\n",
-                                      conn->c_stage, conn->stop_stage);
-                               spin_unlock_bh(&session->lock);
-                               return -EIO;
-                       }
-                       break;
-               }
-       }
-       if (tmp != conn) {
-               /* bind new iSCSI connection to session */
-               conn->session = session;
-               list_add(&conn->item, &session->connections);
-       }
-       spin_unlock_bh(&session->lock);
-
        if (is_leading)
                session->leadconn = conn;
+       spin_unlock_bh(&session->lock);
 
        /*
         * Unblock xmitworker(), Login Phase will pass through.