(n1 > n2 && (n2 - n1 < SNA32_CHECK)));
 }
 
+inline void iscsi_conn_queue_work(struct iscsi_conn *conn)
+{
+       struct Scsi_Host *shost = conn->session->host;
+       struct iscsi_host *ihost = shost_priv(shost);
+
+       queue_work(ihost->workq, &conn->xmitwork);
+}
+EXPORT_SYMBOL_GPL(iscsi_conn_queue_work);
+
 void
 iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
 {
                if (!list_empty(&session->leadconn->xmitqueue) ||
                    !list_empty(&session->leadconn->mgmtqueue)) {
                        if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD))
-                               scsi_queue_work(session->host,
-                                               &session->leadconn->xmitwork);
+                               iscsi_conn_queue_work(session->leadconn);
                }
        }
 }
                        goto free_task;
 
        } else
-               scsi_queue_work(conn->session->host, &conn->xmitwork);
+               iscsi_conn_queue_work(conn);
 
        return task;
 
        struct iscsi_conn *conn = task->conn;
 
        list_move_tail(&task->running, &conn->requeue);
-       scsi_queue_work(conn->session->host, &conn->xmitwork);
+       iscsi_conn_queue_work(conn);
 }
 EXPORT_SYMBOL_GPL(iscsi_requeue_task);
 
                        goto prepd_reject;
                }
        } else
-               scsi_queue_work(session->host, &conn->xmitwork);
+               iscsi_conn_queue_work(conn);
 
        session->queued_cmdsn++;
        spin_unlock(&session->lock);
 
 void iscsi_suspend_tx(struct iscsi_conn *conn)
 {
+       struct Scsi_Host *shost = conn->session->host;
+       struct iscsi_host *ihost = shost_priv(shost);
+
        set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
        if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
-               scsi_flush_work(conn->session->host);
+               flush_workqueue(ihost->workq);
 }
 EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
 
 {
        clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
        if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
-               scsi_queue_work(conn->session->host, &conn->xmitwork);
+               iscsi_conn_queue_work(conn);
 }
 
 static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
  * @sht: scsi host template
  * @dd_data_size: driver host data size
  * @qdepth: default device queue depth
+ * @xmit_can_sleep: bool indicating if LLD will queue IO from a work queue
  *
  * This should be called by partial offload and software iscsi drivers.
  * To access the driver specific memory use the iscsi_host_priv() macro.
  */
 struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
-                                  int dd_data_size, uint16_t qdepth)
+                                  int dd_data_size, uint16_t qdepth,
+                                  bool xmit_can_sleep)
 {
        struct Scsi_Host *shost;
        struct iscsi_host *ihost;
        if (qdepth == 0)
                qdepth = ISCSI_DEF_CMD_PER_LUN;
        shost->cmd_per_lun = qdepth;
-
        ihost = shost_priv(shost);
+
+       if (xmit_can_sleep) {
+               snprintf(ihost->workq_name, sizeof(ihost->workq_name),
+                       "iscsi_q_%d", shost->host_no);
+               ihost->workq = create_singlethread_workqueue(ihost->workq_name);
+               if (!ihost->workq)
+                       goto free_host;
+       }
+
        spin_lock_init(&ihost->lock);
        ihost->state = ISCSI_HOST_SETUP;
        ihost->num_sessions = 0;
        init_waitqueue_head(&ihost->session_removal_wq);
        return shost;
+
+free_host:
+       scsi_host_put(shost);
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(iscsi_host_alloc);
 
                flush_signals(current);
 
        scsi_remove_host(shost);
+       if (ihost->workq)
+               destroy_workqueue(ihost->workq);
 }
 EXPORT_SYMBOL_GPL(iscsi_host_remove);
 
 
        spinlock_t              lock;
        int                     num_sessions;
        int                     state;
+
+       struct workqueue_struct *workq;
+       char                    workq_name[20];
 };
 
 /*
                                enum iscsi_host_param param, char *buf);
 extern int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev);
 extern struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
-                                         int dd_data_size, uint16_t qdepth);
+                                         int dd_data_size, uint16_t qdepth,
+                                         bool xmit_can_sleep);
 extern void iscsi_host_remove(struct Scsi_Host *shost);
 extern void iscsi_host_free(struct Scsi_Host *shost);
 
 extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
                                enum iscsi_param param, char *buf);
 extern void iscsi_suspend_tx(struct iscsi_conn *conn);
+extern void iscsi_conn_queue_work(struct iscsi_conn *conn);
 
 #define iscsi_conn_printk(prefix, _c, fmt, a...) \
        iscsi_cls_conn_printk(prefix, ((struct iscsi_conn *)_c)->cls_conn, \