diff options
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index a5168a67350..ff891543df2 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -76,6 +76,15 @@ static int iscsi_sna_lte(u32 n1, u32 n2) (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) { @@ -103,8 +112,7 @@ 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); } } } @@ -586,7 +594,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, goto free_task; } else - scsi_queue_work(conn->session->host, &conn->xmitwork); + iscsi_conn_queue_work(conn); return task; @@ -1160,7 +1168,7 @@ void iscsi_requeue_task(struct iscsi_task *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); @@ -1413,7 +1421,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) goto prepd_reject; } } else - scsi_queue_work(session->host, &conn->xmitwork); + iscsi_conn_queue_work(conn); session->queued_cmdsn++; spin_unlock(&session->lock); @@ -1631,9 +1639,12 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, 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); @@ -1641,7 +1652,7 @@ static void iscsi_start_tx(struct iscsi_conn *conn) { 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) @@ -2046,12 +2057,14 @@ EXPORT_SYMBOL_GPL(iscsi_host_add); * @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; @@ -2063,13 +2076,25 @@ struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht, 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); @@ -2101,6 +2126,8 @@ void iscsi_host_remove(struct Scsi_Host *shost) flush_signals(current); scsi_remove_host(shost); + if (ihost->workq) + destroy_workqueue(ihost->workq); } EXPORT_SYMBOL_GPL(iscsi_host_remove); |