libata: add @disable_on_err to ata_set_mode()
PATCH 1/1 libata: add @disable_on_err to ata_set_mode()
Hello.
This patchset adds @disable_on_err to ata_set_mode(). If zero, ata_set_mode() returns error code on failure; otherwise, only the failing devices get disabled. Note that the approach is slightly different here because ATA xfer mode configuration is port-wide, so ata_set_mode() acts as the final decision maker regarding device offlining advised by @disable_on_err.
This patchset is against
[1] the current upstream
+ [2] implement-per-dev-xfermask patchset
Thanks.
--
tejun
[1] fb21f0d0ec7e31cc814165e1a9d2662d9c9dd980
[2] http://article.gmane.org/gmane.linux.ide/8705
PATCH 1/4 libata: implement ata_dev_disable()
This patch implements ata_dev_disable() which prints a warning message and takes @dev offline. Currently, this is done by explicitly incrementing dev->class with case-by-case warning messages. Giving user clear indication when libata gives up will be more important as libata will be doing more retries.
---
drivers/scsi/libata-core.c | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-)
b0e8e3c30b12f3adf35a7047031c9a6e8258e289
drivers/scsi/libata-core.c +9 -0
@@ -394,6 +394,15 @@ static const char *ata_mode_string(unsigreturn "<n/a>" ; } +static void ata_dev_disable (struct ata_port *ap,struct ata_device *dev) +{ +if (ata_dev_present (dev)) { +printk (KERN_WARNING "ata%u: dev %u disabled\n" , + ap->id, dev->devno); + dev->class++; + } +} +/** * ata_pio_devchk - PATA device presence detection * @ap: ATA channel to examine
Signature · 1 line
1.2.4
PATCH 2/4 libata: use ata_dev_disable() in ata_bus_probe()
In reply to Tejun HeoWe may or may not disable a device after ata_dev_configure() fails. Kill 'not supported, ignoring' message in ata_dev_configure() and use ata_dev_disable() in ata_bus_probe().
---
drivers/scsi/libata-core.c | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-)
54e2f80b5190b3f94779c06cbfe722b4bfe9204a
drivers/scsi/libata-core.c +1 -3
@@ -1373,8 +1373,6 @@ static int ata_dev_configure(struct ata_return 0 ; err_out_nosup: -printk (KERN_WARNING "ata%u: dev %u not supported, ignoring\n" , - ap->id, dev->devno);DPRINTK ("EXIT, err\n" );return rc; }
@@ -1443,7 +1441,7 @@ static int ata_bus_probe(struct ata_port }if (ata_dev_configure (ap, dev,1 )) { - dev->class++;/* disable device */ +ata_dev_disable (ap, dev);continue ; }
Signature · 1 line
1.2.4
PATCH 3/4 libata: make ata_set_mode() responsible for failure handling
In reply to Tejun HeoMake ata_set_mode() responsible for determining whether to take port or device offline on failure. ata_dev_set_xfermode() and ata_dev_set_mode() indicate error to the caller instead of disabling port directly on failure. Also, for consistency, ata_dev_present() check is done in ata_set_mode() instead of ata_dev_set_mode().
---
drivers/scsi/libata-core.c | 56 ++++++++++++++++++++++++++++---------------- 1 files changed, 36 insertions(+), 20 deletions(-)
07934616ecb83d7bac2adfe9eb32f5173feb32ff
drivers/scsi/libata-core.c +36 -20
@@ -64,7 +64,8 @@static unsigned int ata_dev_init_params (struct ata_port *ap,struct ata_device *dev);static void ata_set_mode (struct ata_port *ap); -static void ata_dev_set_xfermode (struct ata_port *ap,struct ata_device *dev); +static unsigned int ata_dev_set_xfermode (struct ata_port *ap, +struct ata_device *dev);static void ata_dev_xfermask (struct ata_port *ap,struct ata_device *dev);static unsigned int ata_unique_id =1 ;
@@ -1754,20 +1755,28 @@ int ata_timing_compute(struct ata_devicereturn 0 ; } -static void ata_dev_set_mode (struct ata_port *ap,struct ata_device *dev) +static int ata_dev_set_mode (struct ata_port *ap,struct ata_device *dev) { -if (!ata_dev_present (dev) || (ap->flags &ATA_FLAG_PORT_DISABLED )) -return ; +unsigned int err_mask; +int rc;if (dev->xfer_shift ==ATA_SHIFT_PIO ) dev->flags |=ATA_DFLAG_PIO ; -ata_dev_set_xfermode (ap, dev); + err_mask =ata_dev_set_xfermode (ap, dev); +if (err_mask) { +printk (KERN_ERR +"ata%u: failed to set xfermode (err_mask=0x%x)\n" , + ap->id, err_mask); +return -EIO ; + } -if (ata_dev_revalidate (ap, dev,0 )) { -printk (KERN_ERR "ata%u: failed to revalidate after set " -"xfermode, disabled\n" , ap->id); -ata_port_disable (ap); + rc =ata_dev_revalidate (ap, dev,0 ); +if (rc) { +printk (KERN_ERR +"ata%u: failed to revalidate after set xfermode\n" , + ap->id); +return rc; } DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
@@ -1776,6 +1785,7 @@ static void ata_dev_set_mode(struct ata_printk (KERN_INFO "ata%u: dev %u configured for %s\n" , ap->id, dev->devno,ata_mode_string (ata_xfer_mode2mask (dev->xfer_mode))); +return 0 ; }static int ata_host_set_pio (struct ata_port *ap)
@@ -1859,11 +1869,15 @@ static void ata_set_mode(struct ata_portata_host_set_dma (ap);/* step 4: update devices' xfer mode */ -for (i =0 ; i <ATA_MAX_DEVICES ; i++) -ata_dev_set_mode (ap, &ap->device[i]); +for (i =0 ; i <ATA_MAX_DEVICES ; i++) { +struct ata_device *dev = &ap->device[i]; -if (ap->flags &ATA_FLAG_PORT_DISABLED ) -return ; +if (!ata_dev_present (dev)) +continue ; + +if (ata_dev_set_mode (ap, dev)) + goto err_out; + }if (ap->ops->post_set_mode) ap->ops->post_set_mode (ap);
@@ -2702,11 +2716,16 @@ static void ata_dev_xfermask(struct ata_* * LOCKING: * PCI/etc. bus probe sem. +* +* RETURNS: +* 0 on success, AC_ERR_* mask otherwise. */ -static void ata_dev_set_xfermode (struct ata_port *ap,struct ata_device *dev) +static unsigned int ata_dev_set_xfermode (struct ata_port *ap, +struct ata_device *dev) {struct ata_taskfile tf; +unsigned int err_mask;/* set up set-features taskfile */ DPRINTK ("set features - xfer mode\n" );
@@ -2718,13 +2737,10 @@ static void ata_dev_set_xfermode(struct tf.protocol =ATA_PROT_NODATA ; tf.nsect = dev->xfer_mode; -if (ata_exec_internal (ap, dev, &tf,DMA_NONE ,NULL ,0 )) { -printk (KERN_ERR "ata%u: failed to set xfermode, disabled\n" , - ap->id); -ata_port_disable (ap); - } + err_mask =ata_exec_internal (ap, dev, &tf,DMA_NONE ,NULL ,0 ); -DPRINTK ("EXIT\n" ); +DPRINTK ("EXIT, err_mask=%x\n" , err_mask); +return err_mask; }/**
Signature · 1 line
1.2.4
Re: [PATCH 3/4] libata: make ata_set_mode() responsible for failure handling
Quoted 29 lines · Tejun Heo
Make
ata_set_mode()responsible for determining whether to take port or device offline on failure.ata_dev_set_xfermode()andata_dev_set_mode()indicate error to the caller instead of disabling port directly on failure. Also, for consistency,ata_dev_present()check is done inata_set_mode()instead ofata_dev_set_mode().Signed-off-by Tejun Heo <[email protected]>---
drivers/scsi/libata-core.c | 56 ++++++++++++++++++++++++++++---------------- 1 files changed, 36 insertions(+), 20 deletions(-)
07934616ecb83d7bac2adfe9eb32f5173feb32ffdrivers/scsi/libata-core.c +2
-1@@ -64,7 +64,8 @@static unsigned int ata_dev_init_params (struct ata_port *ap,struct ata_device *dev);static void ata_set_mode (struct ata_port *ap); -static void ata_dev_set_xfermode (struct ata_port *ap,struct ata_device *dev); +static unsigned int ata_dev_set_xfermode (struct ata_port *ap, +struct ata_device *dev);static void ata_dev_xfermask (struct ata_port *ap,struct ata_device *dev);static unsigned int ata_unique_id =1 ;
drivers/scsi/libata-core.c int ata_timing_compute(struct ata_device · line 1756
Quoted 2 lines
drivers/scsi/libata-core.c +0
-0@@ -1754,20 +1755,28 @@ int ata_timing_compute(struct ata_devicereturn 0 ; }
ACK 1-4 in this patchset, but dropping due to dropped patches in previous patchset.
I have the following concern with this patch (#3) however:
drivers/scsi/libata-core.c int ata_timing_compute(struct ata_device · line 1760
Quoted 5 lines
drivers/scsi/libata-core.c +1
-3-static void ata_dev_set_mode (struct ata_port *ap,struct ata_device *dev) +static int ata_dev_set_mode (struct ata_port *ap,struct ata_device *dev) { -if (!ata_dev_present (dev) || (ap->flags &ATA_FLAG_PORT_DISABLED )) -return ;
I think you drop too many ATA_FLAG_PORT_DISABLED tests in this patch, leading the code to potentially miss a previously-flagged PORT_DISABLED (perhaps by an LLDD).
Jeff
Re: [PATCH 3/4] libata: make ata_set_mode() responsible for failure handling
Quoted 13 lines · Jeff Garzik
I have the following concern with this patch (#3) however:
drivers/scsi/libata-core.c int ata_timing_compute(struct ata_device · line 1760
Quoted 5 lines
drivers/scsi/libata-core.c +1
-1-static void ata_dev_set_mode (struct ata_port *ap,struct ata_device *dev) +static int ata_dev_set_mode (struct ata_port *ap,struct ata_device *dev){
drivers/scsi/libata-core.c +0
-2-if (!ata_dev_present (dev) || (ap->flags &ATA_FLAG_PORT_DISABLED )) -return ;I think you drop too many
ATA_FLAG_PORT_DISABLEDtests in this patch, leading the code to potentially miss a previously-flaggedPORT_DISABLED(perhaps by an LLDD).
Hmmm... the plan is to disallow LLDD's take ports or devices offline from low level callbacks. They should just let upper layer know by returning failure code.
Currently, during probing, the only place where disabling a port is allowed is ->phy_reset (for compatibility), which ata_bus_probe() interprets as no active device and reenables the port. Later, ->error_handler() would have that power too but I don't think any other callback should be allowed to do that. Also, no current in-kernel LLDD does that during probing process.
If we're gonna allow some callbacks to disable ports or devices. I think we need to come up with clear rules such that checks can be performed exactly where needed.
Thanks.
Signature · 1 line
tejun
Re: [PATCH 3/4] libata: make ata_set_mode() responsible for failure handling
Quoted 15 lines · Tejun Heo
Quoted 11 lines · Jeff Garzik
I have the following concern with this patch (#3) however:
drivers/scsi/libata-core.c int ata_timing_compute(struct ata_device · line 1760
Quoted 5 lines
drivers/scsi/libata-core.c +1
-1-static void ata_dev_set_mode (struct ata_port *ap,struct ata_device *dev) +static int ata_dev_set_mode (struct ata_port *ap,struct ata_device *dev){
drivers/scsi/libata-core.c +0
-2-if (!ata_dev_present (dev) || (ap->flags &ATA_FLAG_PORT_DISABLED )) -return ;I think you drop too many
ATA_FLAG_PORT_DISABLEDtests in this patch, leading the code to potentially miss a previously-flaggedPORT_DISABLED(perhaps by an LLDD).
Quoted 3 lines
Hmmm... the plan is to disallow LLDD's take ports or devices offline from low level callbacks. They should just let upper layer know by returning failure code.
Long term that plan is fine, but you still have to deal with the existing API one way or another. ata_port_disable() is called directly by a bunch of Alan's PATA drivers, and by ata_piix and sata_mv.
Thus you would either need to keep the PORT_DISABLED checks or convert the drivers in question to a better API.
So just check those ata_port_disable() cases...
Jeff
Re: [PATCH 3/4] libata: make ata_set_mode() responsible for failure handling
Quoted 23 lines · Jeff Garzik
Quoted 18 lines · Tejun Heo
Quoted 14 lines · Jeff Garzik
I have the following concern with this patch (#3) however:
drivers/scsi/libata-core.c int ata_timing_compute(struct ata_device · line 1760
Quoted 6 lines
-static void
ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev)
+static intata_dev_set_mode(struct ata_port *ap, struct ata_device *dev){drivers/scsi/libata-core.c +0
-2-if (!ata_dev_present (dev) || (ap->flags &ATA_FLAG_PORT_DISABLED )) -return ;I think you drop too many
ATA_FLAG_PORT_DISABLEDtests in this patch, leading the code to potentially miss a previously-flaggedPORT_DISABLED(perhaps by an LLDD).Quoted 3 lines
Hmmm... the plan is to disallow LLDD's take ports or devices offline from low level callbacks. They should just let upper layer know by returning failure code.
Quoted 9 lines
Long term that plan is fine, but you still have to deal with the existing API one way or another.
ata_port_disable()is called directly by a bunch of Alan's PATA drivers, and byata_piixandsata_mv.Thus you would either need to keep the
PORT_DISABLEDchecks or convert the drivers in question to a better API.So just check those
ata_port_disable()cases...
AFAICS, ata_piix doesn't call ata_port_disable() directly, but sata_mv() does, through mv_host_intr() -> mv_err_intr() ->mv_stop_and_reset() -> __mv_phy_reset(). I'll check the code path such that disabled ports are handled properly. Thanks for pointing out.
Signature · 1 line
tejun
Re: [PATCH 3/4] libata: make ata_set_mode() responsible for failure handling
Quoted 36 lines · Tejun Heo
Quoted 24 lines · Jeff Garzik
Quoted 21 lines · Tejun Heo
Quoted 4 lines · Jeff Garzik
I have the following concern with this patch (#3) however:
Quoted 9 lines
drivers/scsi/libata-core.c int ata_timing_compute(struct ata_device · line 1760
Quoted 6 lines
-static void
ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev)
+static intata_dev_set_mode(struct ata_port *ap, struct ata_device *dev){drivers/scsi/libata-core.c +0
-2-if (!ata_dev_present (dev) || (ap->flags &ATA_FLAG_PORT_DISABLED )) -return ;I think you drop too many
ATA_FLAG_PORT_DISABLEDtests in this patch, leading the code to potentially miss a previously-flaggedPORT_DISABLED(perhaps by an LLDD).Hmmm... the plan is to disallow LLDD's take ports or devices offline
from low level callbacks. They should just let upper layer know by
Quoted 8 lines
Quoted 1 line
returning failure code.
Long term that plan is fine, but you still have to deal with the existing API one way or another.
ata_port_disable()is called directly by a bunch of Alan's PATA drivers, and byata_piixandsata_mv.Thus you would either need to keep the
PORT_DISABLEDchecks or convert the drivers in question to a better API.So just check those
ata_port_disable()cases...
Quoted 5 lines
AFAICS,
ata_piixdoesn't callata_port_disable()directly, butsata_mv()does, throughmv_host_intr()->mv_err_intr()->mv_stop_and_reset() ->__mv_phy_reset(). I'll check the code path such that disabled ports are handled properly. Thanks for pointing out.
Yeah, sorry, for ata_piix I was looking at vanilla linux-2.6.git rather than libata-dev.git#upstream... :)
Jeff
PATCH 4/4 libata: add @disable_on_err argument to ata_set_mode()
In reply to Tejun Heoata_set_mode() used to disable whole port on failure. This patch adds @disable_on_err which makes ata_set_mode() disable failing devices when non-zero, and simply return when zero. Due to the port-wide characteristic of ATA xfer mode configuration, ata_mode_set() is the final place to determine device offlining; thus, the @disable_on_err mechanism to tell it which action to take on failure.
Now port is disabled only if all devices on the port is disabled. This behavior change is intentional.
---
drivers/scsi/libata-core.c | 61 +++++++++++++++++++++++++++----------------- 1 files changed, 37 insertions(+), 24 deletions(-)
4eb4d225ccfc6b5401b338c92c142f30b761db2e
drivers/scsi/libata-core.c +37 -24
@@ -63,7 +63,7 @@static unsigned int ata_dev_init_params (struct ata_port *ap,struct ata_device *dev); -static void ata_set_mode (struct ata_port *ap); +static int ata_set_mode (struct ata_port *ap,int disable_on_err);static unsigned int ata_dev_set_xfermode (struct ata_port *ap,struct ata_device *dev);static void ata_dev_xfermask (struct ata_port *ap,struct ata_device *dev);
@@ -1449,16 +1449,16 @@ static int ata_bus_probe(struct ata_port found =1 ; } -if (!found) - goto err_out_disable; - -ata_set_mode (ap); -if (ap->flags &ATA_FLAG_PORT_DISABLED ) - goto err_out_disable; - -return 0 ; +/* configure transfer mode */ +if (found) { +ata_set_mode (ap,1 ); +for (i =0 ; i <ATA_MAX_DEVICES ; i++) +if (ata_dev_present (&ap->device[i])) +return 0 ; + } -err_out_disable: +/* no device present, disable port */ +ata_port_disable (ap); ap->ops->port_disable (ap);return -1 ; }
@@ -1788,7 +1788,7 @@ static int ata_dev_set_mode(struct ata_preturn 0 ; } -static int ata_host_set_pio (struct ata_port *ap) +static int ata_host_set_pio (struct ata_port *ap,int disable_on_err) {int i;
@@ -1799,8 +1799,13 @@ static int ata_host_set_pio(struct ata_pcontinue ;if (!dev->pio_mode) { -printk (KERN_WARNING "ata%u: no PIO support\n" , ap->id); -return -1 ; +printk (KERN_WARNING "ata%u: dev %u no PIO support\n" , + ap->id, dev->devno); +if (disable_on_err) { +ata_dev_disable (ap, dev); +continue ; + }else +return -EINVAL ; } dev->xfer_mode = dev->pio_mode;
@@ -1832,13 +1837,19 @@ static void ata_host_set_dma(struct ata_/** * ata_set_mode - Program timings and issue SET FEATURES - XFER * @ap: port on which timings will be programmed +* @disable_on_err: disable device on error * -* Set ATA device disk transfer mode (PIO3, UDMA6, etc.). +* Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If +* @disable_on_err is non-zero, devices which fail to configure +* are taken offline and this function always succeeds. * * LOCKING: * PCI/etc. bus probe sem. +* +* RETURNS: +* 0 on success, negative errno otherwise */ -static void ata_set_mode (struct ata_port *ap) +static int ata_set_mode (struct ata_port *ap,int disable_on_err) {int i, rc;
@@ -1861,9 +1872,9 @@ static void ata_set_mode(struct ata_port }/* step 2: always set host PIO timings */ - rc =ata_host_set_pio (ap); + rc =ata_host_set_pio (ap, disable_on_err);if (rc) - goto err_out; +return rc;/* step 3: set host DMA timings */ ata_host_set_dma (ap);
@@ -1875,17 +1886,19 @@ static void ata_set_mode(struct ata_portif (!ata_dev_present (dev))continue ; -if (ata_dev_set_mode (ap, dev)) - goto err_out; + rc =ata_dev_set_mode (ap, dev); +if (rc) { +if (disable_on_err) +ata_dev_disable (ap, dev); +else +return rc; + } }if (ap->ops->post_set_mode) ap->ops->post_set_mode (ap); -return ; - -err_out: -ata_port_disable (ap); +return 0 ; }/**
@@ -4526,7 +4539,7 @@ int ata_device_resume(struct ata_port *a {if (ap->flags &ATA_FLAG_SUSPENDED ) { ap->flags &= ~ATA_FLAG_SUSPENDED ; -ata_set_mode (ap); +ata_set_mode (ap,1 ); }if (!ata_dev_present (dev))return 0 ;
Signature · 1 line
1.2.4