From 6ef1b512f4e6f936d89aa20be3d97a7ec7c290ac Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 Jun 2012 10:52:34 -0700 Subject: [SCSI] libsas: fix taskfile corruption in sas_ata_qc_fill_rtf fill_result_tf() grabs the taskfile flags from the originating qc which sas_ata_qc_fill_rtf() promptly overwrites. The presence of an ata_taskfile in the sata_device makes it tempting to just copy the full contents in sas_ata_qc_fill_rtf(). However, libata really only wants the fis contents and expects the other portions of the taskfile to not be touched by ->qc_fill_rtf. To that end store a fis buffer in the sata_device and use ata_tf_from_fis() like every other ->qc_fill_rtf() implementation. Cc: Reported-by: Praveen Murali Tested-by: Praveen Murali Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- include/scsi/libsas.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'include/scsi/libsas.h') diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index f4f1c96dca72..10ce74f589c5 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -163,6 +163,8 @@ enum ata_command_set { ATAPI_COMMAND_SET = 1, }; +#define ATA_RESP_FIS_SIZE 24 + struct sata_device { enum ata_command_set command_set; struct smp_resp rps_resp; /* report_phy_sata_resp */ @@ -171,7 +173,7 @@ struct sata_device { struct ata_port *ap; struct ata_host ata_host; - struct ata_taskfile tf; + u8 fis[ATA_RESP_FIS_SIZE]; }; enum { @@ -537,7 +539,7 @@ enum exec_status { */ struct ata_task_resp { u16 frame_len; - u8 ending_fis[24]; /* dev to host or data-in */ + u8 ending_fis[ATA_RESP_FIS_SIZE]; /* dev to host or data-in */ }; #define SAS_STATUS_BUF_SIZE 96 -- cgit v1.2.3 From e4a9c3732cea3e3c8c704aad86636090ffe6b25f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:25:27 -0700 Subject: [SCSI] libata, libsas: introduce sched_eh and end_eh port ops When managing shost->host_eh_scheduled libata assumes that there is a 1:1 shost-to-ata_port relationship. libsas creates a 1:N relationship so it needs to manage host_eh_scheduled cumulatively at the host level. The sched_eh and end_eh port port ops allow libsas to track when domain devices enter/leave the "eh-pending" state under ha->lock (previously named ha->state_lock, but it is no longer just a lock for ha->state changes). Since host_eh_scheduled indicates eh without backing commands pinning the device it can be deallocated at any time. Move the taking of the domain_device reference under the port_lock to guarantee that the ata_port stays around for the duration of eh. Reviewed-by: Jacek Danecki Acked-by: Jeff Garzik Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- include/scsi/libsas.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include/scsi/libsas.h') diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 10ce74f589c5..814d8cb592ad 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -179,6 +179,7 @@ struct sata_device { enum { SAS_DEV_GONE, SAS_DEV_DESTROY, + SAS_DEV_EH_PENDING, }; struct domain_device { @@ -386,7 +387,8 @@ struct sas_ha_struct { struct list_head defer_q; /* work queued while draining */ struct mutex drain_mutex; unsigned long state; - spinlock_t state_lock; + spinlock_t lock; + int eh_active; struct mutex disco_mutex; -- cgit v1.2.3 From 5db45bdc87ce4f503947adf7896586d60c63322c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:30:48 -0700 Subject: [SCSI] libsas: enforce eh strategy handlers only in eh context The strategy handlers may be called in places that are problematic for libsas (i.e. sata resets outside of domain revalidation filtering / libata link recovery), or problematic for userspace (non-blocking ioctl to sleeping reset functions). However, these routines are also called for eh escalations and recovery of scsi_eh_prep_cmnd(), so permit them as long as we are running in the host's error handler, otherwise arrange for them to be triggered in eh_context. Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- include/scsi/libsas.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include/scsi/libsas.h') diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 814d8cb592ad..df9cefdf2a8e 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -176,10 +176,17 @@ struct sata_device { u8 fis[ATA_RESP_FIS_SIZE]; }; +struct ssp_device { + struct list_head eh_list_node; /* pending a user requested eh action */ + struct scsi_lun reset_lun; +}; + enum { SAS_DEV_GONE, SAS_DEV_DESTROY, SAS_DEV_EH_PENDING, + SAS_DEV_LU_RESET, + SAS_DEV_RESET, }; struct domain_device { @@ -213,6 +220,7 @@ struct domain_device { union { struct expander_device ex_dev; struct sata_device sata_dev; /* STP & directly attached */ + struct ssp_device ssp_dev; }; void *lldd_dev; @@ -389,6 +397,8 @@ struct sas_ha_struct { unsigned long state; spinlock_t lock; int eh_active; + wait_queue_head_t eh_wait_q; + struct list_head eh_dev_q; struct mutex disco_mutex; -- cgit v1.2.3 From 9524c6821849bddad4bf592a47276cfb8a8a98c0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:30:53 -0700 Subject: [SCSI] libsas: add sas_eh_abort_handler When recovering failed eh-cmnds let the lldd attempt an abort via scsi_abort_eh_cmnd before escalating. Reviewed-by: Jacek Danecki Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- include/scsi/libsas.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/scsi/libsas.h') diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index df9cefdf2a8e..acefe13ebacf 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -720,6 +720,7 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *); void sas_init_dev(struct domain_device *); void sas_task_abort(struct sas_task *); +int sas_eh_abort_handler(struct scsi_cmnd *cmd); int sas_eh_device_reset_handler(struct scsi_cmnd *cmd); int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd); -- cgit v1.2.3 From a494fd5bd98bb35d5a9a274fecb768e14ebf499c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:36:25 -0700 Subject: [SCSI] libsas: drop sata port multiplier infrastructure On the way to add a new sata_device field, noticed that libsas is carrying port multiplier infrastructure that is explicitly disabled by sas_discover_sata(). The aic94xx touches the unused port_no, so leave that field in case there was some use for it. Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- include/scsi/libsas.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/scsi/libsas.h') diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index acefe13ebacf..29a8cc7831af 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -169,7 +169,6 @@ struct sata_device { enum ata_command_set command_set; struct smp_resp rps_resp; /* report_phy_sata_resp */ u8 port_no; /* port number, if this is a PM (Port) */ - struct list_head children; /* PM Ports if this is a PM */ struct ata_port *ap; struct ata_host ata_host; -- cgit v1.2.3 From f0bf750c2d25c3a2131ececbff63c7878e0e3765 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Jun 2012 23:36:30 -0700 Subject: [SCSI] libsas: trim sas_task of slow path infrastructure The timer and the completion are only used for slow path tasks (smp, and lldd tmfs), yet we incur the allocation space and cpu setup time for every fast path task. Cc: Xiangliang Yu Acked-by: Jack Wang Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- include/scsi/libsas.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'include/scsi/libsas.h') diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 29a8cc7831af..ae33706afeb0 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -613,10 +613,6 @@ struct sas_task { enum sas_protocol task_proto; - /* Used by the discovery code. */ - struct timer_list timer; - struct completion completion; - union { struct sas_ata_task ata_task; struct sas_smp_task smp_task; @@ -633,8 +629,15 @@ struct sas_task { void *lldd_task; /* for use by LLDDs */ void *uldd_task; + struct sas_task_slow *slow_task; +}; - struct work_struct abort_work; +struct sas_task_slow { + /* standard/extra infrastructure for slow path commands (SMP and + * internal lldd commands + */ + struct timer_list timer; + struct completion completion; }; #define SAS_TASK_STATE_PENDING 1 @@ -644,6 +647,7 @@ struct sas_task { #define SAS_TASK_AT_INITIATOR 16 extern struct sas_task *sas_alloc_task(gfp_t flags); +extern struct sas_task *sas_alloc_slow_task(gfp_t flags); extern void sas_free_task(struct sas_task *task); struct sas_domain_function_template { -- cgit v1.2.3