]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - drivers/scsi/libiscsi.c
DRM: remove unused dev_class
[mirror_ubuntu-zesty-kernel.git] / drivers / scsi / libiscsi.c
index 553168ae44f1864c01a6f5cdc8508cc985fc7029..010c1b9b178cb5ae5ea0e9f54e3a631c210f0a7e 100644 (file)
@@ -137,6 +137,70 @@ static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
        return 0;
 }
 
+/*
+ * make an extended cdb AHS
+ */
+static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask)
+{
+       struct scsi_cmnd *cmd = ctask->sc;
+       unsigned rlen, pad_len;
+       unsigned short ahslength;
+       struct iscsi_ecdb_ahdr *ecdb_ahdr;
+       int rc;
+
+       ecdb_ahdr = iscsi_next_hdr(ctask);
+       rlen = cmd->cmd_len - ISCSI_CDB_SIZE;
+
+       BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb));
+       ahslength = rlen + sizeof(ecdb_ahdr->reserved);
+
+       pad_len = iscsi_padding(rlen);
+
+       rc = iscsi_add_hdr(ctask, sizeof(ecdb_ahdr->ahslength) +
+                          sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len);
+       if (rc)
+               return rc;
+
+       if (pad_len)
+               memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
+
+       ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
+       ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
+       ecdb_ahdr->reserved = 0;
+       memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen);
+
+       debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d "
+                  "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n",
+                  cmd->cmd_len, rlen, pad_len, ahslength, ctask->hdr_len);
+
+       return 0;
+}
+
+static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask)
+{
+       struct scsi_cmnd *sc = ctask->sc;
+       struct iscsi_rlength_ahdr *rlen_ahdr;
+       int rc;
+
+       rlen_ahdr = iscsi_next_hdr(ctask);
+       rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr));
+       if (rc)
+               return rc;
+
+       rlen_ahdr->ahslength =
+               cpu_to_be16(sizeof(rlen_ahdr->read_length) +
+                                                 sizeof(rlen_ahdr->reserved));
+       rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
+       rlen_ahdr->reserved = 0;
+       rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
+
+       debug_scsi("bidi-in rlen_ahdr->read_length(%d) "
+                  "rlen_ahdr->ahslength(%d)\n",
+                  be32_to_cpu(rlen_ahdr->read_length),
+                  be16_to_cpu(rlen_ahdr->ahslength));
+       return 0;
+}
+
 /**
  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
  * @ctask: iscsi cmd task
@@ -150,7 +214,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
        struct iscsi_session *session = conn->session;
        struct iscsi_cmd *hdr = ctask->hdr;
        struct scsi_cmnd *sc = ctask->sc;
-       unsigned hdrlength;
+       unsigned hdrlength, cmd_len;
        int rc;
 
        ctask->hdr_len = 0;
@@ -160,18 +224,31 @@ static int 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 = build_itt(ctask->itt, conn->id, session->age);
-       hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
+       hdr->itt = build_itt(ctask->itt, session->age);
        hdr->cmdsn = cpu_to_be32(session->cmdsn);
        session->cmdsn++;
        hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
-       memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
-       if (sc->cmd_len < MAX_COMMAND_SIZE)
-               memset(&hdr->cdb[sc->cmd_len], 0,
-                       MAX_COMMAND_SIZE - sc->cmd_len);
+       cmd_len = sc->cmd_len;
+       if (cmd_len < ISCSI_CDB_SIZE)
+               memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len);
+       else if (cmd_len > ISCSI_CDB_SIZE) {
+               rc = iscsi_prep_ecdb_ahs(ctask);
+               if (rc)
+                       return rc;
+               cmd_len = ISCSI_CDB_SIZE;
+       }
+       memcpy(hdr->cdb, sc->cmnd, cmd_len);
 
        ctask->imm_count = 0;
+       if (scsi_bidi_cmnd(sc)) {
+               hdr->flags |= ISCSI_FLAG_CMD_READ;
+               rc = iscsi_prep_bidi_ahs(ctask);
+               if (rc)
+                       return rc;
+       }
        if (sc->sc_data_direction == DMA_TO_DEVICE) {
+               unsigned out_len = scsi_out(sc)->length;
+               hdr->data_length = cpu_to_be32(out_len);
                hdr->flags |= ISCSI_FLAG_CMD_WRITE;
                /*
                 * Write counters:
@@ -192,19 +269,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
                ctask->unsol_datasn = 0;
 
                if (session->imm_data_en) {
-                       if (scsi_bufflen(sc) >= session->first_burst)
+                       if (out_len >= session->first_burst)
                                ctask->imm_count = min(session->first_burst,
                                                        conn->max_xmit_dlength);
                        else
-                               ctask->imm_count = min(scsi_bufflen(sc),
+                               ctask->imm_count = min(out_len,
                                                        conn->max_xmit_dlength);
                        hton24(hdr->dlength, ctask->imm_count);
                } else
                        zero_data(hdr->dlength);
 
                if (!session->initial_r2t_en) {
-                       ctask->unsol_count = min((session->first_burst),
-                               (scsi_bufflen(sc))) - ctask->imm_count;
+                       ctask->unsol_count = min(session->first_burst, out_len)
+                                                            - ctask->imm_count;
                        ctask->unsol_offset = ctask->imm_count;
                }
 
@@ -214,6 +291,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
        } else {
                hdr->flags |= ISCSI_FLAG_CMD_FINAL;
                zero_data(hdr->dlength);
+               hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
 
                if (sc->sc_data_direction == DMA_FROM_DEVICE)
                        hdr->flags |= ISCSI_FLAG_CMD_READ;
@@ -232,10 +310,12 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
                return EIO;
 
        conn->scsicmd_pdus_cnt++;
-       debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
-               "cmdsn %d win %d]\n",
-               sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
-               conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
+       debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x "
+               "len %d bidi_len %d cmdsn %d win %d]\n",
+               scsi_bidi_cmnd(sc) ? "bidirectional" :
+                    sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+               conn->id, sc, sc->cmnd[0], ctask->itt,
+               scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
                session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
        return 0;
 }
@@ -298,7 +378,12 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
                conn->session->tt->cleanup_cmd_task(conn, ctask);
 
        sc->result = err;
-       scsi_set_resid(sc, scsi_bufflen(sc));
+       if (!scsi_bidi_cmnd(sc))
+               scsi_set_resid(sc, scsi_bufflen(sc));
+       else {
+               scsi_out(sc)->resid = scsi_out(sc)->length;
+               scsi_in(sc)->resid = scsi_in(sc)->length;
+       }
        if (conn->ctask == ctask)
                conn->ctask = NULL;
        /* release ref from queuecommand */
