scsi: ibmvfc: Complete commands outside the host/queue lock
Drain the command queue and place all commands on a completion list. Perform command completion on that list outside the host/queue locks. Further, move purged command compeletions outside the host_lock as well. Link: https://lore.kernel.org/r/20210106201835.1053593-5-tyreld@linux.ibm.com Reviewed-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Родитель
57e80e0bc1
Коммит
1f4a4a1950
|
@ -894,7 +894,7 @@ static void ibmvfc_scsi_eh_done(struct ibmvfc_event *evt)
|
||||||
* @purge_list: list head of failed commands
|
* @purge_list: list head of failed commands
|
||||||
*
|
*
|
||||||
* This function runs completions on commands to fail as a result of a
|
* This function runs completions on commands to fail as a result of a
|
||||||
* host reset or platform migration. Caller must hold host_lock.
|
* host reset or platform migration.
|
||||||
**/
|
**/
|
||||||
static void ibmvfc_complete_purge(struct list_head *purge_list)
|
static void ibmvfc_complete_purge(struct list_head *purge_list)
|
||||||
{
|
{
|
||||||
|
@ -1407,6 +1407,23 @@ static struct ibmvfc_event *ibmvfc_get_event(struct ibmvfc_queue *queue)
|
||||||
return evt;
|
return evt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ibmvfc_locked_done - Calls evt completion with host_lock held
|
||||||
|
* @evt: ibmvfc evt to complete
|
||||||
|
*
|
||||||
|
* All non-scsi command completion callbacks have the expectation that the
|
||||||
|
* host_lock is held. This callback is used by ibmvfc_init_event to wrap a
|
||||||
|
* MAD evt with the host_lock.
|
||||||
|
**/
|
||||||
|
static void ibmvfc_locked_done(struct ibmvfc_event *evt)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(evt->vhost->host->host_lock, flags);
|
||||||
|
evt->_done(evt);
|
||||||
|
spin_unlock_irqrestore(evt->vhost->host->host_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ibmvfc_init_event - Initialize fields in an event struct that are always
|
* ibmvfc_init_event - Initialize fields in an event struct that are always
|
||||||
* required.
|
* required.
|
||||||
|
@ -1419,9 +1436,14 @@ static void ibmvfc_init_event(struct ibmvfc_event *evt,
|
||||||
{
|
{
|
||||||
evt->cmnd = NULL;
|
evt->cmnd = NULL;
|
||||||
evt->sync_iu = NULL;
|
evt->sync_iu = NULL;
|
||||||
evt->crq.format = format;
|
|
||||||
evt->done = done;
|
|
||||||
evt->eh_comp = NULL;
|
evt->eh_comp = NULL;
|
||||||
|
evt->crq.format = format;
|
||||||
|
if (format == IBMVFC_CMD_FORMAT)
|
||||||
|
evt->done = done;
|
||||||
|
else {
|
||||||
|
evt->_done = done;
|
||||||
|
evt->done = ibmvfc_locked_done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1640,7 +1662,9 @@ static void ibmvfc_relogin(struct scsi_device *sdev)
|
||||||
struct ibmvfc_host *vhost = shost_priv(sdev->host);
|
struct ibmvfc_host *vhost = shost_priv(sdev->host);
|
||||||
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
|
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
|
||||||
struct ibmvfc_target *tgt;
|
struct ibmvfc_target *tgt;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(vhost->host->host_lock, flags);
|
||||||
list_for_each_entry(tgt, &vhost->targets, queue) {
|
list_for_each_entry(tgt, &vhost->targets, queue) {
|
||||||
if (rport == tgt->rport) {
|
if (rport == tgt->rport) {
|
||||||
ibmvfc_del_tgt(tgt);
|
ibmvfc_del_tgt(tgt);
|
||||||
|
@ -1649,6 +1673,7 @@ static void ibmvfc_relogin(struct scsi_device *sdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
ibmvfc_reinit_host(vhost);
|
ibmvfc_reinit_host(vhost);
|
||||||
|
spin_unlock_irqrestore(vhost->host->host_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2901,7 +2926,8 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
|
||||||
* @vhost: ibmvfc host struct
|
* @vhost: ibmvfc host struct
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)
|
static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost,
|
||||||
|
struct list_head *evt_doneq)
|
||||||
{
|
{
|
||||||
long rc;
|
long rc;
|
||||||
struct ibmvfc_event *evt = (struct ibmvfc_event *)be64_to_cpu(crq->ioba);
|
struct ibmvfc_event *evt = (struct ibmvfc_event *)be64_to_cpu(crq->ioba);
|
||||||
|
@ -2972,12 +2998,9 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
del_timer(&evt->timer);
|
|
||||||
spin_lock(&evt->queue->l_lock);
|
spin_lock(&evt->queue->l_lock);
|
||||||
list_del(&evt->queue_list);
|
list_move_tail(&evt->queue_list, evt_doneq);
|
||||||
spin_unlock(&evt->queue->l_lock);
|
spin_unlock(&evt->queue->l_lock);
|
||||||
ibmvfc_trc_end(evt);
|
|
||||||
evt->done(evt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3364,8 +3387,10 @@ static void ibmvfc_tasklet(void *data)
|
||||||
struct vio_dev *vdev = to_vio_dev(vhost->dev);
|
struct vio_dev *vdev = to_vio_dev(vhost->dev);
|
||||||
struct ibmvfc_crq *crq;
|
struct ibmvfc_crq *crq;
|
||||||
struct ibmvfc_async_crq *async;
|
struct ibmvfc_async_crq *async;
|
||||||
|
struct ibmvfc_event *evt, *temp;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
|
LIST_HEAD(evt_doneq);
|
||||||
|
|
||||||
spin_lock_irqsave(vhost->host->host_lock, flags);
|
spin_lock_irqsave(vhost->host->host_lock, flags);
|
||||||
spin_lock(vhost->crq.q_lock);
|
spin_lock(vhost->crq.q_lock);
|
||||||
|
@ -3379,7 +3404,7 @@ static void ibmvfc_tasklet(void *data)
|
||||||
|
|
||||||
/* Pull all the valid messages off the CRQ */
|
/* Pull all the valid messages off the CRQ */
|
||||||
while ((crq = ibmvfc_next_crq(vhost)) != NULL) {
|
while ((crq = ibmvfc_next_crq(vhost)) != NULL) {
|
||||||
ibmvfc_handle_crq(crq, vhost);
|
ibmvfc_handle_crq(crq, vhost, &evt_doneq);
|
||||||
crq->valid = 0;
|
crq->valid = 0;
|
||||||
wmb();
|
wmb();
|
||||||
}
|
}
|
||||||
|
@ -3392,7 +3417,7 @@ static void ibmvfc_tasklet(void *data)
|
||||||
wmb();
|
wmb();
|
||||||
} else if ((crq = ibmvfc_next_crq(vhost)) != NULL) {
|
} else if ((crq = ibmvfc_next_crq(vhost)) != NULL) {
|
||||||
vio_disable_interrupts(vdev);
|
vio_disable_interrupts(vdev);
|
||||||
ibmvfc_handle_crq(crq, vhost);
|
ibmvfc_handle_crq(crq, vhost, &evt_doneq);
|
||||||
crq->valid = 0;
|
crq->valid = 0;
|
||||||
wmb();
|
wmb();
|
||||||
} else
|
} else
|
||||||
|
@ -3401,6 +3426,13 @@ static void ibmvfc_tasklet(void *data)
|
||||||
|
|
||||||
spin_unlock(vhost->crq.q_lock);
|
spin_unlock(vhost->crq.q_lock);
|
||||||
spin_unlock_irqrestore(vhost->host->host_lock, flags);
|
spin_unlock_irqrestore(vhost->host->host_lock, flags);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(evt, temp, &evt_doneq, queue_list) {
|
||||||
|
del_timer(&evt->timer);
|
||||||
|
list_del(&evt->queue_list);
|
||||||
|
ibmvfc_trc_end(evt);
|
||||||
|
evt->done(evt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4790,8 +4822,8 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
|
||||||
case IBMVFC_HOST_ACTION_RESET:
|
case IBMVFC_HOST_ACTION_RESET:
|
||||||
vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
|
vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
|
||||||
list_splice_init(&vhost->purge, &purge);
|
list_splice_init(&vhost->purge, &purge);
|
||||||
ibmvfc_complete_purge(&purge);
|
|
||||||
spin_unlock_irqrestore(vhost->host->host_lock, flags);
|
spin_unlock_irqrestore(vhost->host->host_lock, flags);
|
||||||
|
ibmvfc_complete_purge(&purge);
|
||||||
rc = ibmvfc_reset_crq(vhost);
|
rc = ibmvfc_reset_crq(vhost);
|
||||||
spin_lock_irqsave(vhost->host->host_lock, flags);
|
spin_lock_irqsave(vhost->host->host_lock, flags);
|
||||||
if (rc == H_CLOSED)
|
if (rc == H_CLOSED)
|
||||||
|
@ -4805,8 +4837,8 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
|
||||||
case IBMVFC_HOST_ACTION_REENABLE:
|
case IBMVFC_HOST_ACTION_REENABLE:
|
||||||
vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
|
vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
|
||||||
list_splice_init(&vhost->purge, &purge);
|
list_splice_init(&vhost->purge, &purge);
|
||||||
ibmvfc_complete_purge(&purge);
|
|
||||||
spin_unlock_irqrestore(vhost->host->host_lock, flags);
|
spin_unlock_irqrestore(vhost->host->host_lock, flags);
|
||||||
|
ibmvfc_complete_purge(&purge);
|
||||||
rc = ibmvfc_reenable_crq_queue(vhost);
|
rc = ibmvfc_reenable_crq_queue(vhost);
|
||||||
spin_lock_irqsave(vhost->host->host_lock, flags);
|
spin_lock_irqsave(vhost->host->host_lock, flags);
|
||||||
if (rc || (rc = ibmvfc_send_crq_init(vhost))) {
|
if (rc || (rc = ibmvfc_send_crq_init(vhost))) {
|
||||||
|
@ -5369,8 +5401,8 @@ static int ibmvfc_remove(struct vio_dev *vdev)
|
||||||
spin_lock_irqsave(vhost->host->host_lock, flags);
|
spin_lock_irqsave(vhost->host->host_lock, flags);
|
||||||
ibmvfc_purge_requests(vhost, DID_ERROR);
|
ibmvfc_purge_requests(vhost, DID_ERROR);
|
||||||
list_splice_init(&vhost->purge, &purge);
|
list_splice_init(&vhost->purge, &purge);
|
||||||
ibmvfc_complete_purge(&purge);
|
|
||||||
spin_unlock_irqrestore(vhost->host->host_lock, flags);
|
spin_unlock_irqrestore(vhost->host->host_lock, flags);
|
||||||
|
ibmvfc_complete_purge(&purge);
|
||||||
ibmvfc_free_event_pool(vhost, &vhost->crq);
|
ibmvfc_free_event_pool(vhost, &vhost->crq);
|
||||||
|
|
||||||
ibmvfc_free_mem(vhost);
|
ibmvfc_free_mem(vhost);
|
||||||
|
|
|
@ -733,7 +733,8 @@ struct ibmvfc_event {
|
||||||
struct scsi_cmnd *cmnd;
|
struct scsi_cmnd *cmnd;
|
||||||
atomic_t free;
|
atomic_t free;
|
||||||
union ibmvfc_iu *xfer_iu;
|
union ibmvfc_iu *xfer_iu;
|
||||||
void (*done) (struct ibmvfc_event *);
|
void (*done)(struct ibmvfc_event *evt);
|
||||||
|
void (*_done)(struct ibmvfc_event *evt);
|
||||||
struct ibmvfc_crq crq;
|
struct ibmvfc_crq crq;
|
||||||
union ibmvfc_iu iu;
|
union ibmvfc_iu iu;
|
||||||
union ibmvfc_iu *sync_iu;
|
union ibmvfc_iu *sync_iu;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче