This patch removes all spinlocks from ipr's queuecommand path.
Signed-off-by: Brian King <[email protected]>
---
drivers/scsi/ipr.c | 70 +++++++++++++++++++++++++++++++----------------------
drivers/scsi/ipr.h | 52 +++++++++++++++++++++++++++++++++++++--
2 files changed, 91 insertions(+), 31 deletions(-)
diff -puN drivers/scsi/ipr.h~ipr_lockless_atomic drivers/scsi/ipr.h
--- linux-2.6.git/drivers/scsi/ipr.h~ipr_lockless_atomic 2016-09-06
21:01:16.260239296 -0500
+++ linux-2.6.git-bjking1/drivers/scsi/ipr.h 2016-09-06 21:07:15.309878131
-0500
@@ -512,6 +512,7 @@ struct ipr_hrr_queue {
struct list_head hrrq_error_q;
spinlock_t _lock;
spinlock_t *lock;
+ atomic_t active;
volatile u32 toggle_bit;
u32 size;
@@ -521,6 +522,7 @@ struct ipr_hrr_queue {
u8 ioa_is_dead:1;
u8 allow_cmds:1;
u8 removing_ioa:1;
+ u8 is_active:1;
struct irq_poll iopoll;
};
@@ -1293,13 +1295,13 @@ struct ipr_sata_port {
};
struct ipr_resource_entry {
- u8 needs_sync_complete:1;
+ u8 needs_sync_complete:1; /* atomic? gscsi and vset */
u8 in_erp:1;
u8 add_to_ml:1;
u8 del_from_ml:1;
u8 resetting_device:1;
- u8 reset_occurred:1;
- u8 raw_mode:1;
+ u8 reset_occurred:1; /* atomic? gscsi only */
+ u8 raw_mode:1; /* atomic? AF DASD only */
u32 bus; /* AKA channel */
u32 target; /* AKA id */
@@ -1492,6 +1494,7 @@ struct ipr_ioa_cfg {
u8 cfg_locked:1;
u8 clear_isr:1;
u8 probe_done:1;
+ u8 allow_cmds:1;
u8 revid;
@@ -1544,6 +1547,7 @@ struct ipr_ioa_cfg {
struct ipr_hrr_queue hrrq[IPR_MAX_HRRQ_NUM];
u32 hrrq_num;
atomic_t hrrq_index;
+ atomic_t hrrq_active;
u16 identify_hrrq_index;
struct ipr_bus_attributes bus_attr[IPR_MAX_NUM_BUSES];
@@ -1868,6 +1872,48 @@ static inline void ipr_free_cmd(struct i
ipr_cmd->hrrq->active_map);
}
+static inline void ipr_hrrq_activate(struct ipr_hrr_queue *hrrq)
+{
+ if (!hrrq->is_active) {
+ atomic_inc(&hrrq->active);
+ atomic_inc(&hrrq->ioa_cfg->hrrq_active);
+ hrrq->is_active = 1;
+ }
+}
+
+static inline void ipr_hrrq_deactivate(struct ipr_hrr_queue *hrrq)
+{
+ if (hrrq->is_active) {
+ hrrq->is_active = 0;
+
+ if (!atomic_dec_return(&hrrq->active))
+ atomic_dec(&hrrq->ioa_cfg->hrrq_active);
+ }
+}
+
+static inline int ipr_hrrq_enter(struct ipr_hrr_queue *hrrq)
+{
+ return atomic_inc_not_zero(&hrrq->active);
+}
+
+static void ipr_reset_ioa_job(struct ipr_cmnd *);
+
+static inline void ipr_hrrq_exit(struct ipr_hrr_queue *hrrq)
+{
+ unsigned long flags;
+ struct ipr_ioa_cfg *ioa_cfg;
+
+ if (!atomic_dec_return(&hrrq->active)) {
+ ioa_cfg = hrrq->ioa_cfg;
+
+ if (!atomic_dec_return(&ioa_cfg->hrrq_active)) {
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+ ipr_reset_ioa_job(ioa_cfg->reset_cmd);
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+ }
+ }
+}
+
static inline struct ipr_cmnd* ipr_first_active_cmd(struct ipr_hrr_queue *hrrq)
{
int i = find_first_bit(hrrq->active_map, hrrq->size);
diff -puN drivers/scsi/ipr.c~ipr_lockless_atomic drivers/scsi/ipr.c
--- linux-2.6.git/drivers/scsi/ipr.c~ipr_lockless_atomic 2016-09-06
21:01:16.264239271 -0500
+++ linux-2.6.git-bjking1/drivers/scsi/ipr.c 2016-09-06 21:07:15.311878103
-0500
@@ -6455,10 +6455,8 @@ static void ipr_scsi_done(struct ipr_cmn
if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) {
scsi_dma_unmap(scsi_cmd);
- spin_lock_irqsave(ipr_cmd->hrrq->lock, lock_flags);
ipr_free_cmd(ipr_cmd);
scsi_cmd->scsi_done(scsi_cmd);
- spin_unlock_irqrestore(ipr_cmd->hrrq->lock, lock_flags);
} else {
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
spin_lock(&ipr_cmd->hrrq->_lock);
@@ -6513,9 +6511,27 @@ static int ipr_queuecommand(struct Scsi_
hrrq = &ioa_cfg->hrrq[hrrq_id];
+ if (!ipr_hrrq_enter(hrrq)) {
+ dev_info(&ioa_cfg->pdev->dev, "Failed to get a ref\n");
+
+ spin_lock_irqsave(hrrq->lock, hrrq_flags);
+ if (hrrq->ioa_is_dead || hrrq->removing_ioa) {
+ spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
+ memset(scsi_cmd->sense_buffer, 0,
SCSI_SENSE_BUFFERSIZE);
+ scsi_cmd->result = (DID_NO_CONNECT << 16);
+ scsi_cmd->scsi_done(scsi_cmd);
+ return 0;
+ }
+
+ spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
ipr_cmd = __ipr_get_free_ipr_cmnd(hrrq);
- if (ipr_cmd == NULL)
+ if (ipr_cmd == NULL) {
+ ipr_hrrq_exit(hrrq);
return SCSI_MLQUEUE_HOST_BUSY;
+ }
ipr_init_ipr_cmnd(ipr_cmd, ipr_scsi_done);
ioarcb = &ipr_cmd->ioarcb;
@@ -6529,7 +6545,10 @@ static int ipr_queuecommand(struct Scsi_
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
if (res->reset_occurred) {
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
res->reset_occurred = 0;
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock,
lock_flags);
+
ioarcb->cmd_pkt.flags_lo |=
IPR_FLAGS_LO_DELAY_AFTER_RST;
}
}
@@ -6542,6 +6561,13 @@ static int ipr_queuecommand(struct Scsi_
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_SIMPLE_TASK;
else
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_UNTAGGED_TASK;
+
+ if (res->needs_sync_complete) {
+ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_SYNC_COMPLETE;
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ res->needs_sync_complete = 0;
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock,
lock_flags);
+ }
}
if (scsi_cmd->cmnd[0] >= 0xC0 &&
@@ -6560,38 +6586,20 @@ static int ipr_queuecommand(struct Scsi_
else
rc = ipr_build_ioadl(ioa_cfg, ipr_cmd);
- spin_lock_irqsave(hrrq->lock, hrrq_flags);
- if (unlikely(rc || (!hrrq->allow_cmds && !hrrq->ioa_is_dead &&
!hrrq->removing_ioa))) {
- ipr_free_cmd(ipr_cmd);
- spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
- if (!rc)
+ if (rc) {
+ if (!ipr_cmnd_complete(ipr_cmd)) {
+ ipr_free_cmd(ipr_cmd);
scsi_dma_unmap(scsi_cmd);
+ }
+ ipr_hrrq_exit(hrrq);
return SCSI_MLQUEUE_HOST_BUSY;
}
- if (unlikely(hrrq->ioa_is_dead || hrrq->removing_ioa)) {
- ipr_free_cmd(ipr_cmd);
- spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
- scsi_dma_unmap(scsi_cmd);
- goto err_nodev;
- }
-
ioarcb->res_handle = res->res_handle;
- if (res->needs_sync_complete) {
- ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_SYNC_COMPLETE;
- res->needs_sync_complete = 0;
- }
+
ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_RES_PHYS_LOC(res));
ipr_send_command(ipr_cmd);
- spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
- return 0;
-
-err_nodev:
- spin_lock_irqsave(hrrq->lock, hrrq_flags);
- memset(scsi_cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- scsi_cmd->result = (DID_NO_CONNECT << 16);
- scsi_cmd->scsi_done(scsi_cmd);
- spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
+ ipr_hrrq_exit(hrrq);
return 0;
}
@@ -7160,6 +7168,7 @@ static int ipr_ioa_reset_done(struct ipr
for (j = 0; j < ioa_cfg->hrrq_num; j++) {
spin_lock(&ioa_cfg->hrrq[j]._lock);
ioa_cfg->hrrq[j].allow_cmds = 1;
+ ipr_hrrq_activate(&ioa_cfg->hrrq[j]);
spin_unlock(&ioa_cfg->hrrq[j]._lock);
}
wmb();
@@ -9110,6 +9119,9 @@ static void ipr_reset_ioa_job(struct ipr
return;
}
+ if (atomic_read(&ioa_cfg->hrrq_active))
+ return;
+
if (IPR_IOASC_SENSE_KEY(ioasc)) {
rc = ipr_cmd->job_step_failed(ipr_cmd);
if (rc == IPR_RC_JOB_RETURN)
@@ -9147,6 +9159,7 @@ static void _ipr_initiate_ioa_reset(stru
for (i = 0; i < ioa_cfg->hrrq_num; i++) {
spin_lock(&ioa_cfg->hrrq[i]._lock);
ioa_cfg->hrrq[i].allow_cmds = 0;
+ ipr_hrrq_deactivate(&ioa_cfg->hrrq[i]);
spin_unlock(&ioa_cfg->hrrq[i]._lock);
}
wmb();
@@ -9333,6 +9346,7 @@ static void ipr_pci_perm_failure(struct
for (i = 0; i < ioa_cfg->hrrq_num; i++) {
spin_lock(&ioa_cfg->hrrq[i]._lock);
ioa_cfg->hrrq[i].allow_cmds = 0;
+ ipr_hrrq_deactivate(&ioa_cfg->hrrq[i]);
spin_unlock(&ioa_cfg->hrrq[i]._lock);
}
wmb();
_
------------------------------------------------------------------------------
_______________________________________________
Iprdd-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/iprdd-devel