diff options
Diffstat (limited to 'drivers/scsi/libsas/sas_ata.c')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 80 |
1 files changed, 22 insertions, 58 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 4d3b704ede1c..31fc21f4d831 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -71,13 +71,13 @@ static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts) case SAS_SG_ERR: return AC_ERR_INVALID; - case SAM_STAT_CHECK_CONDITION: case SAS_OPEN_TO: case SAS_OPEN_REJECT: SAS_DPRINTK("%s: Saw error %d. What to do?\n", __func__, ts->stat); return AC_ERR_OTHER; + case SAM_STAT_CHECK_CONDITION: case SAS_ABORTED_TASK: return AC_ERR_DEV; @@ -107,13 +107,15 @@ static void sas_ata_task_done(struct sas_task *task) sas_ha = dev->port->ha; spin_lock_irqsave(dev->sata_dev.ap->lock, flags); - if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD) { + if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD || + ((stat->stat == SAM_STAT_CHECK_CONDITION && + dev->sata_dev.command_set == ATAPI_COMMAND_SET))) { ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf); qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command); dev->sata_dev.sstatus = resp->sstatus; dev->sata_dev.serror = resp->serror; dev->sata_dev.scontrol = resp->scontrol; - } else if (stat->stat != SAM_STAT_GOOD) { + } else { ac = sas_to_ata_err(stat); if (ac) { SAS_DPRINTK("%s: SAS error %x\n", __func__, @@ -305,55 +307,6 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc) } } -static int sas_ata_scr_write(struct ata_link *link, unsigned int sc_reg_in, - u32 val) -{ - struct domain_device *dev = link->ap->private_data; - - SAS_DPRINTK("STUB %s\n", __func__); - switch (sc_reg_in) { - case SCR_STATUS: - dev->sata_dev.sstatus = val; - break; - case SCR_CONTROL: - dev->sata_dev.scontrol = val; - break; - case SCR_ERROR: - dev->sata_dev.serror = val; - break; - case SCR_ACTIVE: - dev->sata_dev.ap->link.sactive = val; - break; - default: - return -EINVAL; - } - return 0; -} - -static int sas_ata_scr_read(struct ata_link *link, unsigned int sc_reg_in, - u32 *val) -{ - struct domain_device *dev = link->ap->private_data; - - SAS_DPRINTK("STUB %s\n", __func__); - switch (sc_reg_in) { - case SCR_STATUS: - *val = dev->sata_dev.sstatus; - return 0; - case SCR_CONTROL: - *val = dev->sata_dev.scontrol; - return 0; - case SCR_ERROR: - *val = dev->sata_dev.serror; - return 0; - case SCR_ACTIVE: - *val = dev->sata_dev.ap->link.sactive; - return 0; - default: - return -EINVAL; - } -} - static struct ata_port_operations sas_sata_ops = { .prereset = ata_std_prereset, .softreset = NULL, @@ -367,8 +320,6 @@ static struct ata_port_operations sas_sata_ops = { .qc_fill_rtf = sas_ata_qc_fill_rtf, .port_start = ata_sas_port_start, .port_stop = ata_sas_port_stop, - .scr_read = sas_ata_scr_read, - .scr_write = sas_ata_scr_write }; static struct ata_port_info sata_port_info = { @@ -801,7 +752,7 @@ void sas_ata_strategy_handler(struct Scsi_Host *shost) if (!dev_is_sata(ddev)) continue; - + ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata port error handler"); ata_scsi_port_error_handler(shost, ap); } @@ -834,13 +785,13 @@ int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, LIST_HEAD(sata_q); ap = NULL; - + list_for_each_entry_safe(cmd, n, work_q, eh_entry) { struct domain_device *ddev = cmd_to_domain_dev(cmd); if (!dev_is_sata(ddev) || TO_SAS_TASK(cmd)) continue; - if(ap && ap != ddev->sata_dev.ap) + if (ap && ap != ddev->sata_dev.ap) continue; ap = ddev->sata_dev.ap; rtn = 1; @@ -848,8 +799,21 @@ int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, } if (!list_empty(&sata_q)) { - ata_port_printk(ap, KERN_DEBUG,"sas eh calling libata cmd error handler\n"); + ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata cmd error handler\n"); ata_scsi_cmd_error_handler(shost, ap, &sata_q); + /* + * ata's error handler may leave the cmd on the list + * so make sure they don't remain on a stack list + * about to go out of scope. + * + * This looks strange, since the commands are + * now part of no list, but the next error + * action will be ata_port_error_handler() + * which takes no list and sweeps them up + * anyway from the ata tag array. + */ + while (!list_empty(&sata_q)) + list_del_init(sata_q.next); } } while (ap); |