@@ -416,8 +501,9 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 
                if (datalen < 2) {
 invalid_datalen:
-                       printk(KERN_ERR "iscsi: Got CHECK_CONDITION but "
-                              "invalid data buffer size of %d\n", datalen);
+                       iscsi_conn_printk(KERN_ERR,  conn,
+                                        "Got CHECK_CONDITION but invalid data "
+                                        "buffer size of %d\n", datalen);
                        sc->result = DID_BAD_TARGET << 16;
                        goto out;
                }
@@ -432,6 +518,18 @@ invalid_datalen:
                           min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
        }
 
+       if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
+                          ISCSI_FLAG_CMD_BIDI_OVERFLOW)) {
+               int res_count = be32_to_cpu(rhdr->bi_residual_count);
+
+               if (scsi_bidi_cmnd(sc) && res_count > 0 &&
+                               (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
+                                res_count <= scsi_in(sc)->length))
+                       scsi_in(sc)->resid = res_count;
+               else
+                       sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
+       }
+
        if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW |
                           ISCSI_FLAG_CMD_OVERFLOW)) {
                int res_count = be32_to_cpu(rhdr->residual_count);
@@ -439,13 +537,11 @@ invalid_datalen:
                if (res_count > 0 &&
                    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
                     res_count <= scsi_bufflen(sc)))
+                       /* write side for bidi or uni-io set_resid */
                        scsi_set_resid(sc, res_count);
                else
                        sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
-       } else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
-                                 ISCSI_FLAG_CMD_BIDI_OVERFLOW))
-               sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
-
+       }
 out:
        debug_scsi("done [sc %lx res %d itt 0x%x]\n",
                   (long)sc, sc->result, ctask->itt);
