diff options
Diffstat (limited to 'drivers/scsi/pm8001/pm8001_sas.c')
-rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.c | 70 |
1 files changed, 48 insertions, 22 deletions
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 7e48154e11c3..b7cbc312843e 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -119,7 +119,7 @@ int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr, mem_virt_alloc = dma_alloc_coherent(&pdev->dev, mem_size + align, &mem_dma_handle, GFP_KERNEL); if (!mem_virt_alloc) { - pm8001_printk("memory allocation error\n"); + pr_err("pm80xx: memory allocation error\n"); return -1; } *pphys_addr = mem_dma_handle; @@ -249,6 +249,8 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, spin_unlock_irqrestore(&pm8001_ha->lock, flags); return 0; default: + PM8001_DEVIO_DBG(pm8001_ha, + pm8001_printk("func 0x%x\n", func)); rc = -EOPNOTSUPP; } msleep(300); @@ -384,8 +386,9 @@ static int pm8001_task_exec(struct sas_task *task, struct pm8001_port *port = NULL; struct sas_task *t = task; struct pm8001_ccb_info *ccb; - u32 tag = 0xdeadbeef, rc, n_elem = 0; + u32 tag = 0xdeadbeef, rc = 0, n_elem = 0; unsigned long flags = 0; + enum sas_protocol task_proto = t->task_proto; if (!dev->port) { struct task_status_struct *tsm = &t->task_status; @@ -410,7 +413,7 @@ static int pm8001_task_exec(struct sas_task *task, pm8001_dev = dev->lldd_dev; port = &pm8001_ha->port[sas_find_local_port_id(dev)]; if (DEV_IS_GONE(pm8001_dev) || !port->port_attached) { - if (sas_protocol_ata(t->task_proto)) { + if (sas_protocol_ata(task_proto)) { struct task_status_struct *ts = &t->task_status; ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_PHY_DOWN; @@ -432,7 +435,7 @@ static int pm8001_task_exec(struct sas_task *task, goto err_out; ccb = &pm8001_ha->ccb_info[tag]; - if (!sas_protocol_ata(t->task_proto)) { + if (!sas_protocol_ata(task_proto)) { if (t->num_scatter) { n_elem = dma_map_sg(pm8001_ha->dev, t->scatter, @@ -452,7 +455,7 @@ static int pm8001_task_exec(struct sas_task *task, ccb->ccb_tag = tag; ccb->task = t; ccb->device = pm8001_dev; - switch (t->task_proto) { + switch (task_proto) { case SAS_PROTOCOL_SMP: rc = pm8001_task_prep_smp(pm8001_ha, ccb); break; @@ -469,8 +472,7 @@ static int pm8001_task_exec(struct sas_task *task, break; default: dev_printk(KERN_ERR, pm8001_ha->dev, - "unknown sas_task proto: 0x%x\n", - t->task_proto); + "unknown sas_task proto: 0x%x\n", task_proto); rc = -EINVAL; break; } @@ -493,7 +495,7 @@ err_out_tag: pm8001_tag_free(pm8001_ha, tag); err_out: dev_printk(KERN_ERR, pm8001_ha->dev, "pm8001 exec failed[%d]!\n", rc); - if (!sas_protocol_ata(t->task_proto)) + if (!sas_protocol_ata(task_proto)) if (n_elem) dma_unmap_sg(pm8001_ha->dev, t->scatter, t->num_scatter, t->data_dir); @@ -1179,7 +1181,7 @@ int pm8001_query_task(struct sas_task *task) break; } } - pm8001_printk(":rc= %d\n", rc); + pr_err("pm80xx: rc= %d\n", rc); return rc; } @@ -1202,8 +1204,8 @@ int pm8001_abort_task(struct sas_task *task) pm8001_dev = dev->lldd_dev; pm8001_ha = pm8001_find_ha_by_dev(dev); phy_id = pm8001_dev->attached_phy; - rc = pm8001_find_tag(task, &tag); - if (rc == 0) { + ret = pm8001_find_tag(task, &tag); + if (ret == 0) { pm8001_printk("no tag for task:%p\n", task); return TMF_RESP_FUNC_FAILED; } @@ -1241,26 +1243,50 @@ int pm8001_abort_task(struct sas_task *task) /* 2. Send Phy Control Hard Reset */ reinit_completion(&completion); + phy->port_reset_status = PORT_RESET_TMO; phy->reset_success = false; phy->enable_completion = &completion; phy->reset_completion = &completion_reset; ret = PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id, PHY_HARD_RESET); - if (ret) - goto out; - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Waiting for local phy ctl\n")); - wait_for_completion(&completion); - if (!phy->reset_success) + if (ret) { + phy->enable_completion = NULL; + phy->reset_completion = NULL; goto out; + } - /* 3. Wait for Port Reset complete / Port reset TMO */ + /* In the case of the reset timeout/fail we still + * abort the command at the firmware. The assumption + * here is that the drive is off doing something so + * that it's not processing requests, and we want to + * avoid getting a completion for this and either + * leaking the task in libsas or losing the race and + * getting a double free. + */ PM8001_MSG_DBG(pm8001_ha, + pm8001_printk("Waiting for local phy ctl\n")); + ret = wait_for_completion_timeout(&completion, + PM8001_TASK_TIMEOUT * HZ); + if (!ret || !phy->reset_success) { + phy->enable_completion = NULL; + phy->reset_completion = NULL; + } else { + /* 3. Wait for Port Reset complete or + * Port reset TMO + */ + PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Waiting for Port reset\n")); - wait_for_completion(&completion_reset); - if (phy->port_reset_status) { - pm8001_dev_gone_notify(dev); - goto out; + ret = wait_for_completion_timeout( + &completion_reset, + PM8001_TASK_TIMEOUT * HZ); + if (!ret) + phy->reset_completion = NULL; + WARN_ON(phy->port_reset_status == + PORT_RESET_TMO); + if (phy->port_reset_status == PORT_RESET_TMO) { + pm8001_dev_gone_notify(dev); + goto out; + } } /* |