tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

disable ATA power management for PCMCIA/CF cards?



Reading PR kern/40531 I tried myself and found that the wd controller
within the CF card somehow goes mad after the "standby" command -
both status and error register are read as 0xff.
(easily seen with "options ATADEBUG"; I've tried with an old
IBM microdrive and 2 different silicon chips)
There might be a bug in the "wdc" driver which triggers this, but
the PR is reported against NetBSD-5 and unless someone who understands
the details is going to investigate it might be easier to avoid the
situation.
(It might be helpful to be in possession of the relevant PCMCIA
or Compactflashassociation specs, but I'm not.)
So I stumbled over a PCMCIA CIS bit called "auto power control"
in some chip description which says that the power commands
"are not needed" which one could interpret as "don't dare to try".
The appended patch passes this bit down to the "wd" driver
and keeps it from doing the "standby" command to the disk.
What do you think?

best regards
Matthias




-------------------------------------------------------------------
-------------------------------------------------------------------
Forschungszentrum Juelich GmbH
52425 Juelich

Sitz der Gesellschaft: Juelich
Eingetragen im Handelsregister des Amtsgerichts Dueren Nr. HR B 3498
Vorsitzende des Aufsichtsrats: MinDir'in Baerbel Brumme-Bothe
Geschaeftsfuehrung: Prof. Dr. Achim Bachem (Vorsitzender),
Dr. Ulrich Krafft (stellv. Vorsitzender), Prof. Dr. Harald Bolt,
Dr. Sebastian M. Schmidt
-------------------------------------------------------------------
-------------------------------------------------------------------
#
# old_revision [884ce8c5452fc4dfbe943834a593e6de60e97b28]
#
# patch "sys/dev/ata/ata.c"
#  from [dd8644460078dbd431a58b8102efbb3b854209bd]
#    to [aec2faabd33948006904fe36dfd8e950058bd6b7]
# 
# patch "sys/dev/ata/atavar.h"
#  from [9f9a1e1ea4930ccc1da501038c95f05c1e220170]
#    to [ddda3dd6830b71057af8a0c81a32306fe02a4112]
# 
# patch "sys/dev/ata/wd.c"
#  from [e3585309ef6464d47751fccb6e89f2bc201e0d9c]
#    to [f55683e1f646695f9935ed0422c1bb351a769d0d]
# 
# patch "sys/dev/ata/wdvar.h"
#  from [bcc7db43ac918b9690d8d380e724b55c5e0a951f]
#    to [46d6d31041bbb3636b251f144c654d4ed1cf2699]
# 
# patch "sys/dev/pcmcia/pcmcia_cis.c"
#  from [2af8ff2acc47e78ef24df4292bb6de967a63e7de]
#    to [f125734d1f0930d07179bce1ddf381af81e1193d]
# 
# patch "sys/dev/pcmcia/pcmciareg.h"
#  from [4f7f65b984cbd5d0947bb1923e1b5750f8ab30b5]
#    to [fd1ba0afe8e9562c905dfbb6d2e47f388dc097df]
# 
# patch "sys/dev/pcmcia/pcmciavar.h"
#  from [50bfaf52a7587e5f73cc022541902e9455e4c6af]
#    to [a982f9ca9901b44228385fd0b76cf424941ae414]
# 
# patch "sys/dev/pcmcia/wdc_pcmcia.c"
#  from [820f9a85fbec708ffba3879400993312b699782b]
#    to [d8d6e772934fe4a4858bb2f3d3e459d241bbc30f]
#
============================================================
--- sys/dev/ata/ata.c   dd8644460078dbd431a58b8102efbb3b854209bd
+++ sys/dev/ata/ata.c   aec2faabd33948006904fe36dfd8e950058bd6b7
@@ -293,6 +293,7 @@ atabusconfig_thread(void *arg)
                adev.adev_channel = chp->ch_channel;
                adev.adev_openings = 1;
                adev.adev_drv_data = &chp->ch_drive[i];
+               adev.adev_nopm = chp->ch_nopm;
                chp->ata_drives[i] = config_found_ia(atabus_sc->sc_dev,
                    "ata_hl", &adev, ataprint);
                if (chp->ata_drives[i] != NULL)
============================================================
--- sys/dev/ata/atavar.h        9f9a1e1ea4930ccc1da501038c95f05c1e220170
+++ sys/dev/ata/atavar.h        ddda3dd6830b71057af8a0c81a32306fe02a4112
@@ -323,6 +323,8 @@ struct ata_device {
        int adev_channel;
        int adev_openings;
        struct ata_drive_datas *adev_drv_data;
+       /* power management (PCMCIA/CF restriction) */
+       int adev_nopm;
 };
 
 /*
@@ -348,6 +350,9 @@ struct ata_channel {
        /* for the reset callback */
        int ch_reset_flags;
 
+       /* power management (PCMCIA/CF restriction) */
+       int ch_nopm;
+
        /* per-drive info */
        int ch_ndrive;
        struct ata_drive_datas ch_drive[ATA_MAXDRIVES];
============================================================
--- sys/dev/ata/wd.c    e3585309ef6464d47751fccb6e89f2bc201e0d9c
+++ sys/dev/ata/wd.c    f55683e1f646695f9935ed0422c1bb351a769d0d
@@ -309,6 +309,7 @@ wdattach(struct device *parent, struct d
        wd->atabus = adev->adev_bustype;
        wd->openings = adev->adev_openings;
        wd->drvp = adev->adev_drv_data;
+       wd->nopm = adev->adev_nopm;
 
        wd->drvp->drv_done = wddone;
        wd->drvp->drv_softc = wd->sc_dev;
@@ -1876,6 +1877,9 @@ wd_standby(struct wd_softc *wd, int flag
 {
        struct ata_command ata_c;
 
+       if (wd->nopm)
+               return 0;
+
        memset(&ata_c, 0, sizeof(struct ata_command));
        ata_c.r_command = WDCC_STANDBY_IMMED;
        ata_c.r_st_bmask = WDCS_DRDY;
============================================================
--- sys/dev/ata/wdvar.h bcc7db43ac918b9690d8d380e724b55c5e0a951f
+++ sys/dev/ata/wdvar.h 46d6d31041bbb3636b251f144c654d4ed1cf2699
@@ -73,6 +73,9 @@ struct wd_softc {
 #if NRND > 0
        rndsource_element_t     rnd_source;
 #endif
+
+       /* PCMCIA/CF restriction */
+       int nopm;
 };
 
 #define sc_drive sc_wdc_bio.drive
============================================================
--- sys/dev/pcmcia/pcmcia_cis.c 2af8ff2acc47e78ef24df4292bb6de967a63e7de
+++ sys/dev/pcmcia/pcmcia_cis.c f125734d1f0930d07179bce1ddf381af81e1193d
@@ -968,6 +968,15 @@ decode_funce(struct pcmcia_tuple *tuple,
                        pf->pf_funce_disk_interface
                            = pcmcia_tuple_read_1(tuple, 1);
                }
+               if (type == PCMCIA_TPLFE_TYPE_DISK_ATA) {
+                       if (tuple->length < 3)
+                               break;
+                       pf->pf_funce_disk_ata_valid = 1;
+                       pf->pf_funce_disk_ata1
+                           = pcmcia_tuple_read_1(tuple, 1);
+                       pf->pf_funce_disk_ata2
+                           = pcmcia_tuple_read_1(tuple, 2);
+               }
                break;
        case PCMCIA_FUNCTION_NETWORK:
                if (type == PCMCIA_TPLFE_TYPE_LAN_NID) {
============================================================
--- sys/dev/pcmcia/pcmciareg.h  4f7f65b984cbd5d0947bb1923e1b5750f8ab30b5
+++ sys/dev/pcmcia/pcmciareg.h  fd1ba0afe8e9562c905dfbb6d2e47f388dc097df
@@ -179,6 +179,7 @@
 #define        PCMCIA_TPLFE_TYPE_LAN_CONN                      0x05
 #define        PCMCIA_TPLFE_TYPE_DISK_DEVICE_INTERFACE         0x01
 #define        PCMCIA_TPLFE_DDI_PCCARD_ATA                             0x01
+#define PCMCIA_TPLFE_TYPE_DISK_ATA                     0x02
 #define        PCMCIA_CISTPL_END                       0xFF
 
 /* Layer 2 Data Recording Format Tuples */
============================================================
--- sys/dev/pcmcia/pcmciavar.h  50bfaf52a7587e5f73cc022541902e9455e4c6af
+++ sys/dev/pcmcia/pcmciavar.h  a982f9ca9901b44228385fd0b76cf424941ae414
@@ -157,6 +157,8 @@ struct pcmcia_function {
 #define pf_funce_disk_interface pf_funce.pfv_disk.pfd_interface
 #define pf_funce_lan_nid pf_funce.pfv_lan.pfl_nid
 #define pf_funce_lan_nidlen pf_funce.pfv_lan.pfl_nidlen
+       int pf_funce_disk_ata_valid;
+       int pf_funce_disk_ata1, pf_funce_disk_ata2;
 };
 
 /* pf_flags */
============================================================
--- sys/dev/pcmcia/wdc_pcmcia.c 820f9a85fbec708ffba3879400993312b699782b
+++ sys/dev/pcmcia/wdc_pcmcia.c d8d6e772934fe4a4858bb2f3d3e459d241bbc30f
@@ -290,6 +290,13 @@ wdc_pcmcia_attach(device_t parent, devic
                sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA32;
        }
 
+       if (pa->pf->pf_funce_disk_ata_valid) {
+               printf("ata parms: %x/%x\n", pa->pf->pf_funce_disk_ata1,
+                      pa->pf->pf_funce_disk_ata2);
+               if (pa->pf->pf_funce_disk_ata2 & 0x08)
+                       sc->ata_channel.ch_nopm = 1;
+       }
+
        sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
        sc->wdc_chanlist[0] = &sc->ata_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanlist;


Home | Main Index | Thread Index | Old Index