libsas: Convert ATA bridge to use new EH
Subsystems (2)
PATCH 1/2 libsas: Convert ATA bridge to use new EH
Migrate the sas_ata bridge to use the new libata EH strategy, and finally implement correct software reset.
WARNING WARNING WARNING! This patch is for experimental use only; it is nowhere near complete! Especially the sas_ata_freeze() function. This patch may eat your data and kill your trees.
jgarzik: If an ATA command was in-progress at the time of a port freeze, can complete after thawing? (Does that even make sense?)
Comments-requested-by Darrick J. Wong <[email protected]>
---
drivers/scsi/libsas/sas_ata.c | 86 ++++++++++++++++++++++++++++++++++------- 1 files changed, 71 insertions(+), 15 deletions(-)
drivers/scsi/libsas/sas_ata.c +71 -15
@@ -35,6 +35,8 @@#include "../scsi_transport_api.h" #include <scsi/scsi_eh.h> +static int sas_issue_ata_srst (struct domain_device *dev); +static enum ata_completion_errors sas_to_ata_err (struct task_status_struct *ts) {/* Cheesy attempt to translate SAS errors into ATA. Hah! */
@@ -233,37 +235,58 @@ static u8 sas_ata_check_status(struct ata_port *ap)return dev->sata_dev.tf.command; } -static void sas_ata_phy_reset (struct ata_port *ap) +static void sas_ata_freeze (struct ata_port *ap) { -struct domain_device *dev = ap->private_data; -struct sas_internal *i = -to_sas_internal (dev->port->ha->core.shost->transportt); -int res =0 ; +/* reroute qc_done for all qc's on this port to a dumb free func */ +/* i wonder if we can get away with throwing out anything that +* completes in this time frame, or if we must find the commands +* that are in progress and cancel only those? */ +printk (KERN_ERR "%s: STUB\n" , __FUNCTION__); +} -if (i->dft->lldd_I_T_nexus_reset) - res = i->dft->lldd_I_T_nexus_reset (dev); +static void sas_ata_thaw (struct ata_port *ap) +{ +/* empty */ +printk (KERN_ERR "%s: STUB\n" , __FUNCTION__); +} -if (res) -SAS_DPRINTK ("%s: Unable to reset I T nexus?\n" , __FUNCTION__); +static int sas_ata_soft_reset (struct ata_link *link,unsigned int *classes, +unsigned long deadline) +{ +struct ata_port *ap = link->ap; +struct domain_device *dev = ap->private_data; +int res; +/* Send SRST to device */ + res =sas_issue_ata_srst (dev); +printk (KERN_ERR "srst 0 returns %d\n" , res); + +/* Set new device type */ switch (dev->sata_dev.command_set) {case ATA_COMMAND_SET :SAS_DPRINTK ("%s: Found ATA device.\n" , __FUNCTION__); - ap->link.device[0 ].class =ATA_DEV_ATA ; + *classes =ATA_DEV_ATA ;break ;case ATAPI_COMMAND_SET :SAS_DPRINTK ("%s: Found ATAPI device.\n" , __FUNCTION__); - ap->link.device[0 ].class =ATA_DEV_ATAPI ; + *classes =ATA_DEV_ATAPI ;break ;default :SAS_DPRINTK ("%s: Unknown SATA command set: %d.\n" , __FUNCTION__, dev->sata_dev.command_set); - ap->link.device[0 ].class =ATA_DEV_UNKNOWN ; -break ; + *classes =ATA_DEV_UNKNOWN ; +break ; } - ap->cbl =ATA_CBL_SATA ; +/* FIXME: What if SRST fails? */ +return 0 ; +} + +static void sas_ata_error_handler (struct ata_port *ap) +{ +ata_do_eh (ap,NULL , sas_ata_soft_reset,NULL ,NULL ); +//uh... hopefully there's no commands left in here? }static void sas_ata_post_internal (struct ata_queued_cmd *qc)
@@ -353,7 +376,9 @@ static struct ata_port_operations sas_sata_ops = { .check_status = sas_ata_check_status, .check_altstatus = sas_ata_check_status, .dev_select = ata_noop_dev_select, - .phy_reset = sas_ata_phy_reset, + .error_handler = sas_ata_error_handler, + .freeze = sas_ata_freeze, + .thaw = sas_ata_thaw, .post_internal_cmd = sas_ata_post_internal, .tf_read = sas_ata_tf_read, .qc_prep = ata_noop_qc_prep,
@@ -658,6 +683,37 @@ out:return res; } +static int sas_issue_ata_srst (struct domain_device *dev) +{ +int res =0 ; +struct sas_task *task; +struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *) + &dev->frame_rcvd[0 ]; + + res = -ENOMEM ; + task =sas_alloc_task (GFP_KERNEL ); +if (!task) + goto out; + + task->dev = dev; + + task->ata_task.fis.fis_type =0x27 ; +/* FIXME: What's a good dummy command? */ + task->ata_task.fis.command =ATA_CMD_CHK_POWER ; + task->ata_task.fis.features =0 ; + task->ata_task.fis.control =ATA_SRST ; + task->ata_task.fis.device = d2h_fis->device; + task->ata_task.retry_count =1 ; + task->ata_task.device_control_reg_update =1 ; + + res =sas_execute_task (task,NULL ,0 ,DMA_NONE ); + +sas_free_task (task); +out: + +return res; +} +static void sas_sata_propagate_sas_addr (struct domain_device *dev) {unsigned long flags;