diff options
Diffstat (limited to 'drivers/nvme/target/fcloop.c')
-rw-r--r-- | drivers/nvme/target/fcloop.c | 81 |
1 files changed, 59 insertions, 22 deletions
diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c index 381b5a90c48b..b50b53db3746 100644 --- a/drivers/nvme/target/fcloop.c +++ b/drivers/nvme/target/fcloop.c @@ -231,6 +231,11 @@ struct fcloop_lsreq { int status; }; +struct fcloop_rscn { + struct fcloop_tport *tport; + struct work_struct work; +}; + enum { INI_IO_START = 0, INI_IO_ACTIVE = 1, @@ -348,6 +353,37 @@ fcloop_xmt_ls_rsp(struct nvmet_fc_target_port *tport, return 0; } +/* + * Simulate reception of RSCN and converting it to a initiator transport + * call to rescan a remote port. + */ +static void +fcloop_tgt_rscn_work(struct work_struct *work) +{ + struct fcloop_rscn *tgt_rscn = + container_of(work, struct fcloop_rscn, work); + struct fcloop_tport *tport = tgt_rscn->tport; + + if (tport->remoteport) + nvme_fc_rescan_remoteport(tport->remoteport); + kfree(tgt_rscn); +} + +static void +fcloop_tgt_discovery_evt(struct nvmet_fc_target_port *tgtport) +{ + struct fcloop_rscn *tgt_rscn; + + tgt_rscn = kzalloc(sizeof(*tgt_rscn), GFP_KERNEL); + if (!tgt_rscn) + return; + + tgt_rscn->tport = tgtport->private; + INIT_WORK(&tgt_rscn->work, fcloop_tgt_rscn_work); + + schedule_work(&tgt_rscn->work); +} + static void fcloop_tfcp_req_free(struct kref *ref) { @@ -398,7 +434,7 @@ fcloop_fcp_recv_work(struct work_struct *work) int ret = 0; bool aborted = false; - spin_lock(&tfcp_req->reqlock); + spin_lock_irq(&tfcp_req->reqlock); switch (tfcp_req->inistate) { case INI_IO_START: tfcp_req->inistate = INI_IO_ACTIVE; @@ -407,11 +443,11 @@ fcloop_fcp_recv_work(struct work_struct *work) aborted = true; break; default: - spin_unlock(&tfcp_req->reqlock); + spin_unlock_irq(&tfcp_req->reqlock); WARN_ON(1); return; } - spin_unlock(&tfcp_req->reqlock); + spin_unlock_irq(&tfcp_req->reqlock); if (unlikely(aborted)) ret = -ECANCELED; @@ -433,7 +469,7 @@ fcloop_fcp_abort_recv_work(struct work_struct *work) struct nvmefc_fcp_req *fcpreq; bool completed = false; - spin_lock(&tfcp_req->reqlock); + spin_lock_irq(&tfcp_req->reqlock); fcpreq = tfcp_req->fcpreq; switch (tfcp_req->inistate) { case INI_IO_ABORTED: @@ -442,11 +478,11 @@ fcloop_fcp_abort_recv_work(struct work_struct *work) completed = true; break; default: - spin_unlock(&tfcp_req->reqlock); + spin_unlock_irq(&tfcp_req->reqlock); WARN_ON(1); return; } - spin_unlock(&tfcp_req->reqlock); + spin_unlock_irq(&tfcp_req->reqlock); if (unlikely(completed)) { /* remove reference taken in original abort downcall */ @@ -458,9 +494,9 @@ fcloop_fcp_abort_recv_work(struct work_struct *work) nvmet_fc_rcv_fcp_abort(tfcp_req->tport->targetport, &tfcp_req->tgt_fcp_req); - spin_lock(&tfcp_req->reqlock); + spin_lock_irq(&tfcp_req->reqlock); tfcp_req->fcpreq = NULL; - spin_unlock(&tfcp_req->reqlock); + spin_unlock_irq(&tfcp_req->reqlock); fcloop_call_host_done(fcpreq, tfcp_req, -ECANCELED); /* call_host_done releases reference for abort downcall */ @@ -477,10 +513,10 @@ fcloop_tgt_fcprqst_done_work(struct work_struct *work) container_of(work, struct fcloop_fcpreq, tio_done_work); struct nvmefc_fcp_req *fcpreq; - spin_lock(&tfcp_req->reqlock); + spin_lock_irq(&tfcp_req->reqlock); fcpreq = tfcp_req->fcpreq; tfcp_req->inistate = INI_IO_COMPLETED; - spin_unlock(&tfcp_req->reqlock); + spin_unlock_irq(&tfcp_req->reqlock); fcloop_call_host_done(fcpreq, tfcp_req, tfcp_req->status); } @@ -499,7 +535,7 @@ fcloop_fcp_req(struct nvme_fc_local_port *localport, if (!rport->targetport) return -ECONNREFUSED; - tfcp_req = kzalloc(sizeof(*tfcp_req), GFP_KERNEL); + tfcp_req = kzalloc(sizeof(*tfcp_req), GFP_ATOMIC); if (!tfcp_req) return -ENOMEM; @@ -585,12 +621,12 @@ fcloop_fcp_op(struct nvmet_fc_target_port *tgtport, int fcp_err = 0, active, aborted; u8 op = tgt_fcpreq->op; - spin_lock(&tfcp_req->reqlock); + spin_lock_irq(&tfcp_req->reqlock); fcpreq = tfcp_req->fcpreq; active = tfcp_req->active; aborted = tfcp_req->aborted; tfcp_req->active = true; - spin_unlock(&tfcp_req->reqlock); + spin_unlock_irq(&tfcp_req->reqlock); if (unlikely(active)) /* illegal - call while i/o active */ @@ -598,9 +634,9 @@ fcloop_fcp_op(struct nvmet_fc_target_port *tgtport, if (unlikely(aborted)) { /* target transport has aborted i/o prior */ - spin_lock(&tfcp_req->reqlock); + spin_lock_irq(&tfcp_req->reqlock); tfcp_req->active = false; - spin_unlock(&tfcp_req->reqlock); + spin_unlock_irq(&tfcp_req->reqlock); tgt_fcpreq->transferred_length = 0; tgt_fcpreq->fcp_error = -ECANCELED; tgt_fcpreq->done(tgt_fcpreq); @@ -657,9 +693,9 @@ fcloop_fcp_op(struct nvmet_fc_target_port *tgtport, break; } - spin_lock(&tfcp_req->reqlock); + spin_lock_irq(&tfcp_req->reqlock); tfcp_req->active = false; - spin_unlock(&tfcp_req->reqlock); + spin_unlock_irq(&tfcp_req->reqlock); tgt_fcpreq->transferred_length = xfrlen; tgt_fcpreq->fcp_error = fcp_err; @@ -679,9 +715,9 @@ fcloop_tgt_fcp_abort(struct nvmet_fc_target_port *tgtport, * (one doing io, other doing abort) and only kills ops posted * after the abort request */ - spin_lock(&tfcp_req->reqlock); + spin_lock_irq(&tfcp_req->reqlock); tfcp_req->aborted = true; - spin_unlock(&tfcp_req->reqlock); + spin_unlock_irq(&tfcp_req->reqlock); tfcp_req->status = NVME_SC_INTERNAL; @@ -729,7 +765,7 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport, return; /* break initiator/target relationship for io */ - spin_lock(&tfcp_req->reqlock); + spin_lock_irq(&tfcp_req->reqlock); switch (tfcp_req->inistate) { case INI_IO_START: case INI_IO_ACTIVE: @@ -739,11 +775,11 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport, abortio = false; break; default: - spin_unlock(&tfcp_req->reqlock); + spin_unlock_irq(&tfcp_req->reqlock); WARN_ON(1); return; } - spin_unlock(&tfcp_req->reqlock); + spin_unlock_irq(&tfcp_req->reqlock); if (abortio) /* leave the reference while the work item is scheduled */ @@ -839,6 +875,7 @@ static struct nvmet_fc_target_template tgttemplate = { .fcp_op = fcloop_fcp_op, .fcp_abort = fcloop_tgt_fcp_abort, .fcp_req_release = fcloop_fcp_req_release, + .discovery_event = fcloop_tgt_discovery_evt, .max_hw_queues = FCLOOP_HW_QUEUES, .max_sgl_segments = FCLOOP_SGL_SEGS, .max_dif_sgl_segments = FCLOOP_SGL_SEGS, |