libata: prep for PMP support, take 6
PATCH 1/2 libata: prep for PMP support, take 6
Hello, all.
This is the sixth take of libata-pmp-prep patchset. This patchset contains 12 patches implementing various stuff needed for PMP.
#01-04 : various small stuff
#05-06 : qc_defer mechanism implementation
#07-11 : link/device quirks and EH fast-fail path - things needed to
handle quirky PMP fan-out links / pseudo devices.
#12 : AN demultiplexer - sata_async_notification()
Change from the last take[L] are...
* Updated to handle both ATAPI AN and PMP AN as ATAPI AN has been merged inbetween. This is done by adding new patch #01 and updating patch #12.
This patchset is against
libata-dev#upstream (b56feca2ede0dd11a8409743ff14cf14cbcf5062)
+ [1] sata_sil24-fix-IRQ-clearing-race-when-PCIX_IRQ_WOC-is-used
Thanks.
--
tejun
[L] http://thread.gmane.org/gmane.linux.ide/20857
[1] http://article.gmane.org/gmane.linux.ide/22918
PATCH 1/12 libata: misc updates for AN
Update AN support in preparation of PMP support.
* s/ata_id_has_AN/ata_id_has_atapi_AN/
* add AN enabled reporting during configuration
* add err_mask to AN configuration failure reporting
* update LOCKING comment for ata_scsi_media_change_notify()
* check whether ATA dev is attached to SCSI dev ata_scsi_media_change_notify()
* set ATA_FLAG_AN in ahci and sata_sil24
--- drivers/ata/ahci.c | 2 +- drivers/ata/libata-core.c | 24 ++++++++++++++---------- drivers/ata/libata-scsi.c | 7 ++++--- drivers/ata/sata_sil24.c | 13 +++++++++++-- include/linux/ata.h | 2 +- 5 files changed, 31 insertions(+), 17 deletions(-)
drivers/ata/ahci.c +1 -1
@@ -177,7 +177,7 @@ enum {AHCI_FLAG_COMMON =ATA_FLAG_SATA |ATA_FLAG_NO_LEGACY |ATA_FLAG_MMIO |ATA_FLAG_PIO_DMA | -ATA_FLAG_ACPI_SATA , +ATA_FLAG_ACPI_SATA |ATA_FLAG_AN , AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY, };
drivers/ata/libata-core.c +14 -10
@@ -2012,7 +2012,8 @@ int ata_dev_configure(struct ata_device *dev)/* ATAPI-specific feature tests */ else if (dev->class == ATA_DEV_ATAPI) { -char *cdb_intr_string ="" ; +const char *cdb_intr_string ="" ; +const char *atapi_an_string ="" ; rc =atapi_cdb_len (id);if ((rc <12 ) || (rc >ATAPI_CDB_LEN )) {
@@ -2028,16 +2029,19 @@ int ata_dev_configure(struct ata_device *dev)* check to see if this ATAPI device supports * Asynchronous Notification */ -if ((ap->flags &ATA_FLAG_AN ) &&ata_id_has_AN (id)) { -int err; +if ((ap->flags &ATA_FLAG_AN ) &&ata_id_has_atapi_AN (id)) { +unsigned int err_mask; +/* issue SET feature command to turn this on */ - err =ata_dev_set_AN (dev,SETFEATURES_SATA_ENABLE ); -if (err) + err_mask =ata_dev_set_AN (dev,SETFEATURES_SATA_ENABLE ); +if (err_mask)ata_dev_printk (dev,KERN_ERR , -"unable to set AN, err %x\n" , - err); -else +"failed to enable ATAPI AN " +"(err_mask=0x%x)\n" , err_mask); +else { dev->flags |=ATA_DFLAG_AN ; + atapi_an_string =", ATAPI AN" ; + } }if (ata_id_cdb_intr (dev->id)) {
@@ -2048,10 +2052,10 @@ int ata_dev_configure(struct ata_device *dev)/* print device info to dmesg */ if (ata_msg_drv (ap) && print_info)ata_dev_printk (dev,KERN_INFO , -"ATAPI: %s, %s, max %s%s\n" , +"ATAPI: %s, %s, max %s%s%s\n" , modelbuf, fwrevbuf,ata_mode_string (xfer_mask), - cdb_intr_string); + cdb_intr_string, atapi_an_string); }/* determine max_sectors */
drivers/ata/libata-scsi.c +4 -3
@@ -3161,12 +3161,13 @@ static void ata_scsi_handle_link_detach(struct ata_link *link)* event. * * LOCKING: -* interrupt context, may not sleep. +* spin_lock_irqsave(host lock) */ -void ata_scsi_media_change_notify (struct ata_device *atadev) +void ata_scsi_media_change_notify (struct ata_device *dev) {#ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED -scsi_device_event_notify (atadev->sdev,SDEV_MEDIA_CHANGE ); +if (dev->sdev) +scsi_device_event_notify (dev->sdev,SDEV_MEDIA_CHANGE );#endif }EXPORT_SYMBOL_GPL (ata_scsi_media_change_notify);
drivers/ata/sata_sil24.c +11 -2
@@ -168,7 +168,7 @@ enum {DEF_PORT_IRQ =PORT_IRQ_COMPLETE |PORT_IRQ_ERROR |PORT_IRQ_PHYRDY_CHG |PORT_IRQ_DEV_XCHG | -PORT_IRQ_UNK_FIS , +PORT_IRQ_UNK_FIS |PORT_IRQ_SDB_NOTIFY ,/* bits[27:16] are unmasked (raw) */ PORT_IRQ_RAW_SHIFT = 16,
@@ -237,7 +237,8 @@ enum {/* host flags */ SIL24_COMMON_FLAGS =ATA_FLAG_SATA |ATA_FLAG_NO_LEGACY |ATA_FLAG_MMIO |ATA_FLAG_PIO_DMA | -ATA_FLAG_NCQ |ATA_FLAG_ACPI_SATA , +ATA_FLAG_NCQ |ATA_FLAG_ACPI_SATA | +ATA_FLAG_AN ,SIL24_COMMON_LFLAGS =ATA_LFLAG_SKIP_D2H_BSY , SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
@@ -818,6 +819,14 @@ static void sil24_error_intr(struct ata_port *ap)ata_ehi_push_desc (ehi,"irq_stat 0x%08x" , irq_stat); +if (irq_stat &PORT_IRQ_SDB_NOTIFY ) { +struct ata_device *dev = ap->link.device; + +ata_ehi_push_desc (ehi,"SDB notify" ); +if (dev->flags &ATA_DFLAG_AN ) +ata_scsi_media_change_notify (dev); + } +if (irq_stat & (PORT_IRQ_PHYRDY_CHG |PORT_IRQ_DEV_XCHG )) {ata_ehi_hotplugged (ehi); ata_ehi_push_desc(ehi, "%s",
include/linux/ata.h +1 -1
@@ -353,7 +353,7 @@ struct ata_taskfile {#define ata_id_queue_depth (id) (((id)[75] & 0x1f) + 1)#define ata_id_removeable (id) ((id)[0] & (1 << 7))#define ata_id_has_dword_io (id) ((id)[48] & (1 << 0)) -#define ata_id_has_AN (id) \ +#define ata_id_has_atapi_AN (id) \ ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \ ((id)[78] & (1 << 5)) )#define ata_id_iordy_disable (id) ((id)[49] & (1 << 10))
Signature · 1 line
1.5.0.3
Re: [PATCH 01/12] libata: misc updates for AN
Quoted 11 lines · Tejun Heo
Update AN support in preparation of PMP support.
* s/ata_id_has_AN/ata_id_has_atapi_AN/
* add AN enabled reporting during configuration
* adderr_maskto AN configuration failure reporting
* update LOCKING comment forata_scsi_media_change_notify()
* check whether ATA dev is attached to SCSI devata_scsi_media_change_notify()
* setATA_FLAG_ANin ahci andsata_sil24Signed-off-by Tejun Heo <[email protected]>Cc Kriten Carlson Accardi <[email protected]>
Quoted 7 lines
--- drivers/ata/ahci.c | 2 +- drivers/ata/libata-core.c | 24 ++++++++++++++---------- drivers/ata/libata-scsi.c | 7 ++++--- drivers/ata/sata_sil24.c | 13 +++++++++++-- include/linux/ata.h | 2 +- 5 files changed, 31 insertions(+), 17 deletions(-)
applied 1-12
PATCH 2/12 libata-pmp-prep: add PMP related constants, fields, ops and update helpers
In reply to Tejun HeoAdd PMP related constants, fields and ops. Also, update ata_class_enabled/disabled() such that PMP classes are considered.
--- include/linux/libata.h | 30 ++++++++++++++++++++++++++---- 1 files changed, 26 insertions(+), 4 deletions(-)
include/linux/libata.h +26 -4
@@ -155,7 +155,11 @@ enum {ATA_DEV_ATA_UNSUP =2 ,/* ATA device (unsupported) */ ATA_DEV_ATAPI =3 ,/* ATAPI device */ ATA_DEV_ATAPI_UNSUP =4 ,/* ATAPI device (unsupported) */ -ATA_DEV_NONE =5 ,/* no device */ +ATA_DEV_PMP =5 ,/* SATA port multiplier */ +ATA_DEV_PMP_UNSUP =6 ,/* SATA port multiplier (unsupported) */ +ATA_DEV_SEMB =7 ,/* SEMB */ +ATA_DEV_SEMB_UNSUP =8 ,/* SEMB (unsupported) */ +ATA_DEV_NONE =9 ,/* no device */ /* struct ata_link flags */ ATA_LFLAG_HRST_TO_RESUME = (1 << 0), /* hardreset to resume link */
@@ -181,6 +185,7 @@ enum {ATA_FLAG_NO_IORDY = (1 <<16 ),/* controller lacks iordy */ ATA_FLAG_ACPI_SATA = (1 <<17 ),/* need native SATA ACPI layout */ ATA_FLAG_AN = (1 <<18 ),/* controller supports AN */ +ATA_FLAG_PMP = (1 <<19 ),/* controller supports PMP */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be
@@ -299,6 +304,10 @@ enum {/* how hard are we gonna try to probe/recover devices */ ATA_PROBE_MAX_TRIES =3 ,ATA_EH_DEV_TRIES =3 , +ATA_EH_PMP_TRIES =5 , +ATA_EH_PMP_LINK_TRIES =3 , + +SATA_PMP_SCR_TIMEOUT =250 ,/* Horkage types. May be set by libata or controller on drives (some horkage may be drive/controller pair dependant */
@@ -450,7 +459,12 @@ struct ata_device {/* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */ u64 n_sectors;/* size of device, if ATA */ unsigned int class;/* ATA_DEV_xxx */ -u16 id[ATA_ID_WORDS ];/* IDENTIFY xxx DEVICE data */ + +union { +u16 id[ATA_ID_WORDS ];/* IDENTIFY xxx DEVICE data */ +u32 gscr[SATA_PMP_GSCR_DWORDS ];/* PMP GSCR block */ + }; +u8 pio_mode;u8 dma_mode;u8 xfer_mode;
@@ -628,6 +642,12 @@ struct ata_port_operations {void (*qc_prep) (struct ata_queued_cmd *qc);unsigned int (*qc_issue) (struct ata_queued_cmd *qc); +/* port multiplier */ +void (*pmp_attach) (struct ata_port *ap); +void (*pmp_detach) (struct ata_port *ap); +int (*pmp_read) (struct ata_device *dev,int pmp,int reg,u32 *r_val); +int (*pmp_write) (struct ata_device *dev,int pmp,int reg,u32 val); +/* Error handlers. ->error_handler overrides ->eng_timeout and * indicates that new-style EH is in place. */
@@ -1033,12 +1053,14 @@ static inline unsigned int ata_tag_internal(unsigned int tag)*/ static inline unsigned int ata_class_enabled (unsigned int class) { -return class ==ATA_DEV_ATA || class ==ATA_DEV_ATAPI ; +return class ==ATA_DEV_ATA || class ==ATA_DEV_ATAPI || + class ==ATA_DEV_PMP || class ==ATA_DEV_SEMB ; }static inline unsigned int ata_class_disabled (unsigned int class) { -return class ==ATA_DEV_ATA_UNSUP || class ==ATA_DEV_ATAPI_UNSUP ; +return class ==ATA_DEV_ATA_UNSUP || class ==ATA_DEV_ATAPI_UNSUP || + class ==ATA_DEV_PMP_UNSUP || class ==ATA_DEV_SEMB_UNSUP ; }static inline unsigned int ata_class_absent (unsigned int class)
Signature · 1 line
1.5.0.3
PATCH 3/12 libata-pmp-prep: add @new_class to ata_dev_revalidate()
In reply to Tejun HeoConsider newly found class code while revalidating. PMP resetting always results in valid class code and issuing PMP commands to ATA/ATAPI device isn't very attractive. Add @new_class to ata_dev_revalidate() and check class code for revalidation.
--- drivers/ata/libata-core.c | 15 +++++++++++++-- drivers/ata/libata-eh.c | 3 ++- drivers/ata/libata.h | 3 ++- 3 files changed, 17 insertions(+), 4 deletions(-)
drivers/ata/libata-core.c +13 -2
@@ -2848,7 +2848,7 @@ static int ata_dev_set_mode(struct ata_device *dev) } ehc->i.flags |=ATA_EHI_POST_SETMODE ; - rc =ata_dev_revalidate (dev,0 ); + rc =ata_dev_revalidate (dev,ATA_DEV_UNKNOWN ,0 ); ehc->i.flags &= ~ATA_EHI_POST_SETMODE ;if (rc)return rc;
@@ -3752,6 +3752,7 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)/** * ata_dev_revalidate - Revalidate ATA device * @dev: device to revalidate +* @new_class: new class code * @readid_flags: read ID flags * * Re-read IDENTIFY page, make sure @dev is still attached to the
@@ -3763,7 +3764,8 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)* RETURNS: * 0 on success, negative errno otherwise */ -int ata_dev_revalidate (struct ata_device *dev,unsigned int readid_flags) +int ata_dev_revalidate (struct ata_device *dev,unsigned int new_class, +unsigned int readid_flags) {u64 n_sectors = dev->n_sectors;int rc;
@@ -3771,6 +3773,15 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)if (!ata_dev_enabled (dev))return -ENODEV ; +/* fail early if !ATA && !ATAPI to avoid issuing [P]IDENTIFY to PMP */ +if (ata_class_enabled (new_class) && + new_class !=ATA_DEV_ATA && new_class !=ATA_DEV_ATAPI ) { +ata_dev_printk (dev,KERN_INFO ,"class mismatch %u != %u\n" , + dev->class, new_class); + rc = -ENODEV ; + goto fail; + } +/* re-read ID */ rc =ata_dev_reread_id (dev, readid_flags);if (rc)
drivers/ata/libata-eh.c +2 -1
@@ -2104,7 +2104,8 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, }ata_eh_about_to_do (link, dev,ATA_EH_REVALIDATE ); - rc =ata_dev_revalidate (dev, readid_flags); + rc =ata_dev_revalidate (dev, ehc->classes[dev->devno], + readid_flags);if (rc) goto err;
drivers/ata/libata.h +2 -1
@@ -77,7 +77,8 @@ extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);extern int ata_dev_read_id (struct ata_device *dev,unsigned int *p_class,unsigned int flags,u16 *id);extern int ata_dev_reread_id (struct ata_device *dev,unsigned int readid_flags); -extern int ata_dev_revalidate (struct ata_device *dev,unsigned int readid_flags); +extern int ata_dev_revalidate (struct ata_device *dev,unsigned int new_class, +unsigned int readid_flags);extern int ata_dev_configure (struct ata_device *dev);extern int sata_down_spd_limit (struct ata_link *link);extern int sata_set_spd_needed (struct ata_link *link);
Signature · 1 line
1.5.0.3
PATCH 4/12 libata-pmp-prep: make a number of functions global to libata
In reply to Tejun HeoMake a number of functions from libata-core.c and libata-eh.c global to libata (drivers/ata/libata.h). These will be used by PMP.
--- drivers/ata/libata-core.c | 4 ++-- drivers/ata/libata-eh.c | 31 +++++++++++++++---------------- drivers/ata/libata.h | 17 +++++++++++++++++ 3 files changed, 34 insertions(+), 18 deletions(-)
drivers/ata/libata-core.c +2 -2
@@ -6220,7 +6220,7 @@ void ata_dev_init(struct ata_device *dev)* LOCKING: * Kernel thread context (may sleep) */ -static void ata_link_init (struct ata_port *ap,struct ata_link *link,int pmp) +void ata_link_init (struct ata_port *ap,struct ata_link *link,int pmp) {int i;
@@ -6255,7 +6255,7 @@ static void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)* RETURNS: * 0 on success, -errno on failure. */ -static int sata_link_init_spd (struct ata_link *link) +int sata_link_init_spd (struct ata_link *link) {u32 scontrol, spd;int rc;
drivers/ata/libata-eh.c +15 -16
@@ -74,7 +74,6 @@ static const unsigned long ata_eh_reset_timeouts[] = { };static void __ata_port_freeze (struct ata_port *ap); -static void ata_eh_finish (struct ata_port *ap);#ifdef CONFIG_PM static void ata_eh_handle_port_suspend (struct ata_port *ap);static void ata_eh_handle_port_resume (struct ata_port *ap);
@@ -1015,7 +1014,7 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc)* LOCKING: * None. */ -static void ata_eh_detach_dev (struct ata_device *dev) +void ata_eh_detach_dev (struct ata_device *dev) {struct ata_link *link = dev->link;struct ata_port *ap = link->ap;
@@ -1052,8 +1051,8 @@ static void ata_eh_detach_dev(struct ata_device *dev)* LOCKING: * None. */ -static void ata_eh_about_to_do (struct ata_link *link,struct ata_device *dev, -unsigned int action) +void ata_eh_about_to_do (struct ata_link *link,struct ata_device *dev, +unsigned int action) {struct ata_port *ap = link->ap;struct ata_eh_info *ehi = &link->eh_info;
@@ -1095,8 +1094,8 @@ static void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,* LOCKING: * None. */ -static void ata_eh_done (struct ata_link *link,struct ata_device *dev, -unsigned int action) +void ata_eh_done (struct ata_link *link,struct ata_device *dev, +unsigned int action) {struct ata_eh_context *ehc = &link->eh_context;
@@ -1756,7 +1755,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)* LOCKING: * Kernel thread context (may sleep). */ -static void ata_eh_autopsy (struct ata_port *ap) +void ata_eh_autopsy (struct ata_port *ap) {struct ata_link *link;
@@ -1867,7 +1866,7 @@ static void ata_eh_link_report(struct ata_link *link)* LOCKING: * None. */ -static void ata_eh_report (struct ata_port *ap) +void ata_eh_report (struct ata_port *ap) {struct ata_link *link;
@@ -1918,9 +1917,9 @@ static int ata_eh_followup_srst_needed(int rc, int classify,return 0 ; } -static int ata_eh_reset (struct ata_link *link,int classify, -ata_prereset_fn_t prereset,ata_reset_fn_t softreset, -ata_reset_fn_t hardreset,ata_postreset_fn_t postreset) +int ata_eh_reset (struct ata_link *link,int classify, +ata_prereset_fn_t prereset,ata_reset_fn_t softreset, +ata_reset_fn_t hardreset,ata_postreset_fn_t postreset) {struct ata_eh_context *ehc = &link->eh_context;unsigned int *classes = ehc->classes;
@@ -2296,10 +2295,10 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)* RETURNS: * 0 on success, -errno on failure. */ -static int ata_eh_recover (struct ata_port *ap,ata_prereset_fn_t prereset, -ata_reset_fn_t softreset,ata_reset_fn_t hardreset, -ata_postreset_fn_t postreset, -struct ata_link **r_failed_link) +int ata_eh_recover (struct ata_port *ap,ata_prereset_fn_t prereset, +ata_reset_fn_t softreset,ata_reset_fn_t hardreset, +ata_postreset_fn_t postreset, +struct ata_link **r_failed_link) {struct ata_link *link;struct ata_device *dev;
@@ -2445,7 +2444,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,* LOCKING: * None. */ -static void ata_eh_finish (struct ata_port *ap) +void ata_eh_finish (struct ata_port *ap) {int tag;
drivers/ata/libata.h +17 -0
@@ -94,6 +94,8 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device,extern void swap_buf_le16 (u16 *buf,unsigned int buf_words);extern int ata_flush_cache (struct ata_device *dev);extern void ata_dev_init (struct ata_device *dev); +extern void ata_link_init (struct ata_port *ap,struct ata_link *link,int pmp); +extern int sata_link_init_spd (struct ata_link *link);extern int ata_task_ioctl (struct scsi_device *scsidev,void __user *arg);extern int ata_cmd_ioctl (struct scsi_device *scsidev,void __user *arg);extern struct ata_port *ata_port_alloc (struct ata_host *host);
@@ -155,6 +157,21 @@ extern void ata_scsi_error(struct Scsi_Host *host);extern void ata_port_wait_eh (struct ata_port *ap);extern void ata_eh_fastdrain_timerfn (unsigned long arg);extern void ata_qc_schedule_eh (struct ata_queued_cmd *qc); +extern void ata_eh_detach_dev (struct ata_device *dev); +extern void ata_eh_about_to_do (struct ata_link *link,struct ata_device *dev, +unsigned int action); +extern void ata_eh_done (struct ata_link *link,struct ata_device *dev, +unsigned int action); +extern void ata_eh_autopsy (struct ata_port *ap); +extern void ata_eh_report (struct ata_port *ap); +extern int ata_eh_reset (struct ata_link *link,int classify, +ata_prereset_fn_t prereset,ata_reset_fn_t softreset, +ata_reset_fn_t hardreset,ata_postreset_fn_t postreset); +extern int ata_eh_recover (struct ata_port *ap,ata_prereset_fn_t prereset, +ata_reset_fn_t softreset,ata_reset_fn_t hardreset, +ata_postreset_fn_t postreset, +struct ata_link **r_failed_disk); +extern void ata_eh_finish (struct ata_port *ap);/* libata-sff.c */ extern u8 ata_irq_on (struct ata_port *ap);
Signature · 1 line
1.5.0.3
PATCH 5/12 libata-pmp-prep: implement ops->qc_defer()
In reply to Tejun HeoControllers which support PMP have various restrictions on which combinations of commands are allowed to what number of devices concurrently. This patch implements ops->qc_defer() which determines whether a qc can be issued at the moment or should be deferred.
If the function returns ATA_DEFER_LINK, the qc will be deferred until a qc completes on the link. If ATA_DEFER_PORT, until a qc completes on any link. The defer conditions are advisory and in general ATA_DEFER_LINK can be considered as lower priority deferring than ATA_DEFER_PORT.
ops->qc_defer() replaces fixed ata_scmd_need_defer(). For standard NCQ/non-NCQ exclusion, ata_std_qc_defer() is implemented. ahci and sata_sil24 are converted to use ata_std_qc_defer().
ops->qc_defer() is heavier than the original mechanism because full qc is prepped before determining to defer it, but various information is needed to determine defer conditinos and fully translating a qc is the only way to supply such information in generic manner.
IMHO, this shouldn't cause any noticeable performance issues as
* for most cases deferring occurs rarely (except for NCQ-aware cmd-switching PMP)
* translation itself isn't that expensive
* once deferred the command won't be repeated until another command completes which usually is a very long time cpu-wise.
--- drivers/ata/ahci.c | 2 + drivers/ata/libata-core.c | 31 ++++++++++++++++++++++ drivers/ata/libata-scsi.c | 62 +++++++++++++++++++-------------------------- drivers/ata/sata_nv.c | 1 + drivers/ata/sata_sil24.c | 1 + include/linux/libata.h | 6 ++++ 6 files changed, 67 insertions(+), 36 deletions(-)
drivers/ata/ahci.c +2 -0
@@ -268,6 +268,7 @@ static const struct ata_port_operations ahci_ops = { .tf_read = ahci_tf_read, + .qc_defer = ata_std_qc_defer, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue,
@@ -298,6 +299,7 @@ static const struct ata_port_operations ahci_vt8251_ops = { .tf_read = ahci_tf_read, + .qc_defer = ata_std_qc_defer, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue,
drivers/ata/libata-core.c +31 -0
@@ -4348,6 +4348,36 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc) }/** +* ata_std_qc_defer - Check whether a qc needs to be deferred +* @qc: ATA command in question +* +* Non-NCQ commands cannot run with any other command, NCQ or +* not. As upper layer only knows the queue depth, we are +* responsible for maintaining exclusion. This function checks +* whether a new command @qc can be issued. +* +* LOCKING: +* spin_lock_irqsave(host lock) +* +* RETURNS: +* ATA_DEFER_* if deferring is needed, 0 otherwise. +*/ +int ata_std_qc_defer (struct ata_queued_cmd *qc) +{ +struct ata_link *link = qc->dev->link; + +if (qc->tf.protocol ==ATA_PROT_NCQ ) { +if (!ata_tag_valid (link->active_tag)) +return 0 ; + }else { +if (!ata_tag_valid (link->active_tag) && !link->sactive) +return 0 ; + } + +return ATA_DEFER_LINK ; +} + +/** * ata_qc_prep - Prepare taskfile for submission * @qc: Metadata associated with taskfile to be prepared *
@@ -7113,6 +7143,7 @@ EXPORT_SYMBOL_GPL(ata_interrupt);EXPORT_SYMBOL_GPL (ata_do_set_mode);EXPORT_SYMBOL_GPL (ata_data_xfer);EXPORT_SYMBOL_GPL (ata_data_xfer_noirq); +EXPORT_SYMBOL_GPL (ata_std_qc_defer);EXPORT_SYMBOL_GPL (ata_qc_prep);EXPORT_SYMBOL_GPL (ata_dumb_qc_prep);EXPORT_SYMBOL_GPL (ata_noop_qc_prep);
drivers/ata/libata-scsi.c +26 -36
103 lines not on this page · raw message
drivers/ata/sata_nv.c +1 -0
@@ -423,6 +423,7 @@ static const struct ata_port_operations nv_adma_ops = { .bmdma_start = ata_bmdma_start, .bmdma_stop = ata_bmdma_stop, .bmdma_status = ata_bmdma_status, + .qc_defer = ata_std_qc_defer, .qc_prep = nv_adma_qc_prep, .qc_issue = nv_adma_qc_issue, .freeze = nv_adma_freeze,
drivers/ata/sata_sil24.c +1 -0
@@ -393,6 +393,7 @@ static const struct ata_port_operations sil24_ops = { .tf_read = sil24_tf_read, + .qc_defer = ata_std_qc_defer, .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue,
include/linux/libata.h +6 -0
@@ -272,6 +272,10 @@ enum {/* ering size */ ATA_ERING_SIZE =32 , +/* return values for ->qc_defer */ +ATA_DEFER_LINK =1 , +ATA_DEFER_PORT =2 , +/* desc_len for ata_eh_info and context */ ATA_EH_DESC_LEN = 80,
@@ -639,6 +643,7 @@ struct ata_port_operations {void (*data_xfer) (struct ata_device *,unsigned char *,unsigned int ,int ); +int (*qc_defer) (struct ata_queued_cmd *qc);void (*qc_prep) (struct ata_queued_cmd *qc);unsigned int (*qc_issue) (struct ata_queued_cmd *qc);
@@ -824,6 +829,7 @@ extern void ata_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data);extern void ata_data_xfer_noirq (struct ata_device *adev,unsigned char *buf,unsigned int buflen,int write_data); +extern int ata_std_qc_defer (struct ata_queued_cmd *qc);extern void ata_dumb_qc_prep (struct ata_queued_cmd *qc);extern void ata_qc_prep (struct ata_queued_cmd *qc);extern void ata_noop_qc_prep (struct ata_queued_cmd *qc);
Signature · 1 line
1.5.0.3
PATCH 6/12 libata-pmp-prep: implement qc_defer helpers
In reply to Tejun HeoImplement ap->nr_active_links (the number of links with active qcs), ap->excl_link (pointer to link which can be used by ->qc_defer and is cleared when a qc with ATA_QCFLAG_CLEAR_EXCL completes), and ata_link_active().
These can be used by ->qc_defer() to implement proper command exclusion. This set of helpers seem enough for both sil24 (ATAPI exclusion needed) and cmd-switching PMP.
--- drivers/ata/libata-core.c | 22 ++++++++++++++++++++-- drivers/ata/libata-eh.c | 5 +++++ include/linux/libata.h | 8 ++++++++ 3 files changed, 33 insertions(+), 2 deletions(-)
drivers/ata/libata-core.c +20 -2
@@ -1392,6 +1392,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,struct ata_queued_cmd *qc;unsigned int tag, preempted_tag;u32 preempted_sactive, preempted_qc_active; +int preempted_nr_active_links;DECLARE_COMPLETION_ONSTACK (wait);unsigned long flags;unsigned int err_mask;
@@ -1430,9 +1431,11 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, preempted_tag = link->active_tag; preempted_sactive = link->sactive; preempted_qc_active = ap->qc_active; + preempted_nr_active_links = ap->nr_active_links; link->active_tag =ATA_TAG_POISON ; link->sactive =0 ; ap->qc_active =0 ; + ap->nr_active_links =0 ;/* prepare & issue qc */ qc->tf = *tf;
@@ -1511,6 +1514,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, link->active_tag = preempted_tag; link->sactive = preempted_sactive; ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links;/* XXX - Some LLDDs (sata_mv) disable port on command failure. * Until those drivers are fixed, we detect the condition
@@ -5410,10 +5414,19 @@ void __ata_qc_complete(struct ata_queued_cmd *qc)ata_sg_clean (qc);/* command should be marked inactive atomically with qc completion */ -if (qc->tf.protocol ==ATA_PROT_NCQ ) +if (qc->tf.protocol ==ATA_PROT_NCQ ) { link->sactive &= ~(1 << qc->tag); -else +if (!link->sactive) + ap->nr_active_links--; + }else { link->active_tag =ATA_TAG_POISON ; + ap->nr_active_links--; + } + +/* clear exclusive status */ +if (unlikely (qc->flags &ATA_QCFLAG_CLEAR_EXCL && + ap->excl_link == link)) + ap->excl_link =NULL ;/* atapi: mark qc as inactive to prevent the interrupt handler * from completing the command twice later, before the error handler
@@ -5592,9 +5605,14 @@ void ata_qc_issue(struct ata_queued_cmd *qc)if (qc->tf.protocol ==ATA_PROT_NCQ ) {WARN_ON (link->sactive & (1 << qc->tag)); + +if (!link->sactive) + ap->nr_active_links++; link->sactive |=1 << qc->tag; }else {WARN_ON (link->sactive); + + ap->nr_active_links++; link->active_tag = qc->tag; }
drivers/ata/libata-eh.c +5 -0
@@ -451,6 +451,7 @@ void ata_scsi_error(struct Scsi_Host *host) ap->pflags |=ATA_PFLAG_EH_IN_PROGRESS ; ap->pflags &= ~ATA_PFLAG_EH_PENDING ; + ap->excl_link =NULL ;/* don't maintain exclusion over EH */ spin_unlock_irqrestore (ap->lock, flags);
@@ -2474,6 +2475,10 @@ void ata_eh_finish(struct ata_port *ap) } } } + +/* make sure nr_active_links is zero after EH */ +WARN_ON (ap->nr_active_links); + ap->nr_active_links =0 ; }/**
include/linux/libata.h +8 -0
@@ -216,6 +216,7 @@ enum {ATA_QCFLAG_DMAMAP =ATA_QCFLAG_SG |ATA_QCFLAG_SINGLE ,ATA_QCFLAG_IO = (1 <<3 ),/* standard IO command */ ATA_QCFLAG_RESULT_TF = (1 <<4 ),/* result TF requested */ +ATA_QCFLAG_CLEAR_EXCL = (1 <<5 ),/* clear excl_link on completion */ ATA_QCFLAG_FAILED = (1 <<16 ),/* cmd failed and is owned by EH */ ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */
@@ -579,11 +580,13 @@ struct ata_port {struct ata_queued_cmd qcmd[ATA_MAX_QUEUE ];unsigned long qc_allocated;unsigned int qc_active; +int nr_active_links;/* #links with active qcs */ struct ata_link link;/* host default link */ int nr_pmp_links;/* nr of available PMP links */ struct ata_link *pmp_link;/* array of PMP links */ +struct ata_link *excl_link;/* for PMP qc exclusion */ struct ata_port_stats stats;struct ata_host *host;
@@ -1104,6 +1107,11 @@ static inline int ata_link_max_devices(const struct ata_link *link)return 1 ; } +static inline int ata_link_active (struct ata_link *link) +{ +return ata_tag_valid (link->active_tag) || link->sactive; +} +static inline struct ata_link *ata_port_first_link (struct ata_port *ap) {if (ap->nr_pmp_links)
Signature · 1 line
1.5.0.3
PATCH 7/12 libata-pmp-prep: implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB
In reply to Tejun HeoSome links on some PMPs locks up on SRST and/or report incorrect device signature. Implement ATA_LFLAG_NO_SRST, ASSUME_ATA and ASSUME_SEMB to handle these quirky links. NO_SRST makes EH avoid SRST. ASSUME_ATA and SEMB forces class code to ATA and SEMB_UNSUP respectively. Note that SEMB isn't currently supported yet so the _UNSUP variant is used.
--- drivers/ata/libata-eh.c | 42 ++++++++++++++++++++++++++++++++---------- include/linux/libata.h | 4 ++++ 2 files changed, 36 insertions(+), 10 deletions(-)
drivers/ata/libata-eh.c +32 -10
@@ -1906,14 +1906,18 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,return 0 ; } -static int ata_eh_followup_srst_needed (int rc,int classify, +static int ata_eh_followup_srst_needed (struct ata_link *link, +int rc,int classify,const unsigned int *classes) { +if (link->flags &ATA_LFLAG_NO_SRST ) +return 0 ;if (rc == -EAGAIN )return 1 ;if (rc !=0 )return 0 ; -if (classify && classes[0 ] ==ATA_DEV_UNKNOWN ) +if (classify && !(link->flags &ATA_LFLAG_ASSUME_CLASS ) && + classes[0 ] ==ATA_DEV_UNKNOWN )return 1 ;return 0 ; }
@@ -1940,7 +1944,8 @@ int ata_eh_reset(struct ata_link *link, int classify,*/ action = ehc->i.action; ehc->i.action &= ~ATA_EH_RESET_MASK ; -if (softreset && (!hardreset || (!sata_set_spd_needed (link) && +if (softreset && (!hardreset || (!(link->flags &ATA_LFLAG_NO_SRST ) && + !sata_set_spd_needed (link) && !(action &ATA_EH_HARDRESET )))) ehc->i.action |=ATA_EH_SOFTRESET ;else
@@ -2003,7 +2008,7 @@ int ata_eh_reset(struct ata_link *link, int classify, rc =ata_do_reset (link, reset, classes, deadline);if (reset == hardreset && -ata_eh_followup_srst_needed (rc, classify, classes)) { +ata_eh_followup_srst_needed (link, rc, classify, classes)) {/* okay, let's do follow-up softreset */ reset = softreset;
@@ -2018,8 +2023,8 @@ int ata_eh_reset(struct ata_link *link, int classify,ata_eh_about_to_do (link,NULL ,ATA_EH_RESET_MASK ); rc =ata_do_reset (link, reset, classes, deadline); -if (rc ==0 && classify && - classes[0 ] ==ATA_DEV_UNKNOWN ) { +if (rc ==0 && classify && classes[0 ] ==ATA_DEV_UNKNOWN && + !(link->flags &ATA_LFLAG_ASSUME_CLASS )) {ata_link_printk (link,KERN_ERR ,"classification failed\n" ); rc = -EINVAL ;
@@ -2027,6 +2032,10 @@ int ata_eh_reset(struct ata_link *link, int classify, } } +/* if we skipped follow-up srst, clear rc */ +if (rc == -EAGAIN ) + rc =0 ; +if (rc && try <ARRAY_SIZE (ata_eh_reset_timeouts)) {unsigned long now = jiffies;
@@ -2051,12 +2060,25 @@ int ata_eh_reset(struct ata_link *link, int classify,if (rc ==0 ) {u32 sstatus; -/* After the reset, the device state is PIO 0 and the -* controller state is undefined. Record the mode. -*/ -ata_link_for_each_dev (dev, link) +ata_link_for_each_dev (dev, link) { +/* After the reset, the device state is PIO 0 +* and the controller state is undefined. +* Record the mode. +*/ dev->pio_mode =XFER_PIO_0 ; +if (ata_link_offline (link)) +continue ; + +/* apply class override and convert UNKNOWN to NONE */ +if (link->flags &ATA_LFLAG_ASSUME_ATA ) + classes[dev->devno] =ATA_DEV_ATA ; +else if (link->flags &ATA_LFLAG_ASSUME_SEMB ) + classes[dev->devno] =ATA_DEV_SEMB_UNSUP ;/* not yet */ +else if (classes[dev->devno] ==ATA_DEV_UNKNOWN ) + classes[dev->devno] =ATA_DEV_NONE ; + } +/* record current link speed */ if (sata_scr_read (link,SCR_STATUS , &sstatus) ==0 ) link->sata_spd = (sstatus >>4 ) &0xf ;
include/linux/libata.h +4 -0
@@ -165,6 +165,10 @@ enum {ATA_LFLAG_HRST_TO_RESUME = (1 <<0 ),/* hardreset to resume link */ ATA_LFLAG_SKIP_D2H_BSY = (1 <<1 ),/* can't wait for the first D2H * Register FIS clearing BSY */ +ATA_LFLAG_NO_SRST = (1 <<2 ),/* avoid softreset */ +ATA_LFLAG_ASSUME_ATA = (1 <<3 ),/* assume ATA class */ +ATA_LFLAG_ASSUME_SEMB = (1 <<4 ),/* assume SEMB class */ +ATA_LFLAG_ASSUME_CLASS =ATA_LFLAG_ASSUME_ATA |ATA_LFLAG_ASSUME_SEMB ,/* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */
Signature · 1 line
1.5.0.3
PATCH 8/12 libata-pmp-prep: implement ATA_LFLAG_NO_RETRY
In reply to Tejun HeoSome PMP links are connected to internal pseudo devices which may come and go depending on situation. There's no reason to try hard to recover them. ATA_LFLAG_NO_RETRY tells EH to not retry if the device attached to the link fails.
--- drivers/ata/libata-eh.c | 5 ++++- include/linux/libata.h | 1 + 2 files changed, 5 insertions(+), 1 deletions(-)
drivers/ata/libata-eh.c +4 -1
@@ -2335,7 +2335,10 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,struct ata_eh_context *ehc = &link->eh_context;ata_link_for_each_dev (dev, link) { - ehc->tries[dev->devno] =ATA_EH_DEV_TRIES ; +if (link->flags &ATA_LFLAG_NO_RETRY ) + ehc->tries[dev->devno] =1 ; +else + ehc->tries[dev->devno] =ATA_EH_DEV_TRIES ;/* collect port action mask recorded in dev actions */ ehc->i.action |= ehc->i.dev_action[dev->devno] &
include/linux/libata.h +1 -0
@@ -169,6 +169,7 @@ enum {ATA_LFLAG_ASSUME_ATA = (1 <<3 ),/* assume ATA class */ ATA_LFLAG_ASSUME_SEMB = (1 <<4 ),/* assume SEMB class */ ATA_LFLAG_ASSUME_CLASS =ATA_LFLAG_ASSUME_ATA |ATA_LFLAG_ASSUME_SEMB , +ATA_LFLAG_NO_RETRY = (1 <<5 ),/* don't retry this link */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */
Signature · 1 line
1.5.0.3
PATCH 9/12 libata-pmp-prep: implement ATA_LFLAG_DISABLED
In reply to Tejun HeoImplement ATA_LFLAG_DISABLED. The flag indicates the link is disabled due to EH recovery failure. While a link is disabled, no EH action is taken on the link and suspend/resume become noop too.
This will be used by PMP links to manage failed links.
--- drivers/ata/libata-eh.c | 30 +++++++++++++++++++++++++++++- include/linux/libata.h | 3 +++ 2 files changed, 32 insertions(+), 1 deletions(-)
drivers/ata/libata-eh.c +29 -1
@@ -1308,6 +1308,7 @@ static void ata_eh_analyze_serror(struct ata_link *link)struct ata_eh_context *ehc = &link->eh_context;u32 serror = ehc->i.serror;unsigned int err_mask =0 , action =0 ; +u32 hotplug_mask;if (serror &SERR_PERSISTENT ) { err_mask |=AC_ERR_ATA_BUS ;
@@ -1326,7 +1327,20 @@ static void ata_eh_analyze_serror(struct ata_link *link) err_mask |=AC_ERR_SYSTEM ; action |=ATA_EH_HARDRESET ; } -if (serror & (SERR_PHYRDY_CHG |SERR_DEV_XCHG )) + +/* Determine whether a hotplug event has occurred. Both +* SError.N/X are considered hotplug events for enabled or +* host links. For disabled PMP links, only N bit is +* considered as X bit is left at 1 for link plugging. +*/ + hotplug_mask =0 ; + +if (!(link->flags &ATA_LFLAG_DISABLED ) ||ata_is_host_link (link)) + hotplug_mask =SERR_PHYRDY_CHG |SERR_DEV_XCHG ; +else + hotplug_mask =SERR_PHYRDY_CHG ; + +if (serror & hotplug_mask)ata_ehi_hotplugged (&ehc->i); ehc->i.err_mask |= err_mask;
@@ -2227,6 +2241,10 @@ static int ata_eh_skip_recovery(struct ata_link *link)struct ata_eh_context *ehc = &link->eh_context;struct ata_device *dev; +/* skip disabled links */ +if (link->flags &ATA_LFLAG_DISABLED ) +return 1 ; +/* thaw frozen port, resume link and recover failed devices */ if ((link->ap->pflags &ATA_PFLAG_FROZEN ) || (ehc->i.flags &ATA_EHI_RESUME_LINK ) ||ata_link_nr_enabled (link))
@@ -2327,6 +2345,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,struct ata_device *dev;int nr_failed_devs, nr_disabled_devs;int reset, rc; +unsigned long flags;DPRINTK ("ENTER\n" );
@@ -2334,6 +2353,15 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,ata_port_for_each_link (link, ap) {struct ata_eh_context *ehc = &link->eh_context; +/* re-enable link? */ +if (ehc->i.action &ATA_EH_ENABLE_LINK ) { +ata_eh_about_to_do (link,NULL ,ATA_EH_ENABLE_LINK ); +spin_lock_irqsave (ap->lock, flags); + link->flags &= ~ATA_LFLAG_DISABLED ; +spin_unlock_irqrestore (ap->lock, flags); +ata_eh_done (link,NULL ,ATA_EH_ENABLE_LINK ); + } +ata_link_for_each_dev (dev, link) {if (link->flags &ATA_LFLAG_NO_RETRY ) ehc->tries[dev->devno] =1 ;
include/linux/libata.h +3 -0
@@ -170,6 +170,7 @@ enum {ATA_LFLAG_ASSUME_SEMB = (1 <<4 ),/* assume SEMB class */ ATA_LFLAG_ASSUME_CLASS =ATA_LFLAG_ASSUME_ATA |ATA_LFLAG_ASSUME_SEMB ,ATA_LFLAG_NO_RETRY = (1 <<5 ),/* don't retry this link */ +ATA_LFLAG_DISABLED = (1 <<6 ),/* link is disabled */ /* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */
@@ -289,6 +290,7 @@ enum {ATA_EH_REVALIDATE = (1 <<0 ),ATA_EH_SOFTRESET = (1 <<1 ),ATA_EH_HARDRESET = (1 <<2 ), +ATA_EH_ENABLE_LINK = (1 <<3 ),ATA_EH_RESET_MASK =ATA_EH_SOFTRESET |ATA_EH_HARDRESET , ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE,
@@ -999,6 +1001,7 @@ static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi) {ata_ehi_schedule_probe (ehi); ehi->flags |=ATA_EHI_HOTPLUGGED ; + ehi->action |=ATA_EH_ENABLE_LINK ; ehi->err_mask |=AC_ERR_ATA_BUS ; }
Signature · 1 line
1.5.0.3
PATCH 10/12 libata-pmp-prep: implement EH fast-fail path
In reply to Tejun HeoIf PMP itself becomes inaccessible while trying to link a downstream link, spending time to recover the downstream link doesn't make any sense. Make EH skip retry and fail fast if -ERESTART is received.
--- drivers/ata/libata-eh.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/ata/libata-eh.c +1 -1
@@ -2050,7 +2050,7 @@ int ata_eh_reset(struct ata_link *link, int classify,if (rc == -EAGAIN ) rc =0 ; -if (rc && try <ARRAY_SIZE (ata_eh_reset_timeouts)) { +if (rc && rc != -ERESTART && try <ARRAY_SIZE (ata_eh_reset_timeouts)) {unsigned long now = jiffies;if (time_before (now, deadline)) {
Signature · 1 line
1.5.0.3
PATCH 11/12 libata-pmp-prep: implement ATA_HORKAGE_SKIP_PM
In reply to Tejun HeoSome pseudo devices fail PM commands unnecessarily aborting system suspend. Implement ATA_HORKAGE_SKIP_PM which makes libata skip PM commands for these devices.
--- drivers/ata/libata-scsi.c | 7 +++++++ include/linux/libata.h | 1 + 2 files changed, 8 insertions(+), 0 deletions(-)
drivers/ata/libata-scsi.c +7 -0
@@ -945,6 +945,13 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) goto invalid_fld;/* LOEJ bit set not supported */ if (((cdb[4 ] >>4 ) &0xf ) !=0 ) goto invalid_fld;/* power conditions not supported */ + +if (qc->dev->horkage &ATA_HORKAGE_SKIP_PM ) { +/* the device lacks PM support, finish without doing anything */ + scmd->result =SAM_STAT_GOOD ; +return 1 ; + } +if (cdb[4 ] &0x1 ) { tf->nsect =1 ;/* 1 sector, lba=0 */
include/linux/libata.h +1 -0
@@ -329,6 +329,7 @@ enum {ATA_HORKAGE_NONCQ = (1 <<2 ),/* Don't use NCQ */ ATA_HORKAGE_MAX_SEC_128 = (1 <<3 ),/* Limit max sects to 128 */ ATA_HORKAGE_BROKEN_HPA = (1 <<4 ),/* Broken HPA */ + ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ }; enum hsm_task_states {
Signature · 1 line
1.5.0.3
PATCH 12/12 libata-pmp-prep: implement sata_async_notification()
In reply to Tejun HeoAN serves multiple purposes. For ATAPI, it's used for media change notification. For PMP, for downstream PHY status change notification. Implement sata_async_notification() which demultiplexes AN.
To avoid unnecessary port events, ATAPI AN is not enabled if PMP is attached but SNTF is not available.
--- drivers/ata/ahci.c | 24 ++++---------- drivers/ata/libata-core.c | 13 +++++-- drivers/ata/libata-eh.c | 73 +++++++++++++++++++++++++++++++++++++++++++++ drivers/ata/libata-scsi.c | 1 - drivers/ata/libata.h | 1 + drivers/ata/sata_sil24.c | 5 +-- include/linux/libata.h | 4 +- 7 files changed, 93 insertions(+), 28 deletions(-)
drivers/ata/ahci.c +7 -17
@@ -1356,27 +1356,17 @@ static void ahci_port_intr(struct ata_port *ap) }if (status &PORT_IRQ_SDB_FIS ) { -/* -* if this is an ATAPI device with AN turned on, -* then we should interrogate the device to -* determine the cause of the interrupt -* -* for AN - this we should check the SDB FIS -* and find the I and N bits set +/* If the 'N' bit in word 0 of the FIS is set, we just +* received asynchronous notification. Tell libata +* about it. Note that as the SDB FIS itself is +* accessible, SNotification can be emulated by the +* driver but don't bother for the time being. */ const __le32 *f = pp->rx_fis +RX_FIS_SDB ;u32 f0 =le32_to_cpu (f[0 ]); -/* check the 'N' bit in word 0 of the FIS */ -if (f0 & (1 <<15 )) { -int port_addr = ((f0 &0x00000f00 ) >>8 ); -struct ata_device *adev; -if (port_addr <ATA_MAX_DEVICES ) { - adev = &ap->link.device[port_addr]; -if (adev->flags &ATA_DFLAG_AN ) -ata_scsi_media_change_notify (adev); - } - } +if (f0 & (1 <<15 )) +sata_async_notification (ap); }if (ap->link.sactive)
drivers/ata/libata-core.c +9 -4
@@ -2018,6 +2018,7 @@ int ata_dev_configure(struct ata_device *dev)else if (dev->class ==ATA_DEV_ATAPI ) {const char *cdb_intr_string ="" ;const char *atapi_an_string ="" ; +u32 sntf; rc =atapi_cdb_len (id);if ((rc <12 ) || (rc >ATAPI_CDB_LEN )) {
@@ -2029,11 +2030,14 @@ int ata_dev_configure(struct ata_device *dev) } dev->cdb_len = (unsigned int ) rc; -/* -* check to see if this ATAPI device supports -* Asynchronous Notification +/* Enable ATAPI AN if both the host and device have +* the support. If PMP is attached, SNTF is required +* to enable ATAPI AN to discern between PHY status +* changed notifications and ATAPI ANs. */ -if ((ap->flags &ATA_FLAG_AN ) &&ata_id_has_atapi_AN (id)) { +if ((ap->flags &ATA_FLAG_AN ) &&ata_id_has_atapi_AN (id) && + (!ap->nr_pmp_links || +sata_scr_read (&ap->link,SCR_NOTIFICATION , &sntf) ==0 )) {unsigned int err_mask;/* issue SET feature command to turn this on */
@@ -7250,6 +7254,7 @@ EXPORT_SYMBOL_GPL(ata_port_schedule_eh);EXPORT_SYMBOL_GPL (ata_link_abort);EXPORT_SYMBOL_GPL (ata_port_abort);EXPORT_SYMBOL_GPL (ata_port_freeze); +EXPORT_SYMBOL_GPL (sata_async_notification);EXPORT_SYMBOL_GPL (ata_eh_freeze_port);EXPORT_SYMBOL_GPL (ata_eh_thaw_port);EXPORT_SYMBOL_GPL (ata_eh_qc_complete);
drivers/ata/libata-eh.c +73 -0
79 lines not on this page · raw message
drivers/ata/libata-scsi.c +0 -1
@@ -3167,7 +3167,6 @@ void ata_scsi_media_change_notify(struct ata_device *dev)scsi_device_event_notify (dev->sdev,SDEV_MEDIA_CHANGE );#endif } -EXPORT_SYMBOL_GPL (ata_scsi_media_change_notify);/** * ata_scsi_hotplug - SCSI part of hotplug
drivers/ata/libata.h +1 -0
@@ -118,6 +118,7 @@ extern int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht);extern void ata_scsi_scan_host (struct ata_port *ap,int sync);extern int ata_scsi_offline_dev (struct ata_device *dev); +extern void ata_scsi_media_change_notify (struct ata_device *dev);extern void ata_scsi_hotplug (struct work_struct *work);extern unsigned int ata_scsiop_inq_std (struct ata_scsi_args *args,u8 *rbuf,unsigned int buflen);
drivers/ata/sata_sil24.c +1 -4
@@ -821,11 +821,8 @@ static void sil24_error_intr(struct ata_port *ap)ata_ehi_push_desc (ehi,"irq_stat 0x%08x" , irq_stat);if (irq_stat &PORT_IRQ_SDB_NOTIFY ) { -struct ata_device *dev = ap->link.device; -ata_ehi_push_desc (ehi,"SDB notify" ); -if (dev->flags &ATA_DFLAG_AN ) -ata_scsi_media_change_notify (dev); +sata_async_notification (ap); }if (irq_stat & (PORT_IRQ_PHYRDY_CHG |PORT_IRQ_DEV_XCHG )) {
include/linux/libata.h +2 -2
@@ -139,7 +139,7 @@ enum {ATA_DFLAG_FLUSH_EXT = (1 <<4 ),/* do FLUSH_EXT instead of FLUSH */ ATA_DFLAG_ACPI_PENDING = (1 <<5 ),/* ACPI resume action pending */ ATA_DFLAG_ACPI_FAILED = (1 <<6 ),/* ACPI on devcfg has failed */ -ATA_DFLAG_AN = (1 <<7 ),/* device supports AN */ +ATA_DFLAG_AN = (1 <<7 ),/* AN configured */ ATA_DFLAG_CFG_MASK = (1 <<12 ) -1 , ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */
@@ -787,7 +787,6 @@ extern void ata_host_init(struct ata_host *, struct device *,extern int ata_scsi_detect (struct scsi_host_template *sht);extern int ata_scsi_ioctl (struct scsi_device *dev,int cmd,void __user *arg);extern int ata_scsi_queuecmd (struct scsi_cmnd *cmd,void (*done)(struct scsi_cmnd *)); -extern void ata_scsi_media_change_notify (struct ata_device *atadev);extern void ata_sas_port_destroy (struct ata_port *);extern struct ata_port *ata_sas_port_alloc (struct ata_host *,struct ata_port_info *,struct Scsi_Host *);
@@ -953,6 +952,7 @@ extern void ata_port_schedule_eh(struct ata_port *ap);extern int ata_link_abort (struct ata_link *link);extern int ata_port_abort (struct ata_port *ap);extern int ata_port_freeze (struct ata_port *ap); +extern int sata_async_notification (struct ata_port *ap);extern void ata_eh_freeze_port (struct ata_port *ap);extern void ata_eh_thaw_port (struct ata_port *ap);
Signature · 1 line
1.5.0.3