@@ -494,7 +590,7 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
 
        mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
        if (!mtask) {
-               printk(KERN_ERR "Could not send nopout\n");
+               iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
                return;
        }
 
@@ -522,9 +618,10 @@ 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 = 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);
+                       iscsi_conn_printk(KERN_ERR, conn,
+                                         "itt 0x%x had pdu (op 0x%x) rejected "
+                                         "due to DataDigest error.\n", itt,
+                                         rejected_pdu.opcode);
                }
        }
        return 0;
@@ -541,8 +638,8 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
  * queuecommand or send generic. session lock must be held and verify
  * itt must have been called.
  */
-int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
-                        char *data, int datalen)
+static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+                               char *data, int datalen)
 {
        struct iscsi_session *session = conn->session;
        int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0;
@@ -672,7 +769,6 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 
        return rc;
 }
-EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
 
 int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                       char *data, int datalen)
@@ -697,18 +793,13 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        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", (__force u32)hdr->itt,
-                               session->age & ISCSI_AGE_MASK);
+                       iscsi_conn_printk(KERN_ERR, conn,
+                                         "received itt %x expected session "
+                                         "age (%x)\n", (__force u32)hdr->itt,
+                                         session->age & ISCSI_AGE_MASK);
                        return ISCSI_ERR_BAD_ITT;
                }
 
-               if (((__force u32)hdr->itt & ISCSI_CID_MASK) !=
-                   (conn->id << ISCSI_CID_SHIFT)) {
-                       printk(KERN_ERR "iscsi: received itt %x, expected "
-                               "CID (%x)\n", (__force u32)hdr->itt, conn->id);
-                       return ISCSI_ERR_BAD_ITT;
-               }
                itt = get_itt(hdr->itt);
        } else
                itt = ~0U;
@@ -717,16 +808,17 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                ctask = session->cmds[itt];
 
                if (!ctask->sc) {
-                       printk(KERN_INFO "iscsi: dropping ctask with "
-                              "itt 0x%x\n", ctask->itt);
+                       iscsi_conn_printk(KERN_INFO, conn, "dropping ctask "
+                                         "with itt 0x%x\n", ctask->itt);
                        /* force drop */
                        return ISCSI_ERR_NO_SCSI_CMD;
                }
 
                if (ctask->sc->SCp.phase != session->age) {
-                       printk(KERN_ERR "iscsi: ctask's session age %d, "
-                               "expected %d\n", ctask->sc->SCp.phase,
-                               session->age);
+                       iscsi_conn_printk(KERN_ERR, conn,
+                                         "iscsi: ctask's session age %d, "
+                                         "expected %d\n", ctask->sc->SCp.phase,
+                                         session->age);
                        return ISCSI_ERR_SESSION_FAILED;
                }
        }
