mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-18 13:16:34 +00:00
Changes:
- Fixed race condition between SCST session registration and IB channel event handler in srpt_add_one(): at least in theory it was possible that sdev->scst_tgt was accessed before being initialized properly. - A kernel WARN_ON() is no longer triggered when a DREQ has been received after SCST session deregistration started. - Made sure that srpt_unmap_sg_to_ib_sge() does not call ib_dma_unmap_sg() twice. - Moved srpt_unmap_sg_to_ib_sge() call out of srpt_reset_ioctx() and srpt_abort_scst_cmd() into the callers of these functions. - Renamed some of the SRPT command states. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1505 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
+193
-156
@@ -696,7 +696,17 @@ static void srpt_free_ioctx_ring(struct srpt_device *sdev,
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state of a command.
|
||||
* srpt_get_cmd_state() - Get the state of a SCSI command.
|
||||
*/
|
||||
static enum srpt_command_state srpt_get_cmd_state(struct srpt_ioctx *ioctx)
|
||||
{
|
||||
BUG_ON(!ioctx);
|
||||
|
||||
return atomic_read(&ioctx->state);
|
||||
}
|
||||
|
||||
/**
|
||||
* srpt_set_cmd_state() - Set the state of a SCSI command.
|
||||
* @new: New state to be set.
|
||||
*
|
||||
* Does not modify the state of aborted commands. Returns the previous command
|
||||
@@ -707,12 +717,12 @@ static enum srpt_command_state srpt_set_cmd_state(struct srpt_ioctx *ioctx,
|
||||
{
|
||||
enum srpt_command_state previous;
|
||||
|
||||
WARN_ON(!ioctx);
|
||||
BUG_ON(!ioctx);
|
||||
WARN_ON(new == SRPT_STATE_NEW);
|
||||
|
||||
do {
|
||||
previous = atomic_read(&ioctx->state);
|
||||
} while (previous != SRPT_STATE_ABORTED
|
||||
} while (previous != SRPT_STATE_DONE
|
||||
&& atomic_cmpxchg(&ioctx->state, previous, new) != previous);
|
||||
|
||||
return previous;
|
||||
@@ -731,7 +741,7 @@ srpt_test_and_set_cmd_state(struct srpt_ioctx *ioctx,
|
||||
enum srpt_command_state new)
|
||||
{
|
||||
WARN_ON(!ioctx);
|
||||
WARN_ON(old == SRPT_STATE_ABORTED);
|
||||
WARN_ON(old == SRPT_STATE_DONE);
|
||||
WARN_ON(new == SRPT_STATE_NEW);
|
||||
|
||||
return atomic_cmpxchg(&ioctx->state, old, new);
|
||||
@@ -1016,17 +1026,15 @@ static int srpt_req_lim_delta(struct srpt_rdma_ch *ch)
|
||||
|
||||
static void srpt_reset_ioctx(struct srpt_rdma_ch *ch, struct srpt_ioctx *ioctx)
|
||||
{
|
||||
srpt_unmap_sg_to_ib_sge(ch, ioctx);
|
||||
BUG_ON(!ch);
|
||||
BUG_ON(!ioctx);
|
||||
|
||||
if (ioctx->n_rbuf > 1) {
|
||||
kfree(ioctx->rbufs);
|
||||
ioctx->rbufs = NULL;
|
||||
ioctx->n_rbuf = 0;
|
||||
}
|
||||
|
||||
WARN_ON(!ch);
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
if (srpt_post_recv(ch->sport->sdev, ioctx))
|
||||
PRINT_ERROR("%s", "SRQ post_recv failed - this is serious.");
|
||||
/* we should queue it back to free_ioctx queue */
|
||||
@@ -1041,51 +1049,50 @@ static void srpt_reset_ioctx(struct srpt_rdma_ch *ch, struct srpt_ioctx *ioctx)
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort a command.
|
||||
* srpt_abort_scst_cmd() - Abort a SCSI command.
|
||||
*/
|
||||
static void srpt_abort_scst_cmd(struct srpt_device *sdev,
|
||||
struct scst_cmd *scmnd,
|
||||
static void srpt_abort_scst_cmd(struct srpt_ioctx *ioctx,
|
||||
enum scst_exec_context context)
|
||||
{
|
||||
struct srpt_ioctx *ioctx;
|
||||
scst_data_direction dir;
|
||||
enum srpt_command_state previous_state;
|
||||
struct scst_cmd *scmnd;
|
||||
enum srpt_command_state state;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
ioctx = scst_cmd_get_tgt_priv(scmnd);
|
||||
BUG_ON(!ioctx);
|
||||
|
||||
previous_state = srpt_set_cmd_state(ioctx, SRPT_STATE_ABORTED);
|
||||
if (previous_state == SRPT_STATE_ABORTED)
|
||||
state = srpt_set_cmd_state(ioctx, SRPT_STATE_DONE);
|
||||
if (state == SRPT_STATE_DONE)
|
||||
goto out;
|
||||
|
||||
scmnd = ioctx->scmnd;
|
||||
WARN_ON(!scmnd);
|
||||
if (!scmnd)
|
||||
goto out;
|
||||
|
||||
WARN_ON(ioctx != scst_cmd_get_tgt_priv(scmnd));
|
||||
|
||||
TRACE_DBG("Aborting cmd with state %d and tag %lld",
|
||||
previous_state, scst_cmd_get_tag(scmnd));
|
||||
state, scst_cmd_get_tag(scmnd));
|
||||
|
||||
dir = scst_cmd_get_data_direction(scmnd);
|
||||
if (dir != SCST_DATA_NONE && scst_cmd_get_sg(scmnd))
|
||||
ib_dma_unmap_sg(sdev->device,
|
||||
scst_cmd_get_sg(scmnd),
|
||||
scst_cmd_get_sg_cnt(scmnd),
|
||||
scst_to_tgt_dma_dir(dir));
|
||||
|
||||
switch (previous_state) {
|
||||
switch (state) {
|
||||
case SRPT_STATE_NEW:
|
||||
scst_set_delivery_status(scmnd, SCST_CMD_DELIVERY_ABORTED);
|
||||
break;
|
||||
case SRPT_STATE_NEED_DATA:
|
||||
WARN_ON(scst_cmd_get_data_direction(ioctx->scmnd)
|
||||
== SCST_DATA_READ);
|
||||
scst_rx_data(scmnd, SCST_RX_STATUS_ERROR, context);
|
||||
break;
|
||||
case SRPT_STATE_DATA_IN:
|
||||
case SRPT_STATE_PROCESSED:
|
||||
case SRPT_STATE_CMD_RSP_SENT:
|
||||
scst_set_delivery_status(scmnd, SCST_CMD_DELIVERY_ABORTED);
|
||||
break;
|
||||
case SRPT_STATE_MGMT_RSP_SENT:
|
||||
WARN_ON(!"ERROR: srpt_abort_scst_cmd() has been called for"
|
||||
" a management command.");
|
||||
break;
|
||||
default:
|
||||
TRACE_DBG("Aborting cmd with state %d", previous_state);
|
||||
WARN_ON("ERROR: unexpected command state");
|
||||
WARN_ON(!"ERROR: unexpected command state");
|
||||
break;
|
||||
}
|
||||
scst_tgt_cmd_done(scmnd, context);
|
||||
|
||||
@@ -1101,14 +1108,17 @@ static void srpt_handle_err_comp(struct srpt_rdma_ch *ch, struct ib_wc *wc,
|
||||
struct srpt_ioctx *ioctx;
|
||||
struct srpt_device *sdev = ch->sport->sdev;
|
||||
|
||||
TRACE_DBG("%s:%d wr_id = %#llx.", __func__, __LINE__, wc->wr_id);
|
||||
|
||||
if (wc->wr_id & SRPT_OP_RECV) {
|
||||
ioctx = sdev->ioctx_ring[wc->wr_id & ~SRPT_OP_RECV];
|
||||
PRINT_ERROR("%s", "This is serious - SRQ is in bad state.");
|
||||
} else {
|
||||
ioctx = sdev->ioctx_ring[wc->wr_id];
|
||||
|
||||
srpt_unmap_sg_to_ib_sge(ch, ioctx);
|
||||
if (ioctx->scmnd)
|
||||
srpt_abort_scst_cmd(sdev, ioctx->scmnd, context);
|
||||
srpt_abort_scst_cmd(ioctx, context);
|
||||
else
|
||||
srpt_reset_ioctx(ch, ioctx);
|
||||
}
|
||||
@@ -1119,16 +1129,20 @@ static void srpt_handle_send_comp(struct srpt_rdma_ch *ch,
|
||||
struct srpt_ioctx *ioctx,
|
||||
enum scst_exec_context context)
|
||||
{
|
||||
if (ioctx->scmnd) {
|
||||
scst_data_direction dir =
|
||||
scst_cmd_get_data_direction(ioctx->scmnd);
|
||||
enum srpt_command_state state;
|
||||
struct scst_cmd *scmnd;
|
||||
|
||||
if (dir != SCST_DATA_NONE && scst_cmd_get_sg(ioctx->scmnd))
|
||||
ib_dma_unmap_sg(ch->sport->sdev->device,
|
||||
scst_cmd_get_sg(ioctx->scmnd),
|
||||
scst_cmd_get_sg_cnt(ioctx->scmnd),
|
||||
scst_to_tgt_dma_dir(dir));
|
||||
scst_tgt_cmd_done(ioctx->scmnd, context);
|
||||
state = srpt_get_cmd_state(ioctx);
|
||||
scmnd = ioctx->scmnd;
|
||||
|
||||
WARN_ON(state != SRPT_STATE_CMD_RSP_SENT
|
||||
&& state != SRPT_STATE_MGMT_RSP_SENT);
|
||||
WARN_ON(state == SRPT_STATE_MGMT_RSP_SENT && scmnd);
|
||||
|
||||
if (scmnd) {
|
||||
srpt_unmap_sg_to_ib_sge(ch, ioctx);
|
||||
srpt_set_cmd_state(ioctx, SRPT_STATE_DONE);
|
||||
scst_tgt_cmd_done(scmnd, context);
|
||||
} else
|
||||
srpt_reset_ioctx(ch, ioctx);
|
||||
}
|
||||
@@ -1138,23 +1152,23 @@ static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch,
|
||||
struct srpt_ioctx *ioctx,
|
||||
enum scst_exec_context context)
|
||||
{
|
||||
if (!ioctx->scmnd) {
|
||||
WARN_ON("ERROR: ioctx->scmnd == NULL");
|
||||
srpt_reset_ioctx(ch, ioctx);
|
||||
return;
|
||||
}
|
||||
enum srpt_command_state state;
|
||||
struct scst_cmd *scmnd;
|
||||
|
||||
/*
|
||||
* If an RDMA completion notification has been received for a write
|
||||
* command, tell SCST that processing can continue by calling
|
||||
* scst_rx_data().
|
||||
*/
|
||||
if (srpt_test_and_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA,
|
||||
SRPT_STATE_DATA_IN) == SRPT_STATE_NEED_DATA) {
|
||||
WARN_ON(scst_cmd_get_data_direction(ioctx->scmnd)
|
||||
== SCST_DATA_READ);
|
||||
scmnd = ioctx->scmnd;
|
||||
WARN_ON(!scmnd);
|
||||
if (!scmnd)
|
||||
return;
|
||||
|
||||
state = srpt_test_and_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA,
|
||||
SRPT_STATE_DATA_IN);
|
||||
|
||||
WARN_ON(state != SRPT_STATE_NEED_DATA);
|
||||
|
||||
if (unlikely(scst_cmd_aborted(scmnd)))
|
||||
srpt_abort_scst_cmd(ioctx, context);
|
||||
else
|
||||
scst_rx_data(ioctx->scmnd, SCST_RX_STATUS_SUCCESS, context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1259,16 +1273,14 @@ static int srpt_build_tskmgmt_rsp(struct srpt_rdma_ch *ch,
|
||||
/*
|
||||
* Process SRP_CMD.
|
||||
*/
|
||||
static int srpt_handle_cmd(struct srpt_rdma_ch *ch, struct srpt_ioctx *ioctx)
|
||||
static int srpt_handle_cmd(struct srpt_rdma_ch *ch, struct srpt_ioctx *ioctx,
|
||||
enum scst_exec_context context)
|
||||
{
|
||||
struct scst_cmd *scmnd;
|
||||
struct srp_cmd *srp_cmd;
|
||||
scst_data_direction dir;
|
||||
u64 data_len;
|
||||
int ret;
|
||||
enum scst_exec_context context;
|
||||
|
||||
context = thread ? SCST_CONTEXT_THREAD : SCST_CONTEXT_TASKLET;
|
||||
|
||||
srp_cmd = ioctx->buf;
|
||||
|
||||
@@ -1424,57 +1436,58 @@ static void srpt_handle_new_iu(struct srpt_rdma_ch *ch,
|
||||
struct srpt_ioctx *ioctx)
|
||||
{
|
||||
struct srp_cmd *srp_cmd;
|
||||
struct scst_cmd *scmnd;
|
||||
enum rdma_ch_state ch_state;
|
||||
u8 srp_response_status;
|
||||
u8 srp_tsk_mgmt_status;
|
||||
int len;
|
||||
|
||||
/*
|
||||
* A quote from SAM-3, paragraph 4.9.6: "Any command that is not
|
||||
* relayed to a dependent logical unit shall be terminated with a
|
||||
* CHECK CONDITION status. The sense key shall be set to ILLEGAL
|
||||
* REQUEST and the additional sense code shall be set to INVALID
|
||||
* COMMAND OPERATION CODE. If a task management function cannot be
|
||||
* relayed to a dependent logical unit, a service response of SERVICE
|
||||
* DELIVERY OR TARGET FAILURE shall be returned."
|
||||
*/
|
||||
|
||||
srp_response_status = SAM_STAT_BUSY;
|
||||
/* To keep the compiler happy. */
|
||||
srp_tsk_mgmt_status = -1;
|
||||
int send_rsp_res;
|
||||
enum scst_exec_context context;
|
||||
|
||||
ch_state = atomic_read(&ch->state);
|
||||
if (ch_state == RDMA_CHANNEL_CONNECTING) {
|
||||
list_add_tail(&ioctx->wait_list, &ch->cmd_wait_list);
|
||||
return;
|
||||
} else if (ch_state == RDMA_CHANNEL_DISCONNECTING) {
|
||||
}
|
||||
|
||||
ioctx->n_rbuf = 0;
|
||||
ioctx->rbufs = NULL;
|
||||
ioctx->n_rdma = 0;
|
||||
ioctx->n_rdma_ius = 0;
|
||||
ioctx->rdma_ius = NULL;
|
||||
ioctx->mapped_sg_count = 0;
|
||||
ioctx->scmnd = NULL;
|
||||
ioctx->ch = ch;
|
||||
atomic_set(&ioctx->state, SRPT_STATE_NEW);
|
||||
|
||||
if (ch_state == RDMA_CHANNEL_DISCONNECTING) {
|
||||
srpt_reset_ioctx(ch, ioctx);
|
||||
return;
|
||||
}
|
||||
|
||||
WARN_ON(ch_state != RDMA_CHANNEL_LIVE);
|
||||
|
||||
context = thread ? SCST_CONTEXT_THREAD : SCST_CONTEXT_TASKLET;
|
||||
|
||||
scmnd = NULL;
|
||||
|
||||
srp_response_status = SAM_STAT_BUSY;
|
||||
/* To keep the compiler happy. */
|
||||
srp_tsk_mgmt_status = -1;
|
||||
|
||||
ib_dma_sync_single_for_cpu(ch->sport->sdev->device,
|
||||
ioctx->dma, srp_max_message_size,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
srp_cmd = ioctx->buf;
|
||||
|
||||
ioctx->n_rbuf = 0;
|
||||
ioctx->rbufs = NULL;
|
||||
ioctx->n_rdma = 0;
|
||||
ioctx->n_rdma_ius = 0;
|
||||
ioctx->rdma_ius = NULL;
|
||||
ioctx->scmnd = NULL;
|
||||
ioctx->ch = ch;
|
||||
atomic_set(&ioctx->state, SRPT_STATE_NEW);
|
||||
|
||||
switch (srp_cmd->opcode) {
|
||||
case SRP_CMD:
|
||||
if (srpt_handle_cmd(ch, ioctx) < 0) {
|
||||
if (ioctx->scmnd)
|
||||
if (srpt_handle_cmd(ch, ioctx, context) < 0) {
|
||||
scmnd = ioctx->scmnd;
|
||||
if (scmnd)
|
||||
srp_response_status =
|
||||
scst_cmd_get_status(ioctx->scmnd);
|
||||
scst_cmd_get_status(scmnd);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
@@ -1503,36 +1516,45 @@ static void srpt_handle_new_iu(struct srpt_rdma_ch *ch,
|
||||
return;
|
||||
|
||||
err:
|
||||
ch_state = atomic_read(&ch->state);
|
||||
if (ch_state != RDMA_CHANNEL_LIVE) {
|
||||
send_rsp_res = -ENOTCONN;
|
||||
|
||||
if (atomic_read(&ch->state) != RDMA_CHANNEL_LIVE) {
|
||||
/* Give up if another thread modified the channel state. */
|
||||
PRINT_ERROR("%s: channel is in state %d", __func__, ch_state);
|
||||
srpt_reset_ioctx(ch, ioctx);
|
||||
PRINT_ERROR("%s", "channel is no longer in connected state.");
|
||||
} else {
|
||||
s32 req_lim_delta;
|
||||
|
||||
req_lim_delta = srpt_req_lim_delta(ch) + 1;
|
||||
if (srp_cmd->opcode == SRP_TSK_MGMT) {
|
||||
if (srp_cmd->opcode == SRP_TSK_MGMT)
|
||||
len = srpt_build_tskmgmt_rsp(ch, ioctx, req_lim_delta,
|
||||
srp_tsk_mgmt_status,
|
||||
((struct srp_tsk_mgmt *)srp_cmd)->tag);
|
||||
} else if (ioctx->scmnd)
|
||||
else if (scmnd)
|
||||
len = srpt_build_cmd_rsp(ch, ioctx, req_lim_delta,
|
||||
srp_cmd->tag, srp_response_status,
|
||||
scst_cmd_get_sense_buffer(ioctx->scmnd),
|
||||
scst_cmd_get_sense_buffer_len(ioctx->scmnd));
|
||||
else {
|
||||
scst_cmd_get_sense_buffer(scmnd),
|
||||
scst_cmd_get_sense_buffer_len(scmnd));
|
||||
else
|
||||
len = srpt_build_cmd_rsp(ch, ioctx, srp_cmd->tag,
|
||||
req_lim_delta,
|
||||
srp_response_status,
|
||||
NULL, 0);
|
||||
}
|
||||
if (srpt_post_send(ch, ioctx, len)) {
|
||||
srpt_set_cmd_state(ioctx,
|
||||
srp_cmd->opcode == SRP_TSK_MGMT
|
||||
? SRPT_STATE_MGMT_RSP_SENT
|
||||
: SRPT_STATE_CMD_RSP_SENT);
|
||||
send_rsp_res = srpt_post_send(ch, ioctx, len);
|
||||
if (send_rsp_res) {
|
||||
PRINT_ERROR("%s", "Sending SRP_RSP response failed.");
|
||||
atomic_sub(req_lim_delta, &ch->last_response_req_lim);
|
||||
srpt_reset_ioctx(ch, ioctx);
|
||||
}
|
||||
}
|
||||
if (send_rsp_res) {
|
||||
if (scmnd)
|
||||
srpt_abort_scst_cmd(ioctx, context);
|
||||
else
|
||||
srpt_reset_ioctx(ch, ioctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2113,9 +2135,11 @@ static void srpt_cm_dreq_recv(struct ib_cm_id *cm_id)
|
||||
struct srpt_rdma_ch *ch;
|
||||
|
||||
ch = srpt_find_channel(cm_id->context, cm_id);
|
||||
WARN_ON(!ch);
|
||||
if (!ch)
|
||||
if (!ch) {
|
||||
TRACE_DBG("Received DREQ for channel %p which is already"
|
||||
" being unregistered.", cm_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
TRACE_DBG("cm_id= %p ch->state= %d", cm_id, atomic_read(&ch->state));
|
||||
|
||||
@@ -2206,15 +2230,20 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||||
int count, nrdma;
|
||||
int i, j, k;
|
||||
|
||||
BUG_ON(!ch);
|
||||
BUG_ON(!ioctx);
|
||||
BUG_ON(!scmnd);
|
||||
scat = scst_cmd_get_sg(scmnd);
|
||||
WARN_ON(!scat);
|
||||
dir = scst_cmd_get_data_direction(scmnd);
|
||||
WARN_ON(scat == NULL);
|
||||
count = ib_dma_map_sg(ch->sport->sdev->device, scat,
|
||||
scst_cmd_get_sg_cnt(scmnd),
|
||||
scst_to_tgt_dma_dir(dir));
|
||||
if (unlikely(!count))
|
||||
return -EBUSY;
|
||||
|
||||
ioctx->mapped_sg_count = count;
|
||||
|
||||
if (ioctx->rdma_ius && ioctx->n_rdma_ius)
|
||||
nrdma = ioctx->n_rdma_ius;
|
||||
else {
|
||||
@@ -2223,13 +2252,8 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||||
ioctx->rdma_ius = kzalloc(nrdma * sizeof *riu,
|
||||
scst_cmd_atomic(scmnd)
|
||||
? GFP_ATOMIC : GFP_KERNEL);
|
||||
if (!ioctx->rdma_ius) {
|
||||
WARN_ON(scat == NULL);
|
||||
ib_dma_unmap_sg(ch->sport->sdev->device,
|
||||
scat, scst_cmd_get_sg_cnt(scmnd),
|
||||
scst_to_tgt_dma_dir(dir));
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!ioctx->rdma_ius)
|
||||
goto free_mem;
|
||||
|
||||
ioctx->n_rdma_ius = nrdma;
|
||||
}
|
||||
@@ -2367,6 +2391,8 @@ static void srpt_unmap_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||||
struct scatterlist *scat;
|
||||
scst_data_direction dir;
|
||||
|
||||
BUG_ON(!ch);
|
||||
BUG_ON(!ioctx);
|
||||
BUG_ON(ioctx->n_rdma && !ioctx->rdma_ius);
|
||||
|
||||
while (ioctx->n_rdma)
|
||||
@@ -2375,16 +2401,19 @@ static void srpt_unmap_sg_to_ib_sge(struct srpt_rdma_ch *ch,
|
||||
kfree(ioctx->rdma_ius);
|
||||
ioctx->rdma_ius = NULL;
|
||||
|
||||
scmnd = ioctx->scmnd;
|
||||
if (scmnd) {
|
||||
BUG_ON(ioctx != scst_cmd_get_tgt_priv(scmnd));
|
||||
if (ioctx->mapped_sg_count) {
|
||||
scmnd = ioctx->scmnd;
|
||||
BUG_ON(!scmnd);
|
||||
WARN_ON(ioctx->scmnd != scmnd);
|
||||
WARN_ON(ioctx != scst_cmd_get_tgt_priv(scmnd));
|
||||
scat = scst_cmd_get_sg(scmnd);
|
||||
if (scat) {
|
||||
dir = scst_cmd_get_data_direction(scmnd);
|
||||
ib_dma_unmap_sg(ch->sport->sdev->device,
|
||||
scat, scst_cmd_get_sg_cnt(scmnd),
|
||||
scst_to_tgt_dma_dir(dir));
|
||||
}
|
||||
WARN_ON(!scat);
|
||||
dir = scst_cmd_get_data_direction(scmnd);
|
||||
WARN_ON(dir == SCST_DATA_NONE);
|
||||
ib_dma_unmap_sg(ch->sport->sdev->device, scat,
|
||||
scst_cmd_get_sg_cnt(scmnd),
|
||||
scst_to_tgt_dma_dir(dir));
|
||||
ioctx->mapped_sg_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2489,7 +2518,7 @@ static int srpt_rdy_to_xfer(struct scst_cmd *scmnd)
|
||||
BUG_ON(!ioctx);
|
||||
|
||||
WARN_ON(srpt_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA)
|
||||
== SRPT_STATE_ABORTED);
|
||||
== SRPT_STATE_DONE);
|
||||
|
||||
ch = ioctx->ch;
|
||||
WARN_ON(ch != scst_sess_get_tgt_priv(scst_cmd_get_session(scmnd)));
|
||||
@@ -2563,9 +2592,7 @@ static int srpt_xmit_response(struct scst_cmd *scmnd)
|
||||
if (unlikely(scst_cmd_aborted(scmnd))) {
|
||||
TRACE_DBG("cmd with tag %lld has been aborted",
|
||||
scst_cmd_get_tag(scmnd));
|
||||
srpt_abort_scst_cmd(ch->sport->sdev, scmnd,
|
||||
thread ? SCST_CONTEXT_THREAD
|
||||
: SCST_CONTEXT_TASKLET);
|
||||
srpt_abort_scst_cmd(ioctx, SCST_CONTEXT_SAME);
|
||||
ret = SCST_TGT_RES_SUCCESS;
|
||||
goto out;
|
||||
}
|
||||
@@ -2578,11 +2605,8 @@ static int srpt_xmit_response(struct scst_cmd *scmnd)
|
||||
|
||||
srpt_wait_for_cred(ch, 2);
|
||||
|
||||
if (srpt_set_cmd_state(ioctx, SRPT_STATE_PROCESSED)
|
||||
== SRPT_STATE_ABORTED) {
|
||||
ret = SCST_TGT_RES_SUCCESS;
|
||||
goto out;
|
||||
}
|
||||
WARN_ON(srpt_set_cmd_state(ioctx, SRPT_STATE_CMD_RSP_SENT)
|
||||
== SRPT_STATE_DONE);
|
||||
|
||||
dir = scst_cmd_get_data_direction(scmnd);
|
||||
|
||||
@@ -2608,6 +2632,9 @@ static int srpt_xmit_response(struct scst_cmd *scmnd)
|
||||
scst_cmd_get_sense_buffer_len(scmnd));
|
||||
|
||||
if (srpt_post_send(ch, ioctx, resp_len)) {
|
||||
srpt_set_cmd_state(ioctx, SRPT_STATE_DONE);
|
||||
scst_set_delivery_status(scmnd, SCST_CMD_DELIVERY_FAILED);
|
||||
scst_tgt_cmd_done(scmnd, SCST_CONTEXT_SAME);
|
||||
PRINT_ERROR("%s[%d]: ch->state= %d tag= %lld",
|
||||
__func__, __LINE__, atomic_read(&ch->state),
|
||||
(unsigned long long)scst_cmd_get_tag(scmnd));
|
||||
@@ -2650,9 +2677,8 @@ static void srpt_tsk_mgmt_done(struct scst_mgmt_cmd *mcmnd)
|
||||
|
||||
srpt_wait_for_cred(ch, 1);
|
||||
|
||||
if (srpt_set_cmd_state(ioctx, SRPT_STATE_PROCESSED)
|
||||
== SRPT_STATE_ABORTED)
|
||||
goto out;
|
||||
WARN_ON(srpt_set_cmd_state(ioctx, SRPT_STATE_MGMT_RSP_SENT)
|
||||
== SRPT_STATE_DONE);
|
||||
|
||||
req_lim_delta = srpt_req_lim_delta(ch) + 1;
|
||||
rsp_len = srpt_build_tskmgmt_rsp(ch, ioctx, req_lim_delta,
|
||||
@@ -2661,6 +2687,12 @@ static void srpt_tsk_mgmt_done(struct scst_mgmt_cmd *mcmnd)
|
||||
SRP_TSK_MGMT_SUCCESS :
|
||||
SRP_TSK_MGMT_FAILED,
|
||||
mgmt_ioctx->tag);
|
||||
/*
|
||||
* Note: the srpt_post_send() call below sends the task management
|
||||
* response asynchronously. It is possible that the SCST core has
|
||||
* already freed the struct scst_mgmt_cmd structure before the
|
||||
* response is sent. This is fine.
|
||||
*/
|
||||
if (srpt_post_send(ch, ioctx, rsp_len)) {
|
||||
PRINT_ERROR("%s", "Sending SRP_RSP response failed.");
|
||||
atomic_sub(req_lim_delta, &ch->last_response_req_lim);
|
||||
@@ -2669,9 +2701,6 @@ static void srpt_tsk_mgmt_done(struct scst_mgmt_cmd *mcmnd)
|
||||
scst_mgmt_cmd_set_tgt_priv(mcmnd, NULL);
|
||||
|
||||
kfree(mgmt_ioctx);
|
||||
|
||||
out:
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2686,14 +2715,23 @@ static void srpt_on_free_cmd(struct scst_cmd *scmnd)
|
||||
ioctx = scst_cmd_get_tgt_priv(scmnd);
|
||||
BUG_ON(!ioctx);
|
||||
|
||||
WARN_ON(srpt_get_cmd_state(ioctx) != SRPT_STATE_DONE);
|
||||
|
||||
/*
|
||||
* If the WARN_ON() below gets triggered this means that
|
||||
* srpt_unmap_sg_to_ib_sge() has not been called before
|
||||
* scst_tgt_cmd_done().
|
||||
*/
|
||||
WARN_ON(ioctx->mapped_sg_count);
|
||||
|
||||
ch = ioctx->ch;
|
||||
BUG_ON(!ch);
|
||||
|
||||
srpt_reset_ioctx(ch, ioctx);
|
||||
|
||||
scst_cmd_set_tgt_priv(scmnd, NULL);
|
||||
srpt_set_cmd_state(ioctx, SRPT_STATE_ABORTED);
|
||||
ioctx->scmnd = NULL;
|
||||
ioctx->ch = NULL;
|
||||
srpt_reset_ioctx(ch, ioctx);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) && ! defined(BACKPORT_LINUX_WORKQUEUE_TO_2_6_19)
|
||||
@@ -2890,10 +2928,9 @@ static struct class srpt_class = {
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Callback function called by the InfiniBand core when either an InfiniBand
|
||||
* device has been added or during the ib_register_client() call for each
|
||||
* registered InfiniBand device.
|
||||
/**
|
||||
* srpt_add_one() - Callback function that is called once by the InfiniBand
|
||||
* core for each registered InfiniBand device.
|
||||
*/
|
||||
static void srpt_add_one(struct ib_device *device)
|
||||
{
|
||||
@@ -2910,6 +2947,15 @@ static void srpt_add_one(struct ib_device *device)
|
||||
if (!sdev)
|
||||
return;
|
||||
|
||||
sdev->scst_tgt = scst_register(&srpt_template, NULL);
|
||||
if (!sdev->scst_tgt) {
|
||||
PRINT_ERROR("SCST registration failed for %s.",
|
||||
sdev->device->name);
|
||||
goto free_dev;
|
||||
}
|
||||
|
||||
scst_tgt_set_tgt_priv(sdev->scst_tgt, sdev);
|
||||
|
||||
sdev->device = device;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
|
||||
@@ -2929,10 +2975,10 @@ static void srpt_add_one(struct ib_device *device)
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
|
||||
if (class_device_register(&sdev->class_dev))
|
||||
goto free_dev;
|
||||
goto unregister_tgt;
|
||||
#else
|
||||
if (device_register(&sdev->dev))
|
||||
goto free_dev;
|
||||
goto unregister_tgt;
|
||||
#endif
|
||||
|
||||
if (ib_query_device(device, &sdev->dev_attr))
|
||||
@@ -3000,17 +3046,6 @@ static void srpt_add_one(struct ib_device *device)
|
||||
|
||||
ib_set_client_data(device, &srpt_client, sdev);
|
||||
|
||||
srpt_template.xmit_response_atomic = !thread;
|
||||
srpt_template.rdy_to_xfer_atomic = !thread;
|
||||
sdev->scst_tgt = scst_register(&srpt_template, NULL);
|
||||
if (!sdev->scst_tgt) {
|
||||
PRINT_ERROR("SCST registration failed for %s.",
|
||||
sdev->device->name);
|
||||
goto err_ring;
|
||||
}
|
||||
|
||||
scst_tgt_set_tgt_priv(sdev->scst_tgt, sdev);
|
||||
|
||||
WARN_ON(sdev->device->phys_port_cnt
|
||||
> sizeof(sdev->port)/sizeof(sdev->port[0]));
|
||||
|
||||
@@ -3030,7 +3065,7 @@ static void srpt_add_one(struct ib_device *device)
|
||||
if (srpt_refresh_port(sport)) {
|
||||
PRINT_ERROR("MAD registration failed for %s-%d.",
|
||||
sdev->device->name, i);
|
||||
goto err_refresh_port;
|
||||
goto err_ring;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3040,8 +3075,6 @@ static void srpt_add_one(struct ib_device *device)
|
||||
|
||||
return;
|
||||
|
||||
err_refresh_port:
|
||||
scst_unregister(sdev->scst_tgt);
|
||||
err_ring:
|
||||
ib_set_client_data(device, &srpt_client, NULL);
|
||||
srpt_free_ioctx_ring(sdev, sdev->ioctx_ring,
|
||||
@@ -3062,6 +3095,8 @@ err_dev:
|
||||
#else
|
||||
device_unregister(&sdev->dev);
|
||||
#endif
|
||||
unregister_tgt:
|
||||
scst_unregister(sdev->scst_tgt);
|
||||
free_dev:
|
||||
kfree(sdev);
|
||||
|
||||
@@ -3206,6 +3241,8 @@ static int __init srpt_init_module(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
srpt_template.xmit_response_atomic = !thread;
|
||||
srpt_template.rdy_to_xfer_atomic = !thread;
|
||||
ret = scst_register_target_template(&srpt_template);
|
||||
if (ret < 0) {
|
||||
PRINT_ERROR("%s", "couldn't register with scst");
|
||||
|
||||
+16
-8
@@ -136,18 +136,25 @@ struct rdma_iu {
|
||||
int mem_id;
|
||||
};
|
||||
|
||||
/* Command states. */
|
||||
/**
|
||||
* enum srpt_command_state - SCSI command states managed by SRPT.
|
||||
* @SRPT_STATE_NEW: New command arrived and is being processed.
|
||||
* @SRPT_STATE_NEED_DATA: Processing a write or bidir command and waiting for
|
||||
* data arrival.
|
||||
* @SRPT_STATE_DATA_IN: Data for the write or bidir command arrived and is
|
||||
* being processed.
|
||||
* @SRPT_STATE_CMD_RSP_SENT: SRP_RSP for SRP_CMD has been sent.
|
||||
* @SRPT_STATE_MGMT_RSP_SENT: SRP_RSP for SRP_TSK_MGMT has been sent.
|
||||
* @SRPT_STATE_DONE: Command processing finished successfully, command
|
||||
* processing has been aborted or command processing failed.
|
||||
*/
|
||||
enum srpt_command_state {
|
||||
/* New command arrived and is being processed. */
|
||||
SRPT_STATE_NEW = 0,
|
||||
/* Processing a write or bidir command and waiting for data arrival. */
|
||||
SRPT_STATE_NEED_DATA = 1,
|
||||
/* Data for the write or bidir command arrived and is being processed.*/
|
||||
SRPT_STATE_DATA_IN = 2,
|
||||
/* Command processing finished. */
|
||||
SRPT_STATE_PROCESSED = 3,
|
||||
/* Command processing has been aborted. */
|
||||
SRPT_STATE_ABORTED = 4,
|
||||
SRPT_STATE_CMD_RSP_SENT = 3,
|
||||
SRPT_STATE_MGMT_RSP_SENT = 4,
|
||||
SRPT_STATE_DONE = 5,
|
||||
};
|
||||
|
||||
/* SRPT I/O context: SRPT-private data associated with a struct scst_cmd. */
|
||||
@@ -160,6 +167,7 @@ struct srpt_ioctx {
|
||||
struct srp_direct_buf single_rbuf;
|
||||
/* Node for insertion in srpt_rdma_ch::cmd_wait_list. */
|
||||
struct list_head wait_list;
|
||||
int mapped_sg_count;
|
||||
u16 n_rdma_ius;
|
||||
u8 n_rdma;
|
||||
u8 n_rbuf;
|
||||
|
||||
Reference in New Issue
Block a user