prep for PM support
PATCH 10/11 prep for PM support
Howdy,
This is part of patchset series described in [T].
This is the first take of prep-for-PM-support patchset. This patchset contains 7 patches and implements various stuff needed for PM.
One of important updates is the addition of ops->qc_defer(). This is to let LLDDs determine which commands they can accept at the moment. This is necessary for PM and controllers have wildely different capabilities regarding how many/different commands can be issued to how many devices concurrently. More info is in the message [T].
This patchset is against
upstream (acc696d93dcf993dec123d69d599979e1456ffec)
+ [1] prep-for-new-EH patchset
+ [2] new-EH-framework patchset, take 3
+ [3] new-EH-implementation patchset, take 3
+ [4] merge-irq-pio patchset
+ [5] add-NCQ-support patchset, take 3
+ [6] prep-for-hotplug support, take 2
+ [7] prep-LLDDs-for-hotplug-support, take 1
+ [8] add-hotplug-support, take 2
+ [9] implement-ata_link, take 1
--
tejun
[T] http://article.gmane.org/gmane.linux.ide/9957
[1] http://article.gmane.org/gmane.linux.ide/9959
[2] http://article.gmane.org/gmane.linux.ide/9984
[3] http://article.gmane.org/gmane.linux.ide/9995
[4] http://article.gmane.org/gmane.linux.ide/10005
[5] http://article.gmane.org/gmane.linux.ide/10011
[6] http://article.gmane.org/gmane.linux.ide/10028
[7] http://article.gmane.org/gmane.linux.ide/10063
[8] http://article.gmane.org/gmane.linux.ide/10073
[9] http://article.gmane.org/gmane.linux.ide/10106
PATCH 3/7 libata-pm-prep: separate out sata_link_hardreset()
Separate out sata_link_hardreset() from sata_std_hardreset(). This will be used by PM.
---
drivers/scsi/libata-core.c | 54 ++++++++++++++++++++++++++++++++++---------- drivers/scsi/libata.h | 1 + 2 files changed, 43 insertions(+), 12 deletions(-)
618a80782b3044ecbfff23f978aa0066942332d0
drivers/scsi/libata-core.c +42 -12
@@ -2620,11 +2620,10 @@ int ata_std_softreset(struct ata_link *l }/** -* sata_std_hardreset - reset host port via SATA phy reset +* sata_link_hardreset - reset link via SATA phy reset * @link: link to reset -* @class: resulting class of attached device * -* SATA phy-reset host port using DET bits of SControl register. +* SATA phy-reset @link using DET bits of SControl register. * * LOCKING: * Kernel thread context (may sleep)
@@ -2632,11 +2631,10 @@ int ata_std_softreset(struct ata_link *l* RETURNS: * 0 on success, -errno otherwise. */ -int sata_std_hardreset (struct ata_link *link,unsigned int *class) +int sata_link_hardreset (struct ata_link *link) { -struct ata_port *ap = link->ap;u32 scontrol; -int rc; +int rc =0 ;DPRINTK ("ENTER\n" );
@@ -2647,24 +2645,24 @@ int sata_std_hardreset(struct ata_link ** and Sil3124. */ if ((rc =ata_scr_read (link,SCR_CONTROL , &scontrol))) -return rc; + goto out; scontrol = (scontrol &0x0f0 ) |0x302 ;if ((rc =ata_scr_write (link,SCR_CONTROL , scontrol))) -return rc; + goto out;ata_set_sata_spd (link); }/* issue phy wake/reset */ if ((rc =ata_scr_read (link,SCR_CONTROL , &scontrol))) -return rc; + goto out; scontrol = (scontrol &0x0f0 ) |0x301 ;if ((rc =ata_scr_write_flush (link,SCR_CONTROL , scontrol))) -return rc; + goto out;/* Couldn't find anything in SATA I/II specs, but AHCI-1.1 * 10.4.2 says at least 1 ms.
@@ -2672,9 +2670,41 @@ int sata_std_hardreset(struct ata_link *msleep (1 );/* bring phy back */ -sata_link_resume (link,0 ); + rc =sata_link_resume (link,0 ); + out: +if (rc) +ata_link_printk (link,KERN_ERR , +"COMRESET failed (errno=%d)\n" , rc); +DPRINTK ("EXIT, rc=%d\n" , rc); +return rc; +} + +/** +* sata_std_hardreset - reset host port via SATA phy reset +* @link: link to reset +* @class: resulting class of attached device +* +* SATA phy-reset host port using DET bits of SControl register, +* wait for !BSY and classify the attached device. +* +* LOCKING: +* Kernel thread context (may sleep) +* +* RETURNS: +* 0 on success, -errno otherwise. +*/ +int sata_std_hardreset (struct ata_link *link,unsigned int *class) +{ +struct ata_port *ap = link->ap; +int rc; + +DPRINTK ("ENTER\n" ); + +/* do hardreset */ + rc =sata_link_hardreset (link); +if (rc) +return rc; -/* TODO: phy layer with polling, timeouts, etc. */ if (ata_link_offline (link)) { *class =ATA_DEV_NONE ;DPRINTK ("EXIT, link offline\n" );
drivers/scsi/libata.h +1 -0
@@ -54,6 +54,7 @@ extern int ata_dev_read_id(struct ata_de int post_reset, u16 *id);extern int ata_dev_configure (struct ata_device *dev,int print_info);extern void sata_print_link_status (struct ata_link *link); +extern int sata_link_hardreset (struct ata_link *link);extern int ata_down_sata_spd_limit (struct ata_link *link);extern int ata_set_sata_spd_needed (struct ata_link *link);extern int ata_down_xfermask_limit (struct ata_device *dev,int force_pio0);
Signature · 1 line
1.2.4
PATCH 1/7 libata-pm-prep: add @new_class to ata_dev_revalidate()
In reply to Tejun HeoConsider newly found class code while revalidating. PM resetting always results in valid class code and issuing PM commands to ATA/ATAPI devices isn't a very attractive idea. Add @new_class to ata_dev_revalidate() and check class during revalidation.
---
drivers/scsi/libata-core.c | 20 +++++++++++++++----- drivers/scsi/libata-eh.c | 2 +- include/linux/libata.h | 3 ++- 3 files changed, 18 insertions(+), 7 deletions(-)
e9ad06f7ef8413f1027baad8b64bc860b85fa85e
drivers/scsi/libata-core.c +15 -5
@@ -2052,7 +2052,7 @@ static int ata_dev_set_mode(struct ata_dreturn -EIO ; } - rc =ata_dev_revalidate (dev,0 ); + rc =ata_dev_revalidate (dev,ATA_DEV_UNKNOWN ,0 );if (rc)return rc;
@@ -2813,6 +2813,7 @@ static int ata_dev_same_device(struct at/** * ata_dev_revalidate - Revalidate ATA device * @dev: device to revalidate +* @new_class: new class code * @post_reset: is this revalidation after reset? * * Re-read IDENTIFY page and make sure @dev is still attached to
@@ -2824,9 +2825,9 @@ static int ata_dev_same_device(struct at* RETURNS: * 0 on success, negative errno otherwise */ -int ata_dev_revalidate (struct ata_device *dev,int post_reset) +int ata_dev_revalidate (struct ata_device *dev,unsigned int new_class, +int post_reset) { -unsigned int class = dev->class;u16 *id = (void *)dev->link->ap->sector_buf;int rc;
@@ -2835,13 +2836,22 @@ int ata_dev_revalidate(struct ata_device goto fail; } +if (ata_class_enabled (new_class)) { +/* sometimes wrong class is reported, let it retry */ +if (new_class !=ATA_DEV_ATA && new_class !=ATA_DEV_ATAPI ) { + rc = -EIO ; + goto fail; + } + }else + new_class = dev->class; +/* read ID data */ - rc =ata_dev_read_id (dev, &class, post_reset, id); + rc =ata_dev_read_id (dev, &new_class, post_reset, id);if (rc) goto fail;/* is the device still there? */ -if (!ata_dev_same_device (dev, class, id)) { +if (!ata_dev_same_device (dev, new_class, id)) { rc = -ENODEV ; goto fail; }
drivers/scsi/libata-eh.c +1 -1
@@ -1570,7 +1570,7 @@ static int ata_eh_revalidate_and_attach( }ata_eh_about_to_do (link,ATA_EH_REVALIDATE ); - rc =ata_dev_revalidate (dev, + rc =ata_dev_revalidate (dev, ehc->classes[dev->devno], ehc->flags &ATA_EHC_DID_RESET );if (rc)break ;
include/linux/libata.h +2 -1
@@ -633,7 +633,8 @@ extern int ata_std_prereset(struct ata_lextern int ata_std_softreset (struct ata_link *link,unsigned int *classes);extern int sata_std_hardreset (struct ata_link *link,unsigned int *class);extern void ata_std_postreset (struct ata_link *link,unsigned int *classes); -extern int ata_dev_revalidate (struct ata_device *dev,int post_reset); +extern int ata_dev_revalidate (struct ata_device *dev,unsigned int new_class, +int post_reset);extern void ata_port_disable (struct ata_port *);extern void ata_std_ports (struct ata_ioports *ioaddr);#ifdef CONFIG_PCI
Signature · 1 line
1.2.4
PATCH 2/7 libata-pm-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/scsi/libata.h). These will be used by PM.
---
drivers/scsi/libata-core.c | 7 +++---- drivers/scsi/libata-eh.c | 24 ++++++++++++------------ drivers/scsi/libata.h | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 16 deletions(-)
9827f37046db8165d763573523d3cd864966a1be
drivers/scsi/libata-core.c +3 -4
@@ -65,7 +65,6 @@ static unsigned int ata_dev_init_params( u16 heads, u16 sectors);static unsigned int ata_dev_set_xfermode (struct ata_device *dev);static void ata_dev_xfermask (struct ata_device *dev); -static int ata_link_init_sata_spd_limit (struct ata_link *link);static unsigned int ata_unique_id =1 ;static struct workqueue_struct *ata_wq;
@@ -1594,7 +1593,7 @@ void ata_port_probe(struct ata_port *ap)* LOCKING: * None. */ -static void sata_print_link_status (struct ata_link *link) +void sata_print_link_status (struct ata_link *link) {u32 sstatus, scontrol, tmp;
@@ -5118,7 +5117,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) {struct ata_device *dev;
@@ -5151,7 +5150,7 @@ static void ata_link_init(struct ata_por* RETURNS: * 0 on success, -errno on failure. */ -static int ata_link_init_sata_spd_limit (struct ata_link *link) +int ata_link_init_sata_spd_limit (struct ata_link *link) {u32 scontrol, spd;
drivers/scsi/libata-eh.c +12 -12
@@ -679,7 +679,7 @@ void ata_eh_qc_retry(struct ata_queued_c* LOCKING: * None. */ -static void ata_eh_detach_dev (struct ata_device *dev) +void ata_eh_detach_dev (struct ata_device *dev) {struct ata_port *ap = dev->link->ap;unsigned long flags;
@@ -710,7 +710,7 @@ static void ata_eh_detach_dev(struct ata* LOCKING: * None. */ -static void ata_eh_about_to_do (struct ata_link *link,unsigned int action) +void ata_eh_about_to_do (struct ata_link *link,unsigned int action) {struct ata_port *ap = link->ap;unsigned long flags;
@@ -1296,7 +1296,7 @@ static void ata_eh_link_autopsy(struct a* 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;
@@ -1382,7 +1382,7 @@ static void ata_eh_link_report(struct at* LOCKING: * None. */ -static void ata_eh_report (struct ata_port *ap) +void ata_eh_report (struct ata_port *ap) {struct ata_link *link;
@@ -1431,9 +1431,9 @@ static int ata_eh_followup_srst_needed(ireturn 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;
@@ -1665,10 +1665,10 @@ static int ata_eh_skip_recovery(struct a* 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_eh_context *ehc;
@@ -1843,7 +1843,7 @@ static int ata_eh_recover(struct ata_por* LOCKING: * None. */ -static void ata_eh_finish (struct ata_port *ap) +void ata_eh_finish (struct ata_port *ap) {int tag;
drivers/scsi/libata.h +15 -0
@@ -53,6 +53,7 @@ extern unsigned ata_exec_internal(structextern int ata_dev_read_id (struct ata_device *dev,unsigned int *p_class,int post_reset,u16 *id);extern int ata_dev_configure (struct ata_device *dev,int print_info); +extern void sata_print_link_status (struct ata_link *link);extern int ata_down_sata_spd_limit (struct ata_link *link);extern int ata_set_sata_spd_needed (struct ata_link *link);extern int ata_down_xfermask_limit (struct ata_device *dev,int force_pio0);
@@ -66,6 +67,8 @@ extern void ata_dev_select(struct ata_po unsigned int wait, unsigned int can_sleep);extern void swap_buf_le16 (u16 *buf,unsigned int buf_words);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 ata_link_init_sata_spd_limit (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);
@@ -111,6 +114,18 @@ extern void ata_ering_init(struct ata_erextern enum scsi_eh_timer_return ata_scsi_timed_out (struct scsi_cmnd *cmd);extern void ata_scsi_error (struct Scsi_Host *host);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,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);extern void ata_eh_scsi_hotplug (void *data);#endif /* __LIBATA_H__ */
Signature · 1 line
1.2.4
PATCH 4/7 libata-pm-prep: add @is_cmd to ata_tf_to_fis()
In reply to Tejun HeoAdd @is_cmd to ata_tf_to_fis(). This controls bit 7 of the second byte of the constructed FIS which tells the device whether it is for a command or not. This cleans up ahci a bit and will be used by PM.
---
drivers/scsi/ahci.c | 8 +++----- drivers/scsi/libata-core.c | 14 ++++++++------ drivers/scsi/sata_qstor.c | 2 +- drivers/scsi/sata_sil24.c | 2 +- include/linux/libata.h | 3 ++- 5 files changed, 15 insertions(+), 14 deletions(-)
b3b89cc12158046907c50b2112e6bb4e87c5b8cc
drivers/scsi/ahci.c +3 -5
@@ -628,8 +628,7 @@ static int ahci_softreset(struct ata_lin cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY); tf.ctl |=ATA_SRST ; -ata_tf_to_fis (&tf, fis,0 ); - fis[1 ] &= ~(1 <<7 );/* turn off Command FIS bit */ +ata_tf_to_fis (&tf,0 ,0 , fis);writel (1 , port_mmio +PORT_CMD_ISSUE );
@@ -647,8 +646,7 @@ static int ahci_softreset(struct ata_linahci_fill_cmd_slot (pp,0 , cmd_fis_len); tf.ctl &= ~ATA_SRST ; -ata_tf_to_fis (&tf, fis,0 ); - fis[1 ] &= ~(1 <<7 );/* turn off Command FIS bit */ +ata_tf_to_fis (&tf,0 ,0 , fis);writel (1 , port_mmio +PORT_CMD_ISSUE );readl (port_mmio +PORT_CMD_ISSUE );/* flush */
@@ -787,7 +785,7 @@ static void ahci_qc_prep(struct ata_queu*/ cmd_tbl = pp->cmd_tbl + qc->tag *AHCI_CMD_TBL_SZ ; -ata_tf_to_fis (&qc->tf, cmd_tbl,0 ); +ata_tf_to_fis (&qc->tf,0 ,1 , cmd_tbl);if (is_atapi) {memset (cmd_tbl +AHCI_CMD_TBL_CDB ,0 ,32 );memcpy (cmd_tbl +AHCI_CMD_TBL_CDB , qc->cdb, qc->dev->cdb_len);
drivers/scsi/libata-core.c +8 -6
@@ -92,8 +92,9 @@ MODULE_VERSION(DRV_VERSION);/** * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure * @tf: Taskfile to convert -* @fis: Buffer into which data will output * @pmp: Port multiplier port +* @is_cmd: This FIS is for command +* @fis: Buffer into which data will output * * Converts a standard ATA taskfile to a Serial ATA * FIS structure (Register - Host to Device).
@@ -101,12 +102,13 @@ MODULE_VERSION(DRV_VERSION);* LOCKING: * Inherited from caller. */ - -void ata_tf_to_fis (const struct ata_taskfile *tf,u8 *fis,u8 pmp) +void ata_tf_to_fis (const struct ata_taskfile *tf,u8 pmp,int is_cmd,u8 *fis) { - fis[0 ] =0x27 ;/* Register - Host to Device FIS */ - fis[1 ] = (pmp &0xf ) | (1 <<7 );/* Port multiplier number, -bit 7 indicates Command FIS */ + fis[0 ] =0x27 ;/* Register - Host to Device FIS */ + fis[1 ] = pmp &0xf ;/* Port multiplier number*/ +if (is_cmd) + fis[1 ] |= (1 <<7 );/* bit 7 indicates Command FIS */ + fis[2 ] = tf->command; fis[3 ] = tf->feature;
drivers/scsi/sata_qstor.c +1 -1
@@ -335,7 +335,7 @@ static void qs_qc_prep(struct ata_queued buf[28 ] = dflags;/* frame information structure (FIS) */ -ata_tf_to_fis (&qc->tf, &buf[32 ],0 ); +ata_tf_to_fis (&qc->tf,0 ,1 , &buf[32 ]); }static inline void qs_packet_start (struct ata_queued_cmd *qc)
drivers/scsi/sata_sil24.c +1 -1
@@ -682,7 +682,7 @@ static void sil24_qc_prep(struct ata_que } prb->ctrl =cpu_to_le16 (ctrl); -ata_tf_to_fis (&qc->tf, prb->fis,0 ); +ata_tf_to_fis (&qc->tf, qc->dev->link->pmp,1 , prb->fis);if (qc->flags &ATA_QCFLAG_DMAMAP )sil24_fill_sg (qc, sge);
include/linux/libata.h +2 -1
@@ -678,7 +678,8 @@ extern u32 ata_wait_register(void __iome*/ extern void ata_tf_load (struct ata_port *ap,const struct ata_taskfile *tf);extern void ata_tf_read (struct ata_port *ap,struct ata_taskfile *tf); -extern void ata_tf_to_fis (const struct ata_taskfile *tf,u8 *fis,u8 pmp); +extern void ata_tf_to_fis (const struct ata_taskfile *tf, +u8 pmp,int is_cmd,u8 *fis);extern void ata_tf_from_fis (const u8 *fis,struct ata_taskfile *tf);extern u8 ata_noop_check_status (struct ata_port *ap);extern void ata_noop_dev_select (struct ata_port *ap,unsigned int device);
Signature · 1 line
1.2.4
PATCH 5/7 libata-pm-prep: implement ops->qc_defer()
In reply to Tejun HeoControllers which support PM 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 types are advisory and in general ATA_DEFER_LINK can simply be considered as having lower priority 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 PM)
* 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/scsi/ahci.c | 1 + drivers/scsi/libata-core.c | 32 ++++++++++++++++++++++++++++ drivers/scsi/libata-scsi.c | 50 +++++++++++--------------------------------- drivers/scsi/sata_sil24.c | 1 + include/linux/libata.h | 6 +++++ 5 files changed, 52 insertions(+), 38 deletions(-)
6f73e35cbbea07d45cc5fb153d74c273517b5b57
drivers/scsi/ahci.c +1 -0
@@ -239,6 +239,7 @@ static const struct ata_port_operations .tf_read = ahci_tf_read, + .qc_defer = ata_std_qc_defer, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue,
drivers/scsi/libata-core.c +32 -0
@@ -3253,6 +3253,37 @@ int ata_check_atapi_dma(struct ata_queuereturn rc; } + +/** +* 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_set 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
@@ -5837,6 +5868,7 @@ EXPORT_SYMBOL_GPL(ata_port_start);EXPORT_SYMBOL_GPL (ata_port_stop);EXPORT_SYMBOL_GPL (ata_host_stop);EXPORT_SYMBOL_GPL (ata_interrupt); +EXPORT_SYMBOL_GPL (ata_std_qc_defer);EXPORT_SYMBOL_GPL (ata_qc_prep);EXPORT_SYMBOL_GPL (ata_noop_qc_prep);EXPORT_SYMBOL_GPL (ata_bmdma_setup);
drivers/scsi/libata-scsi.c +12 -38
80 lines not on this page · raw message
drivers/scsi/sata_sil24.c +1 -0
@@ -380,6 +380,7 @@ static const struct ata_port_operations .check_altstatus = ata_noop_check_status, .dev_select = ata_noop_dev_select, + .qc_defer = ata_std_qc_defer, .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue,
include/linux/libata.h +6 -0
@@ -235,6 +235,10 @@ enum {ATA_PORT_PRIMARY = (1 <<0 ),ATA_PORT_SECONDARY = (1 <<1 ), +/* 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,
@@ -566,6 +570,7 @@ struct ata_port_operations {void (*bmdma_setup) (struct ata_queued_cmd *qc);void (*bmdma_start) (struct ata_queued_cmd *qc); +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);
@@ -691,6 +696,7 @@ extern int ata_port_start (struct ata_poextern void ata_port_stop (struct ata_port *ap);extern void ata_host_stop (struct ata_host_set *host_set);extern irqreturn_t ata_interrupt (int irq,void *dev_instance,struct pt_regs *regs); +extern int ata_std_qc_defer (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);extern unsigned int ata_qc_issue_prot (struct ata_queued_cmd *qc);
Signature · 1 line
1.2.4
PATCH 6/7 libata-pm-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 PM.
---
drivers/scsi/libata-core.c | 22 +++++++++++++++++++--- drivers/scsi/libata-eh.c | 5 +++++ include/linux/libata.h | 8 ++++++++ 3 files changed, 32 insertions(+), 3 deletions(-)
7deb1fc49ea4e26d9f1bc4258094086e0bcb27f2
drivers/scsi/libata-core.c +19 -3
@@ -994,7 +994,6 @@ void ata_qc_complete_internal(struct ata* LOCKING: * None. Should be called with kernel context, might sleep. */ -unsigned ata_exec_internal (struct ata_device *dev,struct ata_taskfile *tf,const u8 *cdb,int dma_dir,void *buf,unsigned int buflen)
@@ -1005,6 +1004,7 @@ unsigned ata_exec_internal(struct ata_destruct ata_queued_cmd *qc;unsigned int tag, preempted_tag;u32 preempted_sactive, preempted_qc_active; +int preempted_nr_active_links;DECLARE_COMPLETION (wait);unsigned long flags;unsigned int err_mask;
@@ -1043,9 +1043,11 @@ unsigned ata_exec_internal(struct ata_de 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;
@@ -1112,6 +1114,7 @@ unsigned ata_exec_internal(struct ata_de 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
@@ -4327,10 +4330,18 @@ void __ata_qc_complete(struct ata_queuedata_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 =NULL ;/* atapi: mark qc as inactive to prevent the interrupt handler * from completing the command twice later, before the error handler
@@ -4503,9 +4514,14 @@ void ata_qc_issue(struct ata_queued_cmdif (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/scsi/libata-eh.c +5 -0
@@ -248,6 +248,7 @@ void ata_scsi_error(struct Scsi_Host *ho } ap->flags &= ~ATA_FLAG_EH_PENDING ; + ap->excl_link =NULL ;/* don't maintain exclusion over EH */ spin_unlock_irqrestore (hs_lock, flags);
@@ -1873,6 +1874,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 ; }static void ata_eh_scsi_handle_link_detach (struct ata_link *link)
include/linux/libata.h +8 -0
@@ -181,6 +181,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 */
@@ -520,12 +521,14 @@ 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 */ struct ata_device __dev1;/* storage for link.device[1] */ int nr_pm_links;/* nr of available PM links */ struct ata_link *pm_link;/* array of PM links */ +struct ata_link *excl_link;/* for PM qc exclusion */ struct ata_host_stats stats;struct ata_host_set *host_set;
@@ -931,6 +934,11 @@ static inline int ata_link_max_devices(creturn 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_pm_links)
Signature · 1 line
1.2.4
PATCH 7/7 libata-pm-prep: add HRST_TO_RESUME and implement resume action helpers
In reply to Tejun HeoSome PM needs hardreset to resume link. Add ATA_LFLAG_HRST_TO_RESUME to mark such links and separate out ata_link_resume_action() such that the test can be done in one place and, while at it, separate out ata_link_init_probe() which sets resume action and probe mask from ata_device_add(). These resume/probing related helpers will be used by PM.
---
drivers/scsi/libata-core.c | 7 +------ drivers/scsi/libata-eh.c | 6 +++--- drivers/scsi/libata-scsi.c | 4 ++-- include/linux/libata.h | 17 +++++++++++++++++ 4 files changed, 23 insertions(+), 11 deletions(-)
b23bfeecdddff57fd54e62193ae8b05e88729c63
drivers/scsi/libata-core.c +1 -6
@@ -5472,14 +5472,9 @@ int ata_device_add(const struct ata_probata_port_probe (ap);spin_lock_irqsave (&ap->host_set->lock, flags); - - ap->link.eh_info.probe_mask = - (1 <<ata_link_max_devices (&ap->link)) -1 ; - ap->link.eh_info.action |=ATA_EH_SOFTRESET ; -set_bit (bit, &ap->flags); +ata_link_init_probe (&ap->link);ata_port_schedule_eh (ap); -spin_unlock_irqrestore (&ap->host_set->lock, flags); wait_on_bit(&ap->flags, bit, ata_boot_probe_wait,
drivers/scsi/libata-eh.c +3 -3
@@ -941,7 +941,7 @@ static void ata_eh_analyze_serror(struct }if (serror & (SERR_PHYRDY_CHG |SERR_DEV_XCHG )) { err_mask |=AC_ERR_ATA_BUS ; - action |=ATA_EH_HARDRESET ; + action |=ata_link_resume_action (link); ehc->i.probe_mask |=1 ; }
@@ -1695,7 +1695,7 @@ int ata_eh_recover(struct ata_port *ap,ata_eh_detach_dev (dev);ata_dev_init (dev); ehc->did_probe_mask |= (1 << dev->devno); - ehc->i.action |=ATA_EH_SOFTRESET ; + ehc->i.action |=ata_link_resume_action (link); } } }
@@ -1805,7 +1805,7 @@ int ata_eh_recover(struct ata_port *ap, ehc->tries[dev->devno] =ATA_EH_DEV_TRIES ; ehc->did_probe_mask |= (1 << dev->devno); - ehc->i.action |=ATA_EH_SOFTRESET ; + ehc->i.action |=ata_link_resume_action (link); } }else {/* soft didn't work? be haaaaard */
drivers/scsi/libata-scsi.c +2 -2
@@ -2903,7 +2903,7 @@ static int ata_scsi_user_scan(struct Scsata_port_for_each_link (link, ap) { link->eh_info.probe_mask |= (1 <<ata_link_max_devices (link)) -1 ; - link->eh_info.action |=ATA_EH_SOFTRESET ; + link->eh_info.action |=ata_link_resume_action (link); } }else {struct ata_device *dev =ata_find_dev (ap, id);
@@ -2911,7 +2911,7 @@ static int ata_scsi_user_scan(struct Scsif (dev) { link = dev->link; link->eh_info.probe_mask |=1 << dev->devno; - link->eh_info.action |=ATA_EH_SOFTRESET ; + link->eh_info.action |=ata_link_resume_action (link); }else rc = -EINVAL ; }
include/linux/libata.h +17 -0
@@ -143,6 +143,9 @@ enum {ATA_DEV_ERING_SIZE =32 ,/* record 32 recent errors */ +/* struct ata_link flags */ +ATA_LFLAG_HRST_TO_RESUME = (1 <<0 ),/* hardreset needed to resume */ +/* struct ata_port flags */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev *//* (doesn't imply presence) */
@@ -934,6 +937,20 @@ static inline int ata_link_max_devices(creturn 1 ; } +static inline unsigned int ata_link_resume_action (struct ata_link *link) +{ +if (link->flags &ATA_LFLAG_HRST_TO_RESUME ) +return ATA_EH_HARDRESET ; +return ATA_EH_SOFTRESET ; +} + +static inline void ata_link_init_probe (struct ata_link *link) +{ + link->eh_info.probe_mask = (1 <<ata_link_max_devices (link)) -1 ; + link->eh_info.action =ata_link_resume_action (link); + link->eh_context.i = link->eh_info; +} +static inline int ata_link_active (struct ata_link *link) {return ata_tag_valid (link->active_tag) || link->sactive;
Signature · 1 line
1.2.4