@@ -771,7 +863,7 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn,
         */
        nop->cmdsn = cpu_to_be32(session->cmdsn);
        if (hdr->itt != RESERVED_ITT) {
-               hdr->itt = build_itt(mtask->itt, conn->id, session->age);
+               hdr->itt = build_itt(mtask->itt, session->age);
                /*
                 * TODO: We always use immediate, so we never hit this.
                 * If we start to send tmfs or nops as non-immediate then
@@ -997,6 +1089,7 @@ enum {
        FAILURE_SESSION_IN_RECOVERY,
        FAILURE_SESSION_RECOVERY_TIMEOUT,
        FAILURE_SESSION_LOGGING_OUT,
+       FAILURE_SESSION_NOT_READY,
 };
 
 int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
@@ -1017,6 +1110,12 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
        session = iscsi_hostdata(host->hostdata);
        spin_lock(&session->lock);
 
+       reason = iscsi_session_chkready(session_to_cls(session));
+       if (reason) {
+               sc->result = reason;
+               goto fault;
+       }
+
        /*
         * ISCSI_STATE_FAILED is a temp. state. The recovery
         * code will decide what is best to do with command queued
@@ -1033,18 +1132,23 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
                switch (session->state) {
                case ISCSI_STATE_IN_RECOVERY:
                        reason = FAILURE_SESSION_IN_RECOVERY;
-                       goto reject;
+                       sc->result = DID_IMM_RETRY << 16;
+                       break;
                case ISCSI_STATE_LOGGING_OUT:
                        reason = FAILURE_SESSION_LOGGING_OUT;
-                       goto reject;
+                       sc->result = DID_IMM_RETRY << 16;
+                       break;
                case ISCSI_STATE_RECOVERY_FAILED:
                        reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
+                       sc->result = DID_NO_CONNECT << 16;
                        break;
                case ISCSI_STATE_TERMINATE:
                        reason = FAILURE_SESSION_TERMINATE;
+                       sc->result = DID_NO_CONNECT << 16;
                        break;
                default:
                        reason = FAILURE_SESSION_FREED;
+                       sc->result = DID_NO_CONNECT << 16;
                }
                goto fault;
        }
@@ -1052,6 +1156,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
        conn = session->leadconn;
        if (!conn) {
                reason = FAILURE_SESSION_FREED;
+               sc->result = DID_NO_CONNECT << 16;
                goto fault;
        }
 
@@ -1091,10 +1196,13 @@ reject:
 
 fault:
        spin_unlock(&session->lock);
-       printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n",
-              sc->cmnd[0], reason);
-       sc->result = (DID_NO_CONNECT << 16);
-       scsi_set_resid(sc, scsi_bufflen(sc));
+       debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
+       if (!scsi_bidi_cmnd(sc))
+               scsi_set_resid(sc, scsi_bufflen(sc));
+       else {
+               scsi_out(sc)->resid = scsi_out(sc)->length;
+               scsi_in(sc)->resid = scsi_in(sc)->length;
+       }
        sc->scsi_done(sc);
        spin_lock(host->host_lock);
        return 0;
@@ -1160,7 +1268,8 @@ failed:
        mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->lock);
        if (session->state == ISCSI_STATE_LOGGED_IN)
-               printk(KERN_INFO "iscsi: host reset succeeded\n");
+               iscsi_session_printk(KERN_INFO, session,
+                                    "host reset succeeded\n");
        else
                goto failed;
        spin_unlock_bh(&session->lock);
@@ -1239,7 +1348,8 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
  * Fail commands. session lock held and recv side suspended and xmit
  * thread flushed
  */
-static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)
+static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
+                             int error)
 {
        struct iscsi_cmd_task *ctask, *tmp;
 
@@ -1251,7 +1361,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)
                if (lun == ctask->sc->device->lun || lun == -1) {
                        debug_scsi("failing pending sc %p itt 0x%x\n",
                                   ctask->sc, ctask->itt);
-                       fail_command(conn, ctask, DID_BUS_BUSY << 16);
+                       fail_command(conn, ctask, error << 16);
                }
        }
 
@@ -1259,7 +1369,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)
                if (lun == ctask->sc->device->lun || lun == -1) {
                        debug_scsi("failing requeued sc %p itt 0x%x\n",
                                   ctask->sc, ctask->itt);
-                       fail_command(conn, ctask, DID_BUS_BUSY << 16);
+                       fail_command(conn, ctask, error << 16);
                }
        }
 
@@ -1357,10 +1467,10 @@ static void iscsi_check_transport_timeouts(unsigned long data)
        last_recv = conn->last_recv;
        if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ),
                           jiffies)) {
-               printk(KERN_ERR "ping timeout of %d secs expired, "
-                      "last rx %lu, last ping %lu, now %lu\n",
-                      conn->ping_timeout, last_recv,
-                      conn->last_ping, jiffies);
+               iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs "
+                                 "expired, last rx %lu, last ping %lu, "
+                                 "now %lu\n", conn->ping_timeout, last_recv,
+                                 conn->last_ping, jiffies);
                spin_unlock(&session->lock);
                iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
                return;
@@ -1373,14 +1483,11 @@ static void iscsi_check_transport_timeouts(unsigned long data)
                        iscsi_send_nopout(conn, NULL);
                }
                next_timeout = last_recv + timeout + (conn->ping_timeout * HZ);
-       } else {
+       } else
                next_timeout = last_recv + timeout;
-       }
 
-       if (next_timeout) {
-               debug_scsi("Setting next tmo %lu\n", next_timeout);
-               mod_timer(&conn->transport_timer, next_timeout);
-       }
+       debug_scsi("Setting next tmo %lu\n", next_timeout);
+       mod_timer(&conn->transport_timer, next_timeout);
 done:
        spin_unlock(&session->lock);
 }
