libata: new reset mechanism, take#2
PATCH 1/1 libata: new reset mechanism, take#2
Hello, all.
This is the second take of new reset mechanism patchset and against upstream-2.6.17 + eh-misc-updates patchset + three ahci update patches I've sent yesterday.
The goals of new reset mechanism are.
* Do not allow individual reset methods manipulate libata internal data structures (e.g. disable port) to give more control to higher driving logic (e.g. to allow retries).
* Goes hand-in-hand with above. Make low level operations easily shareable with other uses (probe and EH).
* Minimize code duplications but yet allow flexibility if needed.
Major difference from the first take is that core layer doesn't directly drive resets anymore. It just calls ->probe_reset and the rest is upto the low level driver. However, as reset driving logic is identical for most drivers, helper routines are supplied such that low level drivers only have to implement supported reset operations.
Jeff, I think the above change hopefully resolves your concern about fixed driving logic. The other issue was regarding how reset itself should be performed - resets are event-driven in nature and should be implemented accordingly as a qc protocol. I still disagree and don't really see how it can be done. My rationales are in the following two messages. Can you please share your thoughts in deeper detail?
http://marc.theaimsgroup.com/?l=linux-ide&m=113497224219265&w=2
http://marc.theaimsgroup.com/?l=linux-ide&m=113497644716191&w=2
Thanks.
--
tejun
PATCH 1/12 libata: export ata_busy_sleep
Export ata_busy_sleep(), to be used by low level driver reset functions.
---
drivers/scsi/libata-core.c | 9 +++------ include/linux/libata.h | 3 +++ 2 files changed, 6 insertions(+), 6 deletions(-)
902e47427cf54147ffa1450794b5d953696ea10e
drivers/scsi/libata-core.c +3 -6
@@ -61,9 +61,6 @@#include "libata.h" -static unsigned int ata_busy_sleep (struct ata_port *ap, -unsigned long tmout_pat, -unsigned long tmout);static void ata_dev_reread_id (struct ata_port *ap,struct ata_device *dev);static void ata_dev_init_params (struct ata_port *ap,struct ata_device *dev);static void ata_set_mode (struct ata_port *ap);
@@ -2007,9 +2004,8 @@ err_out:* */ -static unsigned int ata_busy_sleep (struct ata_port *ap, -unsigned long tmout_pat, -unsigned long tmout) +unsigned int ata_busy_sleep (struct ata_port *ap, +unsigned long tmout_pat,unsigned long tmout) {unsigned long timer_start, timeout;u8 status;
@@ -5207,6 +5203,7 @@ EXPORT_SYMBOL_GPL(__sata_phy_reset);EXPORT_SYMBOL_GPL (ata_bus_reset);EXPORT_SYMBOL_GPL (ata_port_disable);EXPORT_SYMBOL_GPL (ata_ratelimit); +EXPORT_SYMBOL_GPL (ata_busy_sleep);EXPORT_SYMBOL_GPL (ata_scsi_ioctl);EXPORT_SYMBOL_GPL (ata_scsi_queuecmd);EXPORT_SYMBOL_GPL (ata_scsi_error);
include/linux/libata.h +3 -0
@@ -503,6 +503,9 @@ extern int ata_scsi_device_suspend(strucextern int ata_device_resume (struct ata_port *,struct ata_device *);extern int ata_device_suspend (struct ata_port *,struct ata_device *);extern int ata_ratelimit (void ); +extern unsigned int ata_busy_sleep (struct ata_port *ap, +unsigned long timeout_pat, +unsigned long timeout);/* * Default driver ops implementations
Signature · 1 line
1.1.3
Jeff Garzik
AppliedRe: [PATCH 01/12] libata: export ata_busy_sleep
Quoted 3 lines · Tejun Heo
Export
ata_busy_sleep(), to be used by low level driver reset functions.Signed-off-by Tejun Heo <[email protected]>
applied
PATCH 2/12 libata: modify ata_dev_try_classify
In reply to Tejun HeoMake ata_dev_try_classify take @r_err to store tf error register value on completion and return device class instead of directly manipulating dev->class. This is preparation for new reset mechanism.
---
drivers/scsi/libata-core.c | 30 ++++++++++++++++-------------- 1 files changed, 16 insertions(+), 14 deletions(-)
0ac93b37ce5955cee51d85fa2810cb40b8909c33
drivers/scsi/libata-core.c +16 -14
@@ -830,6 +830,7 @@ unsigned int ata_dev_classify(const stru* ata_dev_try_classify - Parse returned ATA device signature * @ap: ATA channel to examine * @device: Device to examine (starting at zero) +* @r_err: Value of error register on completion * * After an event -- SRST, E.D.D., or SATA COMRESET -- occurs, * an ATA/ATAPI-defined set of values is placed in the ATA
@@ -842,11 +843,14 @@ unsigned int ata_dev_classify(const stru* * LOCKING: * caller. +* +* RETURNS: +* Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE. */ -static u8 ata_dev_try_classify (struct ata_port *ap,unsigned int device) +static unsigned int +ata_dev_try_classify (struct ata_port *ap,unsigned int device,u8 *r_err) { -struct ata_device *dev = &ap->device[device];struct ata_taskfile tf;unsigned int class;u8 err;
@@ -857,8 +861,8 @@ static u8 ata_dev_try_classify(struct at ap->ops->tf_read (ap, &tf); err = tf.feature; - - dev->class =ATA_DEV_NONE ; +if (r_err) + *r_err = err;/* see if device passed diags */ if (err ==1 )
@@ -866,18 +870,16 @@ static u8 ata_dev_try_classify(struct atelse if ((device ==0 ) && (err ==0x81 ))/* do nothing */ ;else -return err; +return ATA_DEV_NONE ; -/* determine if device if ATA or ATAPI */ +/* determine if device is ATA or ATAPI */ class =ata_dev_classify (&tf); +if (class ==ATA_DEV_UNKNOWN ) -return err; +return ATA_DEV_NONE ;if ((class ==ATA_DEV_ATA ) && (ata_chk_status (ap) ==0 )) -return err; - - dev->class = class; - -return err; +return ATA_DEV_NONE ; +return class; }/**
@@ -2224,9 +2226,9 @@ void ata_bus_reset(struct ata_port *ap)/* * determine by signature whether we have ATA or ATAPI devices */ - err =ata_dev_try_classify (ap,0 ); + ap->device[0 ].class =ata_dev_try_classify (ap,0 , &err);if ((slave_possible) && (err !=0x81 )) -ata_dev_try_classify (ap,1 ); + ap->device[1 ].class =ata_dev_try_classify (ap,1 , &err);/* re-enable interrupts */ if (ap->ioaddr.ctl_addr)/* FIXME: hack. create a hook instead */
Signature · 1 line
1.1.3
Re: [PATCH 02/12] libata: modify ata_dev_try_classify
Quoted 5 lines · Tejun Heo
Make
ata_dev_try_classifytake @r_err to store tf error register value on completion and return device class instead of directly manipulatingdev->class. This is preparation for new reset mechanism.Signed-off-by Tejun Heo <[email protected]>
applied 2-3
PATCH 3/12 libata: new ->probe_reset operation
In reply to Tejun HeoAdd new ->probe_reset operation to ata_port_operations obsoleting ->phy_reset. The main difference from ->phy_reset is that the new operation is not allowed to manipulate libata internals directly. It's not allowed to configure or disable the port or devices. It can only succeed or fail and classify attached devices into passed @classes.
This change gives more control to higher level and eases sharing reset methods with EH.
---
drivers/scsi/libata-core.c | 19 ++++++++++++++++++- include/linux/libata.h | 8 +++++--- 2 files changed, 23 insertions(+), 4 deletions(-)
65ce0d036067942117a705c7293aa544804e47a1
drivers/scsi/libata-core.c +18 -1
@@ -1532,7 +1532,24 @@ static int ata_bus_probe(struct ata_port {unsigned int i, found =0 ; - ap->ops->phy_reset (ap); +if (ap->ops->probe_reset) { +unsigned int classes[ATA_MAX_DEVICES ]; +int rc; + +ata_port_probe (ap); + + rc = ap->ops->probe_reset (ap, classes); +if (rc ==0 ) { +for (i =0 ; i <ATA_MAX_DEVICES ; i++) + ap->device[i].class = classes[i]; + }else { +printk (KERN_ERR "ata%u: probe reset failed, " +"disabling port\n" , ap->id); +ata_port_disable (ap); + } + }else + ap->ops->phy_reset (ap); +if (ap->flags &ATA_FLAG_PORT_DISABLED ) goto err_out;
include/linux/libata.h +5 -3
@@ -148,9 +148,9 @@ enum {ATA_FLAG_PORT_DISABLED = (1 <<2 ),/* port is disabled, ignore it */ ATA_FLAG_SATA = (1 <<3 ),ATA_FLAG_NO_LEGACY = (1 <<4 ),/* no legacy mode check */ -ATA_FLAG_SRST = (1 <<5 ),/* use ATA SRST, not E.D.D. */ +ATA_FLAG_SRST = (1 <<5 ),/* (obsolete) use ATA SRST, not E.D.D. */ ATA_FLAG_MMIO = (1 <<6 ),/* use MMIO, not PIO */ -ATA_FLAG_SATA_RESET = (1 <<7 ),/* use COMRESET */ +ATA_FLAG_SATA_RESET = (1 <<7 ),/* (obsolete) use COMRESET */ ATA_FLAG_PIO_DMA = (1 <<8 ),/* PIO cmds via DMA */ ATA_FLAG_NOINTR = (1 <<9 ),/* FIXME: Remove this once * proper HSM is in place. */
@@ -422,7 +422,9 @@ struct ata_port_operations {u8 (*check_altstatus)(struct ata_port *ap);void (*dev_select)(struct ata_port *ap,unsigned int device); -void (*phy_reset) (struct ata_port *ap); +void (*phy_reset) (struct ata_port *ap);/* obsolete */ +int (*probe_reset) (struct ata_port *ap,unsigned int *classes); +void (*post_set_mode) (struct ata_port *ap);int (*check_atapi_dma) (struct ata_queued_cmd *qc);
Signature · 1 line
1.1.3
PATCH 4/12 libata: implement ata_drive_probe_reset()
In reply to Tejun HeoMost low level drivers share supported reset/classify actions and sequence. This patch implements ata_drive_probe_reset() which helps constructing ->probe_reset from three component operations - softreset, hardreset and postreset. This minimizes duplicate code and yet allows flexibility if needed. The three component operations can also be shared by EH later.
---
drivers/scsi/libata-core.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 5 ++ 2 files changed, 94 insertions(+), 0 deletions(-)
a0161772ae1a16f1a4ffb5f830752ccc3bf44e9f
drivers/scsi/libata-core.c +89 -0
@@ -2280,6 +2280,94 @@ err_out:DPRINTK ("EXIT\n" ); } +static int do_probe_reset (struct ata_port *ap,ata_reset_fn_t reset, +ata_postreset_fn_t postreset, +unsigned int *classes) +{ +int i, rc; + +for (i =0 ; i <ATA_MAX_DEVICES ; i++) + classes[i] =ATA_DEV_UNKNOWN ; + + rc =reset (ap,0 , classes); +if (rc) +return rc; + +/* If any class isn't ATA_DEV_UNKNOWN, consider classification +* is complete and convert all ATA_DEV_UNKNOWN to +* ATA_DEV_NONE. +*/ +for (i =0 ; i <ATA_MAX_DEVICES ; i++) +if (classes[i] !=ATA_DEV_UNKNOWN ) +break ; + +if (i <ATA_MAX_DEVICES ) +for (i =0 ; i <ATA_MAX_DEVICES ; i++) +if (classes[i] ==ATA_DEV_UNKNOWN ) + classes[i] =ATA_DEV_NONE ; + +if (postreset) +postreset (ap, classes); + +return classes[0 ] !=ATA_DEV_UNKNOWN ?0 : -ENODEV ; +} + +/** +* ata_drive_probe_reset - Perform probe reset with given methods +* @ap: port to reset +* @softreset: softreset method (can be NULL) +* @hardreset: hardreset method (can be NULL) +* @postreset: postreset method (can be NULL) +* @classes: resulting classes of attached devices +* +* Reset the specified port and classify attached devices using +* given methods. This function prefers softreset but tries all +* possible reset sequences to reset and classify devices. This +* function is intended to be used for constructing ->probe_reset +* callback by low level drivers. +* +* Reset methods should follow the following rules. +* +* - Return 0 on sucess, -errno on failure. +* - If classification is supported, fill classes[] with +* recognized class codes. +* - If classification is not supported, leave classes[] alone. +* - If verbose is non-zero, print error message on failure; +* otherwise, shut up. +* +* LOCKING: +* Kernel thread context (may sleep) +* +* RETURNS: +* 0 on success, -EINVAL if no reset method is avaliable, -ENODEV +* if classification fails, and any error code from reset +* methods. +*/ +int ata_drive_probe_reset (struct ata_port *ap, +ata_reset_fn_t softreset,ata_reset_fn_t hardreset, +ata_postreset_fn_t postreset,unsigned int *classes) +{ +int rc = -EINVAL ; + +if (softreset) { + rc =do_probe_reset (ap, softreset, postreset, classes); +if (rc ==0 ) +return 0 ; + } + +if (!hardreset) +return rc; + + rc =do_probe_reset (ap, hardreset, postreset, classes); +if (rc ==0 || rc != -ENODEV ) +return rc; + +if (softreset) + rc =do_probe_reset (ap, softreset, postreset, classes); + +return rc; +} +static void ata_pr_blacklisted (const struct ata_port *ap,const struct ata_device *dev) {
@@ -5220,6 +5308,7 @@ EXPORT_SYMBOL_GPL(ata_port_probe);EXPORT_SYMBOL_GPL (sata_phy_reset);EXPORT_SYMBOL_GPL (__sata_phy_reset);EXPORT_SYMBOL_GPL (ata_bus_reset); +EXPORT_SYMBOL_GPL (ata_drive_probe_reset);EXPORT_SYMBOL_GPL (ata_port_disable);EXPORT_SYMBOL_GPL (ata_ratelimit);EXPORT_SYMBOL_GPL (ata_busy_sleep);
include/linux/libata.h +5 -0
@@ -244,6 +244,8 @@ struct ata_queued_cmd;/* typedefs */ typedef void (*ata_qc_cb_t ) (struct ata_queued_cmd *qc); +typedef int (*ata_reset_fn_t )(struct ata_port *,int ,unsigned int *); +typedef void (*ata_postreset_fn_t )(struct ata_port *ap,unsigned int *);struct ata_ioports {unsigned long cmd_addr;
@@ -481,6 +483,9 @@ extern void ata_port_probe(struct ata_poextern void __sata_phy_reset (struct ata_port *ap);extern void sata_phy_reset (struct ata_port *ap);extern void ata_bus_reset (struct ata_port *ap); +extern int ata_drive_probe_reset (struct ata_port *ap, +ata_reset_fn_t softreset,ata_reset_fn_t hardreset, +ata_postreset_fn_t postreset,unsigned int *classes);extern void ata_port_disable (struct ata_port *);extern void ata_std_ports (struct ata_ioports *ioaddr);#ifdef CONFIG_PCI
Signature · 1 line
1.1.3
Jeff Garzik
AppliedRe: [PATCH 04/12] libata: implement ata_drive_probe_reset()
Quoted 8 lines · Tejun Heo
Most low level drivers share supported reset/classify actions and sequence. This patch implements
ata_drive_probe_reset()which helps constructing ->probe_reset from three component operations - softreset, hardreset and postreset. This minimizes duplicate code and yet allows flexibility if needed. The three component operations can also be shared by EH later.Signed-off-by Tejun Heo <[email protected]>
applied
PATCH 5/12 libata: implement standard reset component operations and ->probe_reset
In reply to Tejun HeoImplement SRST, COMRESET and standard postreset component operations for ata_drive_probe_reset(), and use these three functions to implement ata_std_probe_reset.
---
drivers/scsi/libata-core.c | 206 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 6 + 2 files changed, 212 insertions(+), 0 deletions(-)
254523d00d03d4948a7452b0cbf04af7cb11f4fe
drivers/scsi/libata-core.c +206 -0
@@ -2280,6 +2280,208 @@ err_out:DPRINTK ("EXIT\n" ); } +/** +* ata_std_softreset - reset host port via ATA SRST +* @ap: port to reset +* @verbose: fail verbosely +* @classes: resulting classes of attached devices +* +* Reset host port using ATA SRST. This function is to be used +* as standard callback for ata_drive_*_reset() functions. +* +* LOCKING: +* Kernel thread context (may sleep) +* +* RETURNS: +* 0 on success, -errno otherwise. +*/ +int ata_std_softreset (struct ata_port *ap,int verbose,unsigned int *classes) +{ +unsigned int slave_possible = ap->flags &ATA_FLAG_SLAVE_POSS ; +unsigned int devmask =0 , err_mask; +u8 err; + +DPRINTK ("ENTER\n" ); + +/* determine if device 0/1 are present */ +if (ata_devchk (ap,0 )) + devmask |= (1 <<0 ); +if (slave_possible &&ata_devchk (ap,1 )) + devmask |= (1 <<1 ); + +/* devchk reports device presence without actual device on +* most SATA controllers. Check SStatus and turn devmask off +* if link is offline. Note that we should continue resetting +* even when it seems like there's no device. +*/ +if (ap->ops->scr_read && !sata_dev_present (ap)) + devmask =0 ; + +/* select device 0 again */ + ap->ops->dev_select (ap,0 ); + +/* issue bus reset */ +DPRINTK ("about to softreset, devmask=%x\n" , devmask); + err_mask =ata_bus_softreset (ap, devmask); +if (err_mask) { +if (verbose) +printk (KERN_ERR "ata%u: SRST failed (err_mask=0x%x)\n" , + ap->id, err_mask); +else +DPRINTK ("EXIT, softreset failed (err_mask=0x%x)\n" , + err_mask); +return -EIO ; + } + +/* determine by signature whether we have ATA or ATAPI devices */ + classes[0 ] =ata_dev_try_classify (ap,0 , &err); +if (slave_possible && err !=0x81 ) + classes[1 ] =ata_dev_try_classify (ap,1 , &err); + +DPRINTK ("EXIT, classes[0]=%u [1]=%u\n" , classes[0 ], classes[1 ]); +return 0 ; +} + +/** +* sata_std_hardreset - reset host port via SATA phy reset +* @ap: port to reset +* @verbose: fail verbosely +* @class: resulting class of attached device +* +* SATA phy-reset host port using DET bits of SControl register. +* This function is to be used as standard callback for +* ata_drive_*_reset(). +* +* LOCKING: +* Kernel thread context (may sleep) +* +* RETURNS: +* 0 on success, -errno otherwise. +*/ +int sata_std_hardreset (struct ata_port *ap,int verbose,unsigned int *class) +{ +u32 sstatus, serror; +unsigned long timeout = jiffies + (HZ *5 ); + +DPRINTK ("ENTER\n" ); + +/* Issue phy wake/reset */ +scr_write_flush (ap,SCR_CONTROL ,0x301 ); + +/* +* Couldn't find anything in SATA I/II specs, but AHCI-1.1 +* 10.4.2 says at least 1 ms. +*/ +msleep (1 ); + +scr_write_flush (ap,SCR_CONTROL ,0x300 ); + +/* Wait for phy to become ready, if necessary. */ +do { +msleep (200 ); + sstatus =scr_read (ap,SCR_STATUS ); +if ((sstatus &0xf ) !=1 ) +break ; + }while (time_before (jiffies, timeout)); + +/* Clear SError */ + serror =scr_read (ap,SCR_ERROR ); +scr_write (ap,SCR_ERROR , serror); + +/* TODO: phy layer with polling, timeouts, etc. */ +if (!sata_dev_present (ap)) { + *class =ATA_DEV_NONE ; +DPRINTK ("EXIT, link offline\n" ); +return 0 ; + } + +if (ata_busy_sleep (ap,ATA_TMOUT_BOOT_QUICK ,ATA_TMOUT_BOOT )) { +if (verbose) +printk (KERN_ERR "ata%u: COMRESET failed " +"(device not ready)\n" , ap->id); +else +DPRINTK ("EXIT, device not ready\n" ); +return -EIO ; + } + + *class =ata_dev_try_classify (ap,0 ,NULL ); + +DPRINTK ("EXIT, class=%u\n" , *class); +return 0 ; +} + +/** +* ata_std_postreset - standard postreset callback +* @ap: the target ata_port +* @classes: classes of attached devices +* +* This function is invoked after a successful reset. Note that +* the device might have been reset more than once using +* different reset methods before postreset is invoked. +* postreset is also reponsible for setting cable type. +* +* This function is to be used as standard callback for +* ata_drive_*_reset(). +* +* LOCKING: +* Kernel thread context (may sleep) +*/ +void ata_std_postreset (struct ata_port *ap,unsigned int *classes) +{ +DPRINTK ("ENTER\n" ); + +/* set cable type */ +if (ap->cbl ==ATA_CBL_NONE && ap->flags &ATA_FLAG_SATA ) + ap->cbl =ATA_CBL_SATA ; + +/* print link status */ +if (ap->cbl ==ATA_CBL_SATA ) +sata_print_link_status (ap); + +/* bail out if no device is present */ +if (classes[0 ] ==ATA_DEV_NONE && classes[1 ] ==ATA_DEV_NONE ) { +DPRINTK ("EXIT, no device\n" ); +return ; + } + +/* is double-select really necessary? */ +if (classes[0 ] !=ATA_DEV_NONE ) + ap->ops->dev_select (ap,1 ); +if (classes[1 ] !=ATA_DEV_NONE ) + ap->ops->dev_select (ap,0 ); + +/* re-enable interrupts & set up device control */ +if (ap->ioaddr.ctl_addr)/* FIXME: hack. create a hook instead */ +ata_irq_on (ap); + +DPRINTK ("EXIT\n" ); +} + +/** +* ata_std_probe_reset - standard probe reset method +* @ap: prot to perform probe-reset +* @classes: resulting classes of attached devices +* +* The stock off-the-shelf ->probe_reset method. +* +* LOCKING: +* Kernel thread context (may sleep) +* +* RETURNS: +* 0 on success, -errno otherwise. +*/ +int ata_std_probe_reset (struct ata_port *ap,unsigned int *classes) +{ +ata_reset_fn_t hardreset; + + hardreset =NULL ; +if (ap->cbl ==ATA_CBL_SATA && ap->ops->scr_read) + hardreset = sata_std_hardreset; + +return ata_drive_probe_reset (ap, ata_std_softreset, hardreset, + ata_std_postreset, classes); +} +static int do_probe_reset (struct ata_port *ap,ata_reset_fn_t reset,ata_postreset_fn_t postreset,unsigned int *classes)
@@ -5308,6 +5510,10 @@ EXPORT_SYMBOL_GPL(ata_port_probe);EXPORT_SYMBOL_GPL (sata_phy_reset);EXPORT_SYMBOL_GPL (__sata_phy_reset);EXPORT_SYMBOL_GPL (ata_bus_reset); +EXPORT_SYMBOL_GPL (ata_std_softreset); +EXPORT_SYMBOL_GPL (sata_std_hardreset); +EXPORT_SYMBOL_GPL (ata_std_postreset); +EXPORT_SYMBOL_GPL (ata_std_probe_reset);EXPORT_SYMBOL_GPL (ata_drive_probe_reset);EXPORT_SYMBOL_GPL (ata_port_disable);EXPORT_SYMBOL_GPL (ata_ratelimit);
include/linux/libata.h +6 -0
@@ -486,6 +486,11 @@ extern void ata_bus_reset(struct ata_porextern int ata_drive_probe_reset (struct ata_port *ap,ata_reset_fn_t softreset,ata_reset_fn_t hardreset,ata_postreset_fn_t postreset,unsigned int *classes); +extern int ata_std_softreset (struct ata_port *ap,int verbose, +unsigned int *classes); +extern int sata_std_hardreset (struct ata_port *ap,int verbose, +unsigned int *class); +extern void ata_std_postreset (struct ata_port *ap,unsigned int *classes);extern void ata_port_disable (struct ata_port *);extern void ata_std_ports (struct ata_ioports *ioaddr);#ifdef CONFIG_PCI
@@ -526,6 +531,7 @@ extern void ata_std_dev_select (struct aextern u8 ata_check_status (struct ata_port *ap);extern u8 ata_altstatus (struct ata_port *ap);extern void ata_exec_command (struct ata_port *ap,const struct ata_taskfile *tf); +extern int ata_std_probe_reset (struct ata_port *ap,unsigned int *classes);extern int ata_port_start (struct ata_port *ap);extern void ata_port_stop (struct ata_port *ap);extern void ata_host_stop (struct ata_host_set *host_set);
Signature · 1 line
1.1.3
Jeff Garzik
AppliedRe: [PATCH 05/12] libata: implement standard reset component operations and ->probe_reset
Quoted 5 lines · Tejun Heo
Implement SRST, COMRESET and standard postreset component operations for
ata_drive_probe_reset(), and use these three functions to implementata_std_probe_reset.Signed-off-by Tejun Heo <[email protected]>
applied
PATCH 6/12 sata_sil: convert to new reset mechanism
In reply to Tejun HeoConvert sata_sil to use new reset mechanism. sata_sil is fairly generic and can directly use std routine.
---
drivers/scsi/sata_sil.c | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-)
48aa3f1d130e624f5789307286aacd6880b7ac0e
drivers/scsi/sata_sil.c +4 -5
@@ -157,7 +157,7 @@ static const struct ata_port_operations .check_status = ata_check_status, .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, - .phy_reset = sata_phy_reset, + .probe_reset = ata_std_probe_reset, .post_set_mode = sil_post_set_mode, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start,
@@ -180,7 +180,7 @@ static const struct ata_port_info sil_po { .sht = &sil_sht, .host_flags =ATA_FLAG_SATA |ATA_FLAG_NO_LEGACY | - ATA_FLAG_SRST | ATA_FLAG_MMIO, + ATA_FLAG_MMIO, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */
@@ -189,8 +189,7 @@ static const struct ata_port_info sil_po { .sht = &sil_sht, .host_flags =ATA_FLAG_SATA |ATA_FLAG_NO_LEGACY | -ATA_FLAG_SRST |ATA_FLAG_MMIO | - SIL_FLAG_MOD15WRITE, + ATA_FLAG_MMIO | SIL_FLAG_MOD15WRITE, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */
@@ -199,7 +198,7 @@ static const struct ata_port_info sil_po { .sht = &sil_sht, .host_flags =ATA_FLAG_SATA |ATA_FLAG_NO_LEGACY | - ATA_FLAG_SRST | ATA_FLAG_MMIO, + ATA_FLAG_MMIO, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */
Signature · 1 line
1.1.3
Re: [PATCH 06/12] sata_sil: convert to new reset mechanism
Quoted 4 lines · Tejun Heo
Convert
sata_silto use new reset mechanism.sata_silis fairly generic and can directly use std routine.Signed-off-by Tejun Heo <[email protected]>
Major NAK.
The placement of every hardware register read/write has been very carefully laid out, and your reset hardware re-orders a lot of that. Code re-ordering is fine. Changing the order of I/O operations is not.
With this patch, sata_sil fails to wake up and initialize the SATA phy!
Proper code transformation is art. You're doing really well, but this was a bit of a hiccup. You should have presented a series of patches which changed over to your new ata_drive_probe_reset() stuff, while -not changing the hardware operations at all-. Like a mathematical solution, your code is then provably correct. If there is a regression, then you know it is a driver bug, and not a problem with hardware acting weird.
If the driver can access the SATA PHY registers, the very first thing it should usually do is the code in sata_std_hardreset()... everything except the 0x301 value write. Or in other words, follow the code in __sata_phy_reset() PRECISELY (presuming that ATA_FLAG_SATA_RESET is not set).
sata_sil hardware initialization order and behavior should not change at all [though certainly you will change it sometime in the future].
So... I will drop all other patches from you, let you resync with the latest stuff in libata-dev.git#upstream (NOTE: renamed from upstream-2.6.17 to upstream), and wait for your next barrage of patches ;-)
Jeff
Re: [PATCH 06/12] sata_sil: convert to new reset mechanism
Quoted 1 line · Jeff Garzik
If the driver can access the SATA PHY registers, the very first thing it should usually do is the code in
sata_std_hardreset()... everything except the0x301value write.
...and possibly the device classification. Probably want to do a soft reset, then get the signature. Read the port multiplier spec PM initialization sequence... that is a highly relevant description.
Jeff
Re: [PATCH 06/12] sata_sil: convert to new reset mechanism
In reply to Jeff GarzikQuoted 10 lines · Jeff Garzik
Quoted 4 lines · Tejun Heo
Convert
sata_silto use new reset mechanism.sata_silis fairly generic and can directly use std routine.Signed-off-by Tejun Heo <[email protected]>Major NAK.
Quoted 8 lines
The placement of every hardware register read/write has been very carefully laid out, and your reset hardware re-orders a lot of that. Code re-ordering is fine. Changing the order of I/O operations is not.
With this patch,sata_silfails to wake up and initialize the SATA phy!Proper code transformation is art. You're doing really well, but this was a bit of a hiccup. You should have presented a series of patches which changed over to your new
ata_drive_probe_reset()stuff, while -not changing the hardware operations at all-. Like a mathematical solution, your code is then provably correct. If there is a regression, then you know it is a driver bug, and not a problem with hardware acting weird.If the driver can access the SATA PHY registers, the very first thing it should usually do is the code in
sata_std_hardreset()... everything except the0x301value write. Or in other words, follow the code in__sata_phy_reset()PRECISELY (presuming thatATA_FLAG_SATA_RESETis not set).
sata_silhardware initialization order and behavior should not change at all [though certainly you will change it sometime in the future].
Okay, I see. I'll rewrite those parts such that it acts in the same way as the original reset.
Quoted 1 line
So... I will drop all other patches from you, let you resync with the latest stuff in libata-dev.git#upstream (NOTE: renamed from upstream-2.6.17 to upstream), and wait for your next barrage of patches ;-)
It's lunar new year here and I am away from office until 1st Feb, so it will take me some time.
Thanks a lot for all your help and guidance. It's been a great year.
Happy (lunar) new year, guys. :-)
Signature · 1 line
tejun
Re: [PATCH 06/12] sata_sil: convert to new reset mechanism
Quoted 3 lines · Tejun
Thanks a lot for all your help and guidance. It's been a great year.
Happy (lunar) new year, guys. :-)
Definitely! Once we get EH/reset stuff taken care of, hotplug, NCQ and other fun will be a lot easier to implement.
Thanks,
Jeff
PATCH 7/12 sata_sil24: convert to new reset mechanism
In reply to Tejun HeoConvert sata_sil24 ->phy_reset to new reset mechanism.
---
drivers/scsi/sata_sil24.c | 55 ++++++++++++++++++++++----------------------- 1 files changed, 27 insertions(+), 28 deletions(-)
0e78d1ce36a30c8e8168af303579c248e32467f1
drivers/scsi/sata_sil24.c +27 -28
@@ -249,7 +249,7 @@ static u8 sil24_check_status(struct ata_static u32 sil24_scr_read (struct ata_port *ap,unsigned sc_reg);static void sil24_scr_write (struct ata_port *ap,unsigned sc_reg,u32 val);static void sil24_tf_read (struct ata_port *ap,struct ata_taskfile *tf); -static void sil24_phy_reset (struct ata_port *ap); +static int sil24_probe_reset (struct ata_port *ap,unsigned int *classes);static void sil24_qc_prep (struct ata_queued_cmd *qc);static unsigned int sil24_qc_issue (struct ata_queued_cmd *qc);static void sil24_irq_clear (struct ata_port *ap);
@@ -305,7 +305,7 @@ static const struct ata_port_operations .tf_read = sil24_tf_read, - .phy_reset = sil24_phy_reset, + .probe_reset = sil24_probe_reset, .qc_prep = sil24_qc_prep, .qc_issue = sil24_qc_issue,
@@ -335,8 +335,8 @@ static struct ata_port_info sil24_port_i { .sht = &sil24_sht, .host_flags =ATA_FLAG_SATA |ATA_FLAG_NO_LEGACY | -ATA_FLAG_SRST |ATA_FLAG_MMIO | - ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(4), +ATA_FLAG_MMIO |ATA_FLAG_PIO_DMA | + SIL24_NPORTS2FLAG(4), .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */
@@ -346,8 +346,8 @@ static struct ata_port_info sil24_port_i { .sht = &sil24_sht, .host_flags =ATA_FLAG_SATA |ATA_FLAG_NO_LEGACY | -ATA_FLAG_SRST |ATA_FLAG_MMIO | - ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(2), +ATA_FLAG_MMIO |ATA_FLAG_PIO_DMA | + SIL24_NPORTS2FLAG(2), .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */
@@ -357,8 +357,8 @@ static struct ata_port_info sil24_port_i { .sht = &sil24_sht, .host_flags =ATA_FLAG_SATA |ATA_FLAG_NO_LEGACY | -ATA_FLAG_SRST |ATA_FLAG_MMIO | - ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(1), +ATA_FLAG_MMIO |ATA_FLAG_PIO_DMA | + SIL24_NPORTS2FLAG(1), .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */
@@ -427,7 +427,8 @@ static void sil24_tf_read(struct ata_por *tf = pp->tf; } -static int sil24_issue_SRST (struct ata_port *ap) +static int sil24_softreset (struct ata_port *ap,int verbose, +unsigned int *class) {void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;struct sil24_port_priv *pp = ap->private_data;
@@ -436,6 +437,8 @@ static int sil24_issue_SRST(struct ata_pu32 irq_enable, irq_stat;int cnt; +DPRINTK ("ENTER\n" ); +/* temporarily turn off IRQs during SRST */ irq_enable =readl (port +PORT_IRQ_ENABLE_SET );writel (irq_enable, port +PORT_IRQ_ENABLE_CLR );
@@ -465,30 +468,26 @@ static int sil24_issue_SRST(struct ata_p/* restore IRQs */ writel (irq_enable, port +PORT_IRQ_ENABLE_SET ); -if (!(irq_stat &PORT_IRQ_COMPLETE )) -return -1 ; +if (sata_dev_present (ap)) { +if (!(irq_stat &PORT_IRQ_COMPLETE )) { +DPRINTK ("EXIT, srst failed\n" ); +return -EIO ; + } -/* update TF */ -sil24_update_tf (ap); +sil24_update_tf (ap); + *class =ata_dev_classify (&pp->tf); + } +if (*class ==ATA_DEV_UNKNOWN ) + *class =ATA_DEV_NONE ; + +DPRINTK ("EXIT, class=%u\n" , *class);return 0 ; } -static void sil24_phy_reset (struct ata_port *ap) +static int sil24_probe_reset (struct ata_port *ap,unsigned int *classes) { -struct sil24_port_priv *pp = ap->private_data; - -__sata_phy_reset (ap); -if (ap->flags &ATA_FLAG_PORT_DISABLED ) -return ; - -if (sil24_issue_SRST (ap) <0 ) { - printk(KERN_ERR DRV_NAME - " ata%u: SRST failed, disabling port\n", ap->id); - ap->ops->port_disable (ap); -return ; - } - - ap->device->class =ata_dev_classify (&pp->tf); +return ata_drive_probe_reset (ap, sil24_softreset,NULL , + ata_std_postreset, classes); } static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
Signature · 1 line
1.1.3
PATCH 8/12 sata_sil24: add hardreset
In reply to Tejun HeoNow that libata is smart enough to handle both soft and hard resets, add hardreset method. Note that sil24 hardreset doesn't supply signature; still, the new reset mechanism can make good use of it.
---
drivers/scsi/sata_sil24.c | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-)
873ad4e86a46fa83982f694d56d2b9e52d0c2b6a
drivers/scsi/sata_sil24.c +10 -1
@@ -484,9 +484,18 @@ static int sil24_softreset(struct ata_poreturn 0 ; } +static int sil24_hardreset (struct ata_port *ap,int verbose, +unsigned int *class) +{ +unsigned int dummy_class; + +/* sil24 doesn't report device signature after hard reset */ +return sata_std_hardreset (ap, verbose, &dummy_class); +} +static int sil24_probe_reset (struct ata_port *ap,unsigned int *classes) { -return ata_drive_probe_reset (ap, sil24_softreset,NULL , +return ata_drive_probe_reset (ap, sil24_softreset, sil24_hardreset, ata_std_postreset, classes); }
Signature · 1 line
1.1.3
PATCH 9/12 ata_piix: convert pata to new reset mechanism
In reply to Tejun HeoConvert ata_piix pata ->phy_reset to new reset mechanism.
---
drivers/scsi/ata_piix.c | 46 ++++++++++++++++++++++++++++++---------------- 1 files changed, 30 insertions(+), 16 deletions(-)
3e72273956b2974ad50165c34b278164fd4094d4
drivers/scsi/ata_piix.c +30 -16
@@ -129,7 +129,7 @@ enum {static int piix_init_one (struct pci_dev *pdev,const struct pci_device_id *ent); -static void piix_pata_phy_reset (struct ata_port *ap); +static int piix_pata_probe_reset (struct ata_port *ap,unsigned int *classes);static void piix_sata_phy_reset (struct ata_port *ap);static void piix_set_piomode (struct ata_port *ap,struct ata_device *adev);static void piix_set_dmamode (struct ata_port *ap,struct ata_device *adev);
@@ -205,7 +205,7 @@ static const struct ata_port_operations .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, - .phy_reset = piix_pata_phy_reset, + .probe_reset = piix_pata_probe_reset, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start,
@@ -256,8 +256,7 @@ static struct ata_port_info piix_port_in/* ich5_pata */ { .sht = &piix_sht, - .host_flags =ATA_FLAG_SLAVE_POSS |ATA_FLAG_SRST | - PIIX_FLAG_CHECKINTR, + .host_flags = ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR, .pio_mask =0x1f ,/* pio0-4 */ #if 0 .mwdma_mask = 0x06, /* mwdma1-2 */
@@ -282,7 +281,7 @@ static struct ata_port_info piix_port_in/* piix4_pata */ { .sht = &piix_sht, - .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .host_flags = ATA_FLAG_SLAVE_POSS, .pio_mask =0x1f ,/* pio0-4 */ #if 0 .mwdma_mask = 0x06, /* mwdma1-2 */
@@ -363,30 +362,45 @@ cbl40: }/** -* piix_pata_phy_reset - Probe specified port on PATA host controller -* @ap: Port to probe +* piix_pata_postreset - Postreset stuff on PATA host controller +* @ap: Target port +* @classes: Classes of attached devices * -* Probe PATA phy. +* Postreset processing including cable detection. * * LOCKING: * None (inherited from caller). */ +static void piix_pata_postreset (struct ata_port *ap,unsigned int *classes) +{ +piix_pata_cbl_detect (ap); +ata_std_postreset (ap, classes); +} -static void piix_pata_phy_reset (struct ata_port *ap) +/** +* piix_pata_probe_reset - Perform reset on PATA port and classify +* @ap: Port to reset +* @classes: Resulting classes of attached devices +* +* Reset PATA phy and classify attached devices. +* +* LOCKING: +* None (inherited from caller). +*/ +static int piix_pata_probe_reset (struct ata_port *ap,unsigned int *classes) {struct pci_dev *pdev =to_pci_dev (ap->host_set->dev); +int i;if (!pci_test_config_bits (pdev, &piix_enable_bits[ap->hard_port_no])) { -ata_port_disable (ap); +for (i =0 ; i <ATA_MAX_DEVICES ; i++) + classes[i] =ATA_DEV_NONE ;printk (KERN_INFO "ata%u: port disabled. ignoring.\n" , ap->id); -return ; +return 0 ; } -piix_pata_cbl_detect (ap); - -ata_port_probe (ap); - -ata_bus_reset (ap); +return ata_drive_probe_reset (ap, ata_std_softreset,NULL , + piix_pata_postreset, classes); }/**
Signature · 1 line
1.1.3
PATCH 10/12 ata_piix: convert sata to new reset mechanism
In reply to Tejun HeoConvert ata_piix sata ->phy_reset to new reset mechanism.
---
drivers/scsi/ata_piix.c | 43 +++++++++++++++++++++---------------------- 1 files changed, 21 insertions(+), 22 deletions(-)
06160eed7c3ea396b25298f0e7a92d81e15cb3f2
drivers/scsi/ata_piix.c +21 -22
@@ -130,7 +130,7 @@ static int piix_init_one (struct pci_dev const struct pci_device_id *ent);static int piix_pata_probe_reset (struct ata_port *ap,unsigned int *classes); -static void piix_sata_phy_reset (struct ata_port *ap); +static int piix_sata_probe_reset (struct ata_port *ap,unsigned int *classes);static void piix_set_piomode (struct ata_port *ap,struct ata_device *adev);static void piix_set_dmamode (struct ata_port *ap,struct ata_device *adev);
@@ -233,7 +233,7 @@ static const struct ata_port_operations .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, - .phy_reset = piix_sata_phy_reset, + .probe_reset = piix_sata_probe_reset, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start,
@@ -270,8 +270,8 @@ static struct ata_port_info piix_port_in/* ich5_sata */ { .sht = &piix_sht, - .host_flags =ATA_FLAG_SATA |ATA_FLAG_SRST | - PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR, + .host_flags =ATA_FLAG_SATA |PIIX_FLAG_COMBINED | + PIIX_FLAG_CHECKINTR, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */
@@ -295,9 +295,8 @@ static struct ata_port_info piix_port_in/* ich6_sata */ { .sht = &piix_sht, - .host_flags =ATA_FLAG_SATA |ATA_FLAG_SRST | -PIIX_FLAG_COMBINED |PIIX_FLAG_CHECKINTR | - ATA_FLAG_SLAVE_POSS, + .host_flags =ATA_FLAG_SATA |PIIX_FLAG_COMBINED | + PIIX_FLAG_CHECKINTR | ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */
@@ -307,9 +306,9 @@ static struct ata_port_info piix_port_in/* ich6_sata_ahci */ { .sht = &piix_sht, - .host_flags =ATA_FLAG_SATA |ATA_FLAG_SRST | -PIIX_FLAG_COMBINED |PIIX_FLAG_CHECKINTR | - ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI, + .host_flags =ATA_FLAG_SATA |PIIX_FLAG_COMBINED | +PIIX_FLAG_CHECKINTR |ATA_FLAG_SLAVE_POSS | + PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */
@@ -451,28 +450,28 @@ static int piix_sata_probe (struct ata_p }/** -* piix_sata_phy_reset - Probe specified port on SATA host controller -* @ap: Port to probe +* piix_sata_probe_reset - Perform reset on SATA port and classify +* @ap: Port to reset +* @classes: Resulting classes of attached devices * -* Probe SATA phy. +* Reset SATA phy and classify attached devices. * * LOCKING: * None (inherited from caller). */ - -static void piix_sata_phy_reset (struct ata_port *ap) +static int piix_sata_probe_reset (struct ata_port *ap,unsigned int *classes) { +int i; +if (!piix_sata_probe (ap)) { -ata_port_disable (ap); +for (i =0 ; i <ATA_MAX_DEVICES ; i++) + classes[i] =ATA_DEV_NONE ;printk (KERN_INFO "ata%u: SATA port has no device.\n" , ap->id); -return ; +return 0 ; } - ap->cbl =ATA_CBL_SATA ; - -ata_port_probe (ap); - -ata_bus_reset (ap); +return ata_drive_probe_reset (ap, ata_std_softreset,NULL , + ata_std_postreset, classes); }/**
Signature · 1 line
1.1.3
PATCH 11/12 ahci: convert to new reset mechanism
In reply to Tejun HeoConvert ahci ->phy_reset to new reset mechanism.
---
drivers/scsi/ahci.c | 46 +++++++++++++++++++++++++++++----------------- 1 files changed, 29 insertions(+), 17 deletions(-)
73d592b3ebb6520d3f87b1cfcd94c323be2d8889
drivers/scsi/ahci.c +29 -17
@@ -190,7 +190,7 @@ static void ahci_scr_write (struct ata_pstatic int ahci_init_one (struct pci_dev *pdev,const struct pci_device_id *ent);static unsigned int ahci_qc_issue (struct ata_queued_cmd *qc);static irqreturn_t ahci_interrupt (int irq,void *dev_instance,struct pt_regs *regs); -static void ahci_phy_reset (struct ata_port *ap); +static int ahci_probe_reset (struct ata_port *ap,unsigned int *classes);static void ahci_irq_clear (struct ata_port *ap);static void ahci_eng_timeout (struct ata_port *ap);static int ahci_port_start (struct ata_port *ap);
@@ -229,7 +229,7 @@ static const struct ata_port_operations .tf_read = ahci_tf_read, - .phy_reset = ahci_phy_reset, + .probe_reset = ahci_probe_reset, .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue,
@@ -251,8 +251,7 @@ static const struct ata_port_info ahci_p { .sht = &ahci_sht, .host_flags =ATA_FLAG_SATA |ATA_FLAG_NO_LEGACY | -ATA_FLAG_SATA_RESET |ATA_FLAG_MMIO | - ATA_FLAG_PIO_DMA, + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &ahci_ops,
@@ -511,28 +510,35 @@ static inline void ahci_fill_cmd_slot(st pp->cmd_slot[0 ].tbl_addr_hi =cpu_to_le32 ((pp->cmd_tbl_dma >>16 ) >>16 ); } -static void ahci_phy_reset (struct ata_port *ap) +static int ahci_hardreset (struct ata_port *ap,int verbose,unsigned int *class) { -void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; -struct ata_device *dev = &ap->device[0 ]; -u32 new_tmp, tmp; +int rc; + +DPRINTK ("ENTER\n" );ahci_stop_engine (ap); -__sata_phy_reset (ap); + rc =sata_std_hardreset (ap, verbose, class);ahci_start_engine (ap); -if (ap->flags &ATA_FLAG_PORT_DISABLED ) -return ; +if (rc ==0 ) + *class =ahci_dev_classify (ap); +if (*class ==ATA_DEV_UNKNOWN ) + *class =ATA_DEV_NONE ; - dev->class =ahci_dev_classify (ap); -if (!ata_dev_present (dev)) { -ata_port_disable (ap); -return ; - } +DPRINTK ("EXIT, rc=%d, class=%u\n" , rc, *class); +return rc; +} + +static void ahci_postreset (struct ata_port *ap,unsigned int *class) +{ +void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; +u32 new_tmp, tmp; + +ata_std_postreset (ap, class);/* Make sure port's ATAPI bit is set appropriately */ new_tmp = tmp =readl (port_mmio +PORT_CMD ); -if (dev->class ==ATA_DEV_ATAPI ) +if (*class ==ATA_DEV_ATAPI ) new_tmp |=PORT_CMD_ATAPI ;else new_tmp &= ~PORT_CMD_ATAPI ;
@@ -542,6 +548,12 @@ static void ahci_phy_reset(struct ata_po } } +static int ahci_probe_reset (struct ata_port *ap,unsigned int *classes) +{ +return ata_drive_probe_reset (ap,NULL , ahci_hardreset, + ahci_postreset, classes); +} +static u8 ahci_check_status (struct ata_port *ap) {void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
Signature · 1 line
1.1.3
PATCH 12/12 ahci: add softreset
In reply to Tejun HeoNow that libata is smart enought to handle both soft and hard resets, add softreset method.
---
drivers/scsi/ahci.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 133 insertions(+), 1 deletions(-)
8796cd07b5183339240083c14714700a46821ae7
drivers/scsi/ahci.c +133 -1
@@ -510,6 +510,138 @@ static inline void ahci_fill_cmd_slot(st pp->cmd_slot[0 ].tbl_addr_hi =cpu_to_le32 ((pp->cmd_tbl_dma >>16 ) >>16 ); } +static int ahci_wait_for_bit (void __iomem *reg,u32 mask,u32 val, +unsigned long interval_msec, +unsigned long timeout_msec) +{ +unsigned long timeout; +u32 tmp; + + timeout = jiffies + (timeout_msec *HZ ) /1000 ; +do { + tmp =readl (reg); +if ((tmp & mask) != val) +return 0 ; +msleep (interval_msec); + }while (time_before (jiffies, timeout)); + +return -1 ; +} + +static int ahci_softreset (struct ata_port *ap,int verbose,unsigned int *class) +{ +struct ahci_host_priv *hpriv = ap->host_set->private_data; +struct ahci_port_priv *pp = ap->private_data; +void __iomem *mmio = ap->host_set->mmio_base; +void __iomem *port_mmio =ahci_port_base (mmio, ap->port_no); +const u32 cmd_fis_len =5 ;/* five dwords */ +const char *reason =NULL ; +struct ata_taskfile tf; +u8 *fis; +int rc; + +DPRINTK ("ENTER\n" ); + +/* prepare for SRST (AHCI-1.1 10.4.1) */ + rc =ahci_stop_engine (ap); +if (rc) { + reason ="failed to stop engine" ; + goto fail_restart; + } + +/* check BUSY/DRQ, perform Command List Override if necessary */ +ahci_tf_read (ap, &tf); +if (tf.command & (ATA_BUSY |ATA_DRQ )) { +u32 tmp; + +if (!(hpriv->cap &HOST_CAP_CLO )) { + rc = -EIO ; + reason ="port busy but no CLO" ; + goto fail_restart; + } + + tmp =readl (port_mmio +PORT_CMD ); + tmp |=PORT_CMD_CLO ; +writel (tmp, port_mmio +PORT_CMD ); +readl (port_mmio +PORT_CMD );/* flush */ + +if (ahci_wait_for_bit (port_mmio +PORT_CMD , +PORT_CMD_CLO ,PORT_CMD_CLO ,1 ,500 )) { + rc = -EIO ; + reason ="CLO failed" ; + goto fail_restart; + } + } + +/* restart engine */ +ahci_start_engine (ap); + +ata_tf_init (ap, &tf,0 ); + fis = pp->cmd_tbl; + +/* issue the first D2H Register FIS */ +ahci_fill_cmd_slot (ap, 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 */ + +writel (1 , port_mmio +PORT_CMD_ISSUE ); +readl (port_mmio +PORT_CMD_ISSUE );/* flush */ + +if (ahci_wait_for_bit (port_mmio +PORT_CMD_ISSUE ,0x1 ,0x1 ,1 ,500 )) { + rc = -EIO ; + reason ="1st FIS failed" ; + goto fail; + } + +/* spec says at least 5us, but be generous and sleep for 1ms */ +msleep (1 ); + +/* issue the second D2H Register FIS */ +ahci_fill_cmd_slot (ap, cmd_fis_len); + + tf.ctl &= ~ATA_SRST ; +ata_tf_to_fis (&tf, fis,0 ); + fis[1 ] &= ~(1 <<7 );/* turn off Command FIS bit */ + +writel (1 , port_mmio +PORT_CMD_ISSUE ); +readl (port_mmio +PORT_CMD_ISSUE );/* flush */ + +/* spec mandates ">= 2ms" before checking status. +* We wait 150ms, because that was the magic delay used for +* ATAPI devices in Hale Landis's ATADRVR, for the period of time +* between when the ATA command register is written, and then +* status is checked. Because waiting for "a while" before +* checking status is fine, post SRST, we perform this magic +* delay here as well. +*/ +msleep (150 ); + + *class =ATA_DEV_NONE ; +if (sata_dev_present (ap)) { +if (ata_busy_sleep (ap,ATA_TMOUT_BOOT_QUICK ,ATA_TMOUT_BOOT )) { + rc = -EIO ; + reason ="device not ready" ; + goto fail; + } + *class =ahci_dev_classify (ap); + } + +DPRINTK ("EXIT, class=%u\n" , *class); +return 0 ; + + fail_restart: +ahci_start_engine (ap); + fail: +if (verbose) +printk (KERN_ERR "ata%u: softreset failed (%s)\n" , + ap->id, reason); +else +DPRINTK ("EXIT, rc=%d reason=\"%s\"\n" , rc, reason); +return rc; +} +static int ahci_hardreset (struct ata_port *ap,int verbose,unsigned int *class) {int rc;
@@ -550,7 +682,7 @@ static void ahci_postreset(struct ata_postatic int ahci_probe_reset (struct ata_port *ap,unsigned int *classes) { -return ata_drive_probe_reset (ap,NULL , ahci_hardreset, +return ata_drive_probe_reset (ap, ahci_softreset, ahci_hardreset, ahci_postreset, classes); }
Signature · 1 line
1.1.3