|
@@ -683,6 +683,7 @@ static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd,
|
|
ipr_reinit_ipr_cmnd(ipr_cmd);
|
|
ipr_reinit_ipr_cmnd(ipr_cmd);
|
|
ipr_cmd->u.scratch = 0;
|
|
ipr_cmd->u.scratch = 0;
|
|
ipr_cmd->sibling = NULL;
|
|
ipr_cmd->sibling = NULL;
|
|
|
|
+ ipr_cmd->eh_comp = NULL;
|
|
ipr_cmd->fast_done = fast_done;
|
|
ipr_cmd->fast_done = fast_done;
|
|
init_timer(&ipr_cmd->timer);
|
|
init_timer(&ipr_cmd->timer);
|
|
}
|
|
}
|
|
@@ -848,6 +849,8 @@ static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd)
|
|
|
|
|
|
scsi_dma_unmap(ipr_cmd->scsi_cmd);
|
|
scsi_dma_unmap(ipr_cmd->scsi_cmd);
|
|
scsi_cmd->scsi_done(scsi_cmd);
|
|
scsi_cmd->scsi_done(scsi_cmd);
|
|
|
|
+ if (ipr_cmd->eh_comp)
|
|
|
|
+ complete(ipr_cmd->eh_comp);
|
|
list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
|
|
list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -4811,6 +4814,84 @@ static int ipr_slave_alloc(struct scsi_device *sdev)
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * ipr_match_lun - Match function for specified LUN
|
|
|
|
+ * @ipr_cmd: ipr command struct
|
|
|
|
+ * @device: device to match (sdev)
|
|
|
|
+ *
|
|
|
|
+ * Returns:
|
|
|
|
+ * 1 if command matches sdev / 0 if command does not match sdev
|
|
|
|
+ **/
|
|
|
|
+static int ipr_match_lun(struct ipr_cmnd *ipr_cmd, void *device)
|
|
|
|
+{
|
|
|
|
+ if (ipr_cmd->scsi_cmd && ipr_cmd->scsi_cmd->device == device)
|
|
|
|
+ return 1;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * ipr_wait_for_ops - Wait for matching commands to complete
|
|
|
|
+ * @ipr_cmd: ipr command struct
|
|
|
|
+ * @device: device to match (sdev)
|
|
|
|
+ * @match: match function to use
|
|
|
|
+ *
|
|
|
|
+ * Returns:
|
|
|
|
+ * SUCCESS / FAILED
|
|
|
|
+ **/
|
|
|
|
+static int ipr_wait_for_ops(struct ipr_ioa_cfg *ioa_cfg, void *device,
|
|
|
|
+ int (*match)(struct ipr_cmnd *, void *))
|
|
|
|
+{
|
|
|
|
+ struct ipr_cmnd *ipr_cmd;
|
|
|
|
+ int wait;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ struct ipr_hrr_queue *hrrq;
|
|
|
|
+ signed long timeout = IPR_ABORT_TASK_TIMEOUT;
|
|
|
|
+ DECLARE_COMPLETION_ONSTACK(comp);
|
|
|
|
+
|
|
|
|
+ ENTER;
|
|
|
|
+ do {
|
|
|
|
+ wait = 0;
|
|
|
|
+
|
|
|
|
+ for_each_hrrq(hrrq, ioa_cfg) {
|
|
|
|
+ spin_lock_irqsave(hrrq->lock, flags);
|
|
|
|
+ list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) {
|
|
|
|
+ if (match(ipr_cmd, device)) {
|
|
|
|
+ ipr_cmd->eh_comp = ∁
|
|
|
|
+ wait++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ spin_unlock_irqrestore(hrrq->lock, flags);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (wait) {
|
|
|
|
+ timeout = wait_for_completion_timeout(&comp, timeout);
|
|
|
|
+
|
|
|
|
+ if (!timeout) {
|
|
|
|
+ wait = 0;
|
|
|
|
+
|
|
|
|
+ for_each_hrrq(hrrq, ioa_cfg) {
|
|
|
|
+ spin_lock_irqsave(hrrq->lock, flags);
|
|
|
|
+ list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) {
|
|
|
|
+ if (match(ipr_cmd, device)) {
|
|
|
|
+ ipr_cmd->eh_comp = NULL;
|
|
|
|
+ wait++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ spin_unlock_irqrestore(hrrq->lock, flags);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (wait)
|
|
|
|
+ dev_err(&ioa_cfg->pdev->dev, "Timed out waiting for aborted commands\n");
|
|
|
|
+ LEAVE;
|
|
|
|
+ return wait ? FAILED : SUCCESS;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } while (wait);
|
|
|
|
+
|
|
|
|
+ LEAVE;
|
|
|
|
+ return SUCCESS;
|
|
|
|
+}
|
|
|
|
+
|
|
static int ipr_eh_host_reset(struct scsi_cmnd *cmd)
|
|
static int ipr_eh_host_reset(struct scsi_cmnd *cmd)
|
|
{
|
|
{
|
|
struct ipr_ioa_cfg *ioa_cfg;
|
|
struct ipr_ioa_cfg *ioa_cfg;
|
|
@@ -5030,11 +5111,17 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd)
|
|
static int ipr_eh_dev_reset(struct scsi_cmnd *cmd)
|
|
static int ipr_eh_dev_reset(struct scsi_cmnd *cmd)
|
|
{
|
|
{
|
|
int rc;
|
|
int rc;
|
|
|
|
+ struct ipr_ioa_cfg *ioa_cfg;
|
|
|
|
+
|
|
|
|
+ ioa_cfg = (struct ipr_ioa_cfg *) cmd->device->host->hostdata;
|
|
|
|
|
|
spin_lock_irq(cmd->device->host->host_lock);
|
|
spin_lock_irq(cmd->device->host->host_lock);
|
|
rc = __ipr_eh_dev_reset(cmd);
|
|
rc = __ipr_eh_dev_reset(cmd);
|
|
spin_unlock_irq(cmd->device->host->host_lock);
|
|
spin_unlock_irq(cmd->device->host->host_lock);
|
|
|
|
|
|
|
|
+ if (rc == SUCCESS)
|
|
|
|
+ rc = ipr_wait_for_ops(ioa_cfg, cmd->device, ipr_match_lun);
|
|
|
|
+
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -5234,13 +5321,18 @@ static int ipr_eh_abort(struct scsi_cmnd *scsi_cmd)
|
|
{
|
|
{
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
int rc;
|
|
int rc;
|
|
|
|
+ struct ipr_ioa_cfg *ioa_cfg;
|
|
|
|
|
|
ENTER;
|
|
ENTER;
|
|
|
|
|
|
|
|
+ ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
|
|
|
|
+
|
|
spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags);
|
|
spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags);
|
|
rc = ipr_cancel_op(scsi_cmd);
|
|
rc = ipr_cancel_op(scsi_cmd);
|
|
spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags);
|
|
spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags);
|
|
|
|
|
|
|
|
+ if (rc == SUCCESS)
|
|
|
|
+ rc = ipr_wait_for_ops(ioa_cfg, scsi_cmd->device, ipr_match_lun);
|
|
LEAVE;
|
|
LEAVE;
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|