@@ -1573,7 +1680,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
        /* need to grab the recv lock then session lock */
        write_lock_bh(conn->recv_lock);
        spin_lock(&session->lock);
-       fail_all_commands(conn, sc->device->lun);
+       fail_all_commands(conn, sc->device->lun, DID_ERROR);
        conn->tmf_state = TMF_INITIAL;
        spin_unlock(&session->lock);
        write_unlock_bh(conn->recv_lock);
@@ -1701,8 +1808,8 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
                qdepth = ISCSI_DEF_CMD_PER_LUN;
        }
 
-       if (!is_power_of_2(cmds_max) ||
-           cmds_max >= ISCSI_MGMT_ITT_OFFSET) {
+       if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET ||
+           cmds_max < 2) {
                if (cmds_max != 0)
                        printk(KERN_ERR "iscsi: invalid can_queue of %d. "
                               "can_queue must be a power of 2 and between "
@@ -1944,9 +2051,10 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
                }
                spin_unlock_irqrestore(session->host->host_lock, flags);
                msleep_interruptible(500);
-               printk(KERN_INFO "iscsi: scsi conn_destroy(): host_busy %d "
-                      "host_failed %d\n", session->host->host_busy,
-                      session->host->host_failed);
+               iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): "
+                                 "host_busy %d host_failed %d\n",
+                                 session->host->host_busy,
+                                 session->host->host_failed);
                /*
                 * force eh_abort() to unblock
                 */
@@ -1975,27 +2083,28 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
        struct iscsi_session *session = conn->session;
 
        if (!session) {
-               printk(KERN_ERR "iscsi: can't start unbound connection\n");
+               iscsi_conn_printk(KERN_ERR, conn,
+                                 "can't start unbound connection\n");
                return -EPERM;
        }
 
        if ((session->imm_data_en || !session->initial_r2t_en) &&
             session->first_burst > session->max_burst) {
-               printk("iscsi: invalid burst lengths: "
-                      "first_burst %d max_burst %d\n",
-                      session->first_burst, session->max_burst);
+               iscsi_conn_printk(KERN_INFO, conn, "invalid burst lengths: "
+                                 "first_burst %d max_burst %d\n",
+                                 session->first_burst, session->max_burst);
                return -EINVAL;
        }
 
        if (conn->ping_timeout && !conn->recv_timeout) {
-               printk(KERN_ERR "iscsi: invalid recv timeout of zero "
-                     "Using 5 seconds\n.");
+               iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of "
+                                 "zero. Using 5 seconds\n.");
                conn->recv_timeout = 5;
        }
 
        if (conn->recv_timeout && !conn->ping_timeout) {
-               printk(KERN_ERR "iscsi: invalid ping timeout of zero "
-                     "Using 5 seconds.\n");
+               iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of "
+                                 "zero. Using 5 seconds.\n");
                conn->ping_timeout = 5;
        }
 
@@ -2019,11 +2128,9 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
                conn->stop_stage = 0;
                conn->tmf_state = TMF_INITIAL;
                session->age++;
-               spin_unlock_bh(&session->lock);
-
-               iscsi_unblock_session(session_to_cls(session));
-               wake_up(&conn->ehwait);
-               return 0;
+               if (session->age == 16)
+                       session->age = 0;
+               break;
        case STOP_CONN_TERM:
                conn->stop_stage = 0;
                break;
@@ -2032,6 +2139,8 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
        }
        spin_unlock_bh(&session->lock);
 
+       iscsi_unblock_session(session_to_cls(session));
+       wake_up(&conn->ehwait);
        return 0;
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_start);
@@ -2123,7 +2232,8 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
         * flush queues.
         */
        spin_lock_bh(&session->lock);
-       fail_all_commands(conn, -1);
+       fail_all_commands(conn, -1,
+                       STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR);
        flush_control_queues(session, conn);
        spin_unlock_bh(&session->lock);
        mutex_unlock(&session->eh_mutex);
@@ -2140,7 +2250,8 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
                iscsi_start_session_recovery(session, conn, flag);
                break;
        default:
-               printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);
+               iscsi_conn_printk(KERN_ERR, conn,
+                                 "invalid stop flag %d\n", flag);
        }
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_stop);