diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-10-28 00:05:37 +0200 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-10-31 10:23:01 +0100 |
commit | 52d74634335dfc0984ed955ed3c6ad6488495f96 (patch) | |
tree | 647120b0916abcc42f1e2d050f13175993509776 /drivers/scsi/isci/task.c | |
parent | [SCSI] isci: Fix hard reset timeout conditions. (diff) | |
download | linux-52d74634335dfc0984ed955ed3c6ad6488495f96.tar.xz linux-52d74634335dfc0984ed955ed3c6ad6488495f96.zip |
[SCSI] isci: revert bcn filtering
The initial bcn filtering implementation was validated on a kernel
baseline that predated the switch to new libata error handling. Also,
prior to that conversion we borrowed the mvsas MVS_DEV_EH approach to
prevent the unwanted extra ap->ops->phy_reset(ap) that occurred in the
ata_bus_probe() path.
After the conversion to new libata eh resets at discovery are more
frequent and get filtered prematurely by IDEV_EH. The result is that
our bcn filtering has been blocked from running and at discovery and it
appears to stall discovery completion to the point of triggering hung
task timeouts. So, revert the implementation for now. When it returns
it will go into libsas proper.
The domain rediscovery that takes place due to ->lldd_I_T_nexus_reset()
events should now be properly waited for by the ata_port_wait_eh() call
in ata_port_probe(). So the hard coded delay in the isci
->lldd_I_T_nexus_reset() and other libsas drivers should help debounce
the libsas thread from seeing temporary device removals.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/isci/task.c')
-rw-r--r-- | drivers/scsi/isci/task.c | 235 |
1 files changed, 0 insertions, 235 deletions
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 6d8ff15a03d1..66ad3dc89498 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -1331,226 +1331,10 @@ isci_task_request_complete(struct isci_host *ihost, complete(tmf_complete); } -static void isci_smp_task_timedout(unsigned long _task) -{ - struct sas_task *task = (void *) _task; - unsigned long flags; - - spin_lock_irqsave(&task->task_state_lock, flags); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) - task->task_state_flags |= SAS_TASK_STATE_ABORTED; - spin_unlock_irqrestore(&task->task_state_lock, flags); - - complete(&task->completion); -} - -static void isci_smp_task_done(struct sas_task *task) -{ - if (!del_timer(&task->timer)) - return; - complete(&task->completion); -} - -static int isci_smp_execute_task(struct isci_host *ihost, - struct domain_device *dev, void *req, - int req_size, void *resp, int resp_size) -{ - int res, retry; - struct sas_task *task = NULL; - - for (retry = 0; retry < 3; retry++) { - task = sas_alloc_task(GFP_KERNEL); - if (!task) - return -ENOMEM; - - task->dev = dev; - task->task_proto = dev->tproto; - sg_init_one(&task->smp_task.smp_req, req, req_size); - sg_init_one(&task->smp_task.smp_resp, resp, resp_size); - - task->task_done = isci_smp_task_done; - - task->timer.data = (unsigned long) task; - task->timer.function = isci_smp_task_timedout; - task->timer.expires = jiffies + 10*HZ; - add_timer(&task->timer); - - res = isci_task_execute_task(task, 1, GFP_KERNEL); - - if (res) { - del_timer(&task->timer); - dev_dbg(&ihost->pdev->dev, - "%s: executing SMP task failed:%d\n", - __func__, res); - goto ex_err; - } - - wait_for_completion(&task->completion); - res = -ECOMM; - if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - dev_dbg(&ihost->pdev->dev, - "%s: smp task timed out or aborted\n", - __func__); - isci_task_abort_task(task); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - dev_dbg(&ihost->pdev->dev, - "%s: SMP task aborted and not done\n", - __func__); - goto ex_err; - } - } - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_STAT_GOOD) { - res = 0; - break; - } - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_DATA_UNDERRUN) { - /* no error, but return the number of bytes of - * underrun */ - res = task->task_status.residual; - break; - } - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_DATA_OVERRUN) { - res = -EMSGSIZE; - break; - } else { - dev_dbg(&ihost->pdev->dev, - "%s: task to dev %016llx response: 0x%x " - "status 0x%x\n", __func__, - SAS_ADDR(dev->sas_addr), - task->task_status.resp, - task->task_status.stat); - sas_free_task(task); - task = NULL; - } - } -ex_err: - BUG_ON(retry == 3 && task != NULL); - sas_free_task(task); - return res; -} - -#define DISCOVER_REQ_SIZE 16 -#define DISCOVER_RESP_SIZE 56 - -int isci_smp_get_phy_attached_dev_type(struct isci_host *ihost, - struct domain_device *dev, - int phy_id, int *adt) -{ - struct smp_resp *disc_resp; - u8 *disc_req; - int res; - - disc_resp = kzalloc(DISCOVER_RESP_SIZE, GFP_KERNEL); - if (!disc_resp) - return -ENOMEM; - - disc_req = kzalloc(DISCOVER_REQ_SIZE, GFP_KERNEL); - if (disc_req) { - disc_req[0] = SMP_REQUEST; - disc_req[1] = SMP_DISCOVER; - disc_req[9] = phy_id; - } else { - kfree(disc_resp); - return -ENOMEM; - } - res = isci_smp_execute_task(ihost, dev, disc_req, DISCOVER_REQ_SIZE, - disc_resp, DISCOVER_RESP_SIZE); - if (!res) { - if (disc_resp->result != SMP_RESP_FUNC_ACC) - res = disc_resp->result; - else - *adt = disc_resp->disc.attached_dev_type; - } - kfree(disc_req); - kfree(disc_resp); - - return res; -} - -static void isci_wait_for_smp_phy_reset(struct isci_remote_device *idev, int phy_num) -{ - struct domain_device *dev = idev->domain_dev; - struct isci_port *iport = idev->isci_port; - struct isci_host *ihost = iport->isci_host; - int res, iteration = 0, attached_device_type; - #define STP_WAIT_MSECS 25000 - unsigned long tmo = msecs_to_jiffies(STP_WAIT_MSECS); - unsigned long deadline = jiffies + tmo; - enum { - SMP_PHYWAIT_PHYDOWN, - SMP_PHYWAIT_PHYUP, - SMP_PHYWAIT_DONE - } phy_state = SMP_PHYWAIT_PHYDOWN; - - /* While there is time, wait for the phy to go away and come back */ - while (time_is_after_jiffies(deadline) && phy_state != SMP_PHYWAIT_DONE) { - int event = atomic_read(&iport->event); - - ++iteration; - - tmo = wait_event_timeout(ihost->eventq, - event != atomic_read(&iport->event) || - !test_bit(IPORT_BCN_BLOCKED, &iport->flags), - tmo); - /* link down, stop polling */ - if (!test_bit(IPORT_BCN_BLOCKED, &iport->flags)) - break; - - dev_dbg(&ihost->pdev->dev, - "%s: iport %p, iteration %d," - " phase %d: time_remaining %lu, bcns = %d\n", - __func__, iport, iteration, phy_state, - tmo, test_bit(IPORT_BCN_PENDING, &iport->flags)); - - res = isci_smp_get_phy_attached_dev_type(ihost, dev, phy_num, - &attached_device_type); - tmo = deadline - jiffies; - - if (res) { - dev_dbg(&ihost->pdev->dev, - "%s: iteration %d, phase %d:" - " SMP error=%d, time_remaining=%lu\n", - __func__, iteration, phy_state, res, tmo); - break; - } - dev_dbg(&ihost->pdev->dev, - "%s: iport %p, iteration %d," - " phase %d: time_remaining %lu, bcns = %d, " - "attdevtype = %x\n", - __func__, iport, iteration, phy_state, - tmo, test_bit(IPORT_BCN_PENDING, &iport->flags), - attached_device_type); - - switch (phy_state) { - case SMP_PHYWAIT_PHYDOWN: - /* Has the device gone away? */ - if (!attached_device_type) - phy_state = SMP_PHYWAIT_PHYUP; - - break; - - case SMP_PHYWAIT_PHYUP: - /* Has the device come back? */ - if (attached_device_type) - phy_state = SMP_PHYWAIT_DONE; - break; - - case SMP_PHYWAIT_DONE: - break; - } - - } - dev_dbg(&ihost->pdev->dev, "%s: done\n", __func__); -} - static int isci_reset_device(struct isci_host *ihost, struct isci_remote_device *idev) { struct sas_phy *phy = sas_find_local_phy(idev->domain_dev); - struct isci_port *iport = idev->isci_port; enum sci_status status; unsigned long flags; int rc; @@ -1570,10 +1354,6 @@ static int isci_reset_device(struct isci_host *ihost, } spin_unlock_irqrestore(&ihost->scic_lock, flags); - /* If this is a device on an expander, disable BCN processing. */ - if (!scsi_is_sas_phy_local(phy)) - set_bit(IPORT_BCN_BLOCKED, &iport->flags); - rc = sas_phy_reset(phy, true); /* Terminate in-progress I/O now. */ @@ -1584,21 +1364,6 @@ static int isci_reset_device(struct isci_host *ihost, status = sci_remote_device_reset_complete(idev); spin_unlock_irqrestore(&ihost->scic_lock, flags); - /* If this is a device on an expander, bring the phy back up. */ - if (!scsi_is_sas_phy_local(phy)) { - /* A phy reset will cause the device to go away then reappear. - * Since libsas will take action on incoming BCNs (eg. remove - * a device going through an SMP phy-control driven reset), - * we need to wait until the phy comes back up before letting - * discovery proceed in libsas. - */ - isci_wait_for_smp_phy_reset(idev, phy->number); - - spin_lock_irqsave(&ihost->scic_lock, flags); - isci_port_bcn_enable(ihost, idev->isci_port); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - } - if (status != SCI_SUCCESS) { dev_dbg(&ihost->pdev->dev, "%s: sci_remote_device_reset_complete(%p) " |