]> err.no Git - linux-2.6/blobdiff - drivers/scsi/libata-core.c
[PATCH] libata-dev: add flush task to ata_exec_internal()
[linux-2.6] / drivers / scsi / libata-core.c
index 18418c82d6f6355fbefe1b828557faff88e0ab87..a28569d0081dfe6e052f63573e4147182c43dfe3 100644 (file)
@@ -65,16 +65,13 @@ 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_get_mode_mask(const struct ata_port *ap, int shift);
-static int fgb(u32 bitmap);
-static int ata_choose_xfer_mode(const struct ata_port *ap,
-                               u8 *xfer_mode_out,
-                               unsigned int *xfer_shift_out);
+static unsigned int ata_dev_xfermask(struct ata_port *ap,
+                                    struct ata_device *dev);
 
 static unsigned int ata_unique_id = 1;
 static struct workqueue_struct *ata_wq;
 
-int atapi_enabled = 0;
+int atapi_enabled = 1;
 module_param(atapi_enabled, int, 0444);
 MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
 
@@ -231,25 +228,108 @@ int ata_rwcmd_protocol(struct ata_queued_cmd *qc)
        return -1;
 }
 
-static const char * const xfer_mode_str[] = {
-       "PIO0",
-       "PIO1",
-       "PIO2",
-       "PIO3",
-       "PIO4",
-       "MWDMA0",
-       "MWDMA1",
-       "MWDMA2",
-       "UDMA/16",
-       "UDMA/25",
-       "UDMA/33",
-       "UDMA/44",
-       "UDMA/66",
-       "UDMA/100",
-       "UDMA/133",
-       "UDMA7",
+/**
+ *     ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask
+ *     @pio_mask: pio_mask
+ *     @mwdma_mask: mwdma_mask
+ *     @udma_mask: udma_mask
+ *
+ *     Pack @pio_mask, @mwdma_mask and @udma_mask into a single
+ *     unsigned int xfer_mask.
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     Packed xfer_mask.
+ */
+static unsigned int ata_pack_xfermask(unsigned int pio_mask,
+                                     unsigned int mwdma_mask,
+                                     unsigned int udma_mask)
+{
+       return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) |
+               ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) |
+               ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA);
+}
+
+static const struct ata_xfer_ent {
+       unsigned int shift, bits;
+       u8 base;
+} ata_xfer_tbl[] = {
+       { ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 },
+       { ATA_SHIFT_MWDMA, ATA_BITS_MWDMA, XFER_MW_DMA_0 },
+       { ATA_SHIFT_UDMA, ATA_BITS_UDMA, XFER_UDMA_0 },
+       { -1, },
 };
 
+/**
+ *     ata_xfer_mask2mode - Find matching XFER_* for the given xfer_mask
+ *     @xfer_mask: xfer_mask of interest
+ *
+ *     Return matching XFER_* value for @xfer_mask.  Only the highest
+ *     bit of @xfer_mask is considered.
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     Matching XFER_* value, 0 if no match found.
+ */
+static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
+{
+       int highbit = fls(xfer_mask) - 1;
+       const struct ata_xfer_ent *ent;
+
+       for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+               if (highbit >= ent->shift && highbit < ent->shift + ent->bits)
+                       return ent->base + highbit - ent->shift;
+       return 0;
+}
+
+/**
+ *     ata_xfer_mode2mask - Find matching xfer_mask for XFER_*
+ *     @xfer_mode: XFER_* of interest
+ *
+ *     Return matching xfer_mask for @xfer_mode.
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     Matching xfer_mask, 0 if no match found.
+ */
+static unsigned int ata_xfer_mode2mask(u8 xfer_mode)
+{
+       const struct ata_xfer_ent *ent;
+
+       for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+               if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
+                       return 1 << (ent->shift + xfer_mode - ent->base);
+       return 0;
+}
+
+/**
+ *     ata_xfer_mode2shift - Find matching xfer_shift for XFER_*
+ *     @xfer_mode: XFER_* of interest
+ *
+ *     Return matching xfer_shift for @xfer_mode.
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     Matching xfer_shift, -1 if no match found.
+ */
+static int ata_xfer_mode2shift(unsigned int xfer_mode)
+{
+       const struct ata_xfer_ent *ent;
+
+       for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+               if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
+                       return ent->shift;
+       return -1;
+}
+
 /**
  *     ata_mode_string - convert xfer_mask to string
  *     @xfer_mask: mask of bits supported; only highest bit counts.
@@ -264,9 +344,26 @@ static const char * const xfer_mode_str[] = {
  *     Constant C string representing highest speed listed in
  *     @mode_mask, or the constant C string "<n/a>".
  */
-
 static const char *ata_mode_string(unsigned int xfer_mask)
 {
+       static const char * const xfer_mode_str[] = {
+               "PIO0",
+               "PIO1",
+               "PIO2",
+               "PIO3",
+               "PIO4",
+               "MWDMA0",
+               "MWDMA1",
+               "MWDMA2",
+               "UDMA/16",
+               "UDMA/25",
+               "UDMA/33",
+               "UDMA/44",
+               "UDMA/66",
+               "UDMA/100",
+               "UDMA/133",
+               "UDMA7",
+       };
        int highbit;
 
        highbit = fls(xfer_mask) - 1;
@@ -682,33 +779,52 @@ static inline void ata_dump_id(const u16 *id)
                id[93]);
 }
 
-/*
- *     Compute the PIO modes available for this device. This is not as
- *     trivial as it seems if we must consider early devices correctly.
+/**
+ *     ata_id_xfermask - Compute xfermask from the given IDENTIFY data
+ *     @id: IDENTIFY data to compute xfer mask from
  *
- *     FIXME: pre IDE drive timing (do we care ?). 
+ *     Compute the xfermask for this device. This is not as trivial
+ *     as it seems if we must consider early devices correctly.
+ *
+ *     FIXME: pre IDE drive timing (do we care ?).
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     Computed xfermask
  */
-
-static unsigned int ata_pio_modes(const struct ata_device *adev)
+static unsigned int ata_id_xfermask(const u16 *id)
 {
-       u16 modes;
+       unsigned int pio_mask, mwdma_mask, udma_mask;
 
        /* Usual case. Word 53 indicates word 64 is valid */
-       if (adev->id[ATA_ID_FIELD_VALID] & (1 << 1)) {
-               modes = adev->id[ATA_ID_PIO_MODES] & 0x03;
-               modes <<= 3;
-               modes |= 0x7;
-               return modes;
+       if (id[ATA_ID_FIELD_VALID] & (1 << 1)) {
+               pio_mask = id[ATA_ID_PIO_MODES] & 0x03;
+               pio_mask <<= 3;
+               pio_mask |= 0x7;
+       } else {
+               /* If word 64 isn't valid then Word 51 high byte holds
+                * the PIO timing number for the maximum. Turn it into
+                * a mask.
+                */
+               pio_mask = (2 << (id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ;
+
+               /* But wait.. there's more. Design your standards by
+                * committee and you too can get a free iordy field to
+                * process. However its the speeds not the modes that
+                * are supported... Note drivers using the timing API
+                * will get this right anyway
+                */
        }
 
-       /* If word 64 isn't valid then Word 51 high byte holds the PIO timing
-          number for the maximum. Turn it into a mask and return it */
-       modes = (2 << ((adev->id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF)) - 1 ;
-       return modes;
-       /* But wait.. there's more. Design your standards by committee and
-          you too can get a free iordy field to process. However its the 
-          speeds not the modes that are supported... Note drivers using the
-          timing API will get this right anyway */
+       mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07;
+
+       udma_mask = 0;
+       if (id[ATA_ID_FIELD_VALID] & (1 << 2))
+               udma_mask = id[ATA_ID_UDMA_MODES] & 0xff;
+
+       return ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);
 }
 
 /**
@@ -846,6 +962,8 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
        spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
        if (!wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL)) {
+               ata_port_flush_task(ap);
+
                spin_lock_irqsave(&ap->host_set->lock, flags);
 
                /* We're racing with irq here.  If we lose, the
@@ -1004,12 +1122,6 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev,
 
        swap_buf_le16(id, ATA_ID_WORDS);
 
-       /* print device capabilities */
-       printk(KERN_DEBUG "ata%u: dev %u cfg "
-              "49:%04x 82:%04x 83:%04x 84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
-              ap->id, dev->devno,
-              id[49], id[82], id[83], id[84], id[85], id[86], id[87], id[88]);
-
        /* sanity check */
        if ((class == ATA_DEV_ATA) != ata_id_is_ata(id)) {
                rc = -EINVAL;
@@ -1077,7 +1189,8 @@ static inline u8 ata_dev_knobble(const struct ata_port *ap,
 static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
                             int print_info)
 {
-       unsigned long xfer_modes;
+       const u16 *id = dev->id;
+       unsigned int xfer_mask;
        int i, rc;
 
        if (!ata_dev_present(dev)) {
@@ -1088,6 +1201,13 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
 
        DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
 
+       /* print device capabilities */
+       if (print_info)
+               printk(KERN_DEBUG "ata%u: dev %u cfg 49:%04x 82:%04x 83:%04x "
+                      "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
+                      ap->id, dev->devno, id[49], id[82], id[83],
+                      id[84], id[85], id[86], id[87], id[88]);
+
        /* initialize to-be-configured parameters */
        dev->flags = 0;
        dev->max_sectors = 0;
@@ -1102,31 +1222,27 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
         */
 
        /* we require DMA support (bits 8 of word 49) */
-       if (!ata_id_has_dma(dev->id)) {
+       if (!ata_id_has_dma(id)) {
                printk(KERN_DEBUG "ata%u: no dma\n", ap->id);
                rc = -EINVAL;
                goto err_out_nosup;
        }
 
-       /* quick-n-dirty find max transfer mode; for printk only */
-       xfer_modes = dev->id[ATA_ID_UDMA_MODES];
-       if (!xfer_modes)
-               xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA;
-       if (!xfer_modes)
-               xfer_modes = ata_pio_modes(dev);
+       /* find max transfer mode; for printk only */
+       xfer_mask = ata_id_xfermask(id);
 
-       ata_dump_id(dev->id);
+       ata_dump_id(id);
 
        /* ATA-specific feature tests */
        if (dev->class == ATA_DEV_ATA) {
-               dev->n_sectors = ata_id_n_sectors(dev->id);
+               dev->n_sectors = ata_id_n_sectors(id);
 
-               if (ata_id_has_lba(dev->id)) {
+               if (ata_id_has_lba(id)) {
                        const char *lba_desc;
 
                        lba_desc = "LBA";
                        dev->flags |= ATA_DFLAG_LBA;
-                       if (ata_id_has_lba48(dev->id)) {
+                       if (ata_id_has_lba48(id)) {
                                dev->flags |= ATA_DFLAG_LBA48;
                                lba_desc = "LBA48";
                        }
@@ -1136,23 +1252,23 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
                                printk(KERN_INFO "ata%u: dev %u ATA-%d, "
                                       "max %s, %Lu sectors: %s\n",
                                       ap->id, dev->devno,
-                                      ata_id_major_version(dev->id),
-                                      ata_mode_string(xfer_modes),
+                                      ata_id_major_version(id),
+                                      ata_mode_string(xfer_mask),
                                       (unsigned long long)dev->n_sectors,
                                       lba_desc);
                } else {
                        /* CHS */
 
                        /* Default translation */
-                       dev->cylinders  = dev->id[1];
-                       dev->heads      = dev->id[3];
-                       dev->sectors    = dev->id[6];
+                       dev->cylinders  = id[1];
+                       dev->heads      = id[3];
+                       dev->sectors    = id[6];
 
-                       if (ata_id_current_chs_valid(dev->id)) {
+                       if (ata_id_current_chs_valid(id)) {
                                /* Current CHS translation is valid. */
-                               dev->cylinders = dev->id[54];
-                               dev->heads     = dev->id[55];
-                               dev->sectors   = dev->id[56];
+                               dev->cylinders = id[54];
+                               dev->heads     = id[55];
+                               dev->sectors   = id[56];
                        }
 
                        /* print device info to dmesg */
@@ -1160,8 +1276,8 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
                                printk(KERN_INFO "ata%u: dev %u ATA-%d, "
                                       "max %s, %Lu sectors: CHS %u/%u/%u\n",
                                       ap->id, dev->devno,
-                                      ata_id_major_version(dev->id),
-                                      ata_mode_string(xfer_modes),
+                                      ata_id_major_version(id),
+                                      ata_mode_string(xfer_mask),
                                       (unsigned long long)dev->n_sectors,
                                       dev->cylinders, dev->heads, dev->sectors);
                }
@@ -1171,7 +1287,7 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
 
        /* ATAPI-specific feature tests */
        else if (dev->class == ATA_DEV_ATAPI) {
-               rc = atapi_cdb_len(dev->id);
+               rc = atapi_cdb_len(id);
                if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
                        printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id);
                        rc = -EINVAL;
@@ -1182,7 +1298,7 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
                /* print device info to dmesg */
                if (print_info)
                        printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
-                              ap->id, dev->devno, ata_mode_string(xfer_modes));
+                              ap->id, dev->devno, ata_mode_string(xfer_mask));
        }
 
        ap->host->max_cmd_len = 0;
@@ -1235,29 +1351,30 @@ static int ata_bus_probe(struct ata_port *ap)
 
        ata_port_probe(ap);
 
-       /* reset */
+       /* reset and determine device classes */
+       for (i = 0; i < ATA_MAX_DEVICES; i++)
+               classes[i] = ATA_DEV_UNKNOWN;
+
        if (ap->ops->probe_reset) {
                rc = ap->ops->probe_reset(ap, classes);
                if (rc) {
                        printk("ata%u: reset failed (errno=%d)\n", ap->id, rc);
                        return rc;
                }
-
-               for (i = 0; i < ATA_MAX_DEVICES; i++)
-                       if (classes[i] == ATA_DEV_UNKNOWN)
-                               classes[i] = ATA_DEV_NONE;
        } else {
                ap->ops->phy_reset(ap);
 
-               for (i = 0; i < ATA_MAX_DEVICES; i++) {
-                       if (!(ap->flags & ATA_FLAG_PORT_DISABLED))
+               if (!(ap->flags & ATA_FLAG_PORT_DISABLED))
+                       for (i = 0; i < ATA_MAX_DEVICES; i++)
                                classes[i] = ap->device[i].class;
-                       else
-                               ap->device[i].class = ATA_DEV_UNKNOWN;
-               }
+
                ata_port_probe(ap);
        }
 
+       for (i = 0; i < ATA_MAX_DEVICES; i++)
+               if (classes[i] == ATA_DEV_UNKNOWN)
+                       classes[i] = ATA_DEV_NONE;
+
        /* read IDENTIFY page and configure devices */
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
                struct ata_device *dev = &ap->device[i];
@@ -1587,31 +1704,8 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
        return 0;
 }
 
-static const struct {
-       unsigned int shift;
-       u8 base;
-} xfer_mode_classes[] = {
-       { ATA_SHIFT_UDMA,       XFER_UDMA_0 },
-       { ATA_SHIFT_MWDMA,      XFER_MW_DMA_0 },
-       { ATA_SHIFT_PIO,        XFER_PIO_0 },
-};
-
-static u8 base_from_shift(unsigned int shift)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++)
-               if (xfer_mode_classes[i].shift == shift)
-                       return xfer_mode_classes[i].base;
-
-       return 0xff;
-}
-
 static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev)
 {
-       int ofs, idx;
-       u8 base;
-
        if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED))
                return;
 
@@ -1620,71 +1714,58 @@ static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev)
 
        ata_dev_set_xfermode(ap, dev);
 
-       base = base_from_shift(dev->xfer_shift);
-       ofs = dev->xfer_mode - base;
-       idx = ofs + dev->xfer_shift;
-       WARN_ON(idx >= ARRAY_SIZE(xfer_mode_str));
-
        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);
        }
 
-       DPRINTK("idx=%d xfer_shift=%u, xfer_mode=0x%x, base=0x%x, offset=%d\n",
-               idx, dev->xfer_shift, (int)dev->xfer_mode, (int)base, ofs);
+       DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
+               dev->xfer_shift, (int)dev->xfer_mode);
 
        printk(KERN_INFO "ata%u: dev %u configured for %s\n",
-               ap->id, dev->devno, xfer_mode_str[idx]);
+              ap->id, dev->devno,
+              ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)));
 }
 
 static int ata_host_set_pio(struct ata_port *ap)
 {
-       unsigned int mask;
-       int x, i;
-       u8 base, xfer_mode;
-
-       mask = ata_get_mode_mask(ap, ATA_SHIFT_PIO);
-       x = fgb(mask);
-       if (x < 0) {
-               printk(KERN_WARNING "ata%u: no PIO support\n", ap->id);
-               return -1;
-       }
-
-       base = base_from_shift(ATA_SHIFT_PIO);
-       xfer_mode = base + x;
-
-       DPRINTK("base 0x%x xfer_mode 0x%x mask 0x%x x %d\n",
-               (int)base, (int)xfer_mode, mask, x);
+       int i;
 
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
                struct ata_device *dev = &ap->device[i];
-               if (ata_dev_present(dev)) {
-                       dev->pio_mode = xfer_mode;
-                       dev->xfer_mode = xfer_mode;
-                       dev->xfer_shift = ATA_SHIFT_PIO;
-                       if (ap->ops->set_piomode)
-                               ap->ops->set_piomode(ap, dev);
+
+               if (!ata_dev_present(dev))
+                       continue;
+
+               if (!dev->pio_mode) {
+                       printk(KERN_WARNING "ata%u: no PIO support\n", ap->id);
+                       return -1;
                }
+
+               dev->xfer_mode = dev->pio_mode;
+               dev->xfer_shift = ATA_SHIFT_PIO;
+               if (ap->ops->set_piomode)
+                       ap->ops->set_piomode(ap, dev);
        }
 
        return 0;
 }
 
-static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
-                           unsigned int xfer_shift)
+static void ata_host_set_dma(struct ata_port *ap)
 {
        int i;
 
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
                struct ata_device *dev = &ap->device[i];
-               if (ata_dev_present(dev)) {
-                       dev->dma_mode = xfer_mode;
-                       dev->xfer_mode = xfer_mode;
-                       dev->xfer_shift = xfer_shift;
-                       if (ap->ops->set_dmamode)
-                               ap->ops->set_dmamode(ap, dev);
-               }
+
+               if (!ata_dev_present(dev) || !dev->dma_mode)
+                       continue;
+
+               dev->xfer_mode = dev->dma_mode;
+               dev->xfer_shift = ata_xfer_mode2shift(dev->dma_mode);
+               if (ap->ops->set_dmamode)
+                       ap->ops->set_dmamode(ap, dev);
        }
 }
 
@@ -1699,28 +1780,34 @@ static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
  */
 static void ata_set_mode(struct ata_port *ap)
 {
-       unsigned int xfer_shift;
-       u8 xfer_mode;
-       int rc;
+       int i, rc;
 
-       /* step 1: always set host PIO timings */
-       rc = ata_host_set_pio(ap);
-       if (rc)
-               goto err_out;
+       /* step 1: calculate xfer_mask */
+       for (i = 0; i < ATA_MAX_DEVICES; i++) {
+               struct ata_device *dev = &ap->device[i];
+               unsigned int xfer_mask;
 
-       /* step 2: choose the best data xfer mode */
-       xfer_mode = xfer_shift = 0;
-       rc = ata_choose_xfer_mode(ap, &xfer_mode, &xfer_shift);
+               if (!ata_dev_present(dev))
+                       continue;
+
+               xfer_mask = ata_dev_xfermask(ap, dev);
+
+               dev->pio_mode = ata_xfer_mask2mode(xfer_mask & ATA_MASK_PIO);
+               dev->dma_mode = ata_xfer_mask2mode(xfer_mask & (ATA_MASK_MWDMA |
+                                                               ATA_MASK_UDMA));
+       }
+
+       /* step 2: always set host PIO timings */
+       rc = ata_host_set_pio(ap);
        if (rc)
                goto err_out;
 
-       /* step 3: if that xfer mode isn't PIO, set host DMA timings */
-       if (xfer_shift != ATA_SHIFT_PIO)
-               ata_host_set_dma(ap, xfer_mode, xfer_shift);
+       /* step 3: set host DMA timings */
+       ata_host_set_dma(ap);
 
        /* step 4: update devices' xfer mode */
-       ata_dev_set_mode(ap, &ap->device[0]);
-       ata_dev_set_mode(ap, &ap->device[1]);
+       for (i = 0; i < ATA_MAX_DEVICES; i++)
+               ata_dev_set_mode(ap, &ap->device[i]);
 
        if (ap->flags & ATA_FLAG_PORT_DISABLED)
                return;
@@ -2465,13 +2552,6 @@ int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev,
        return rc;
 }
 
-static void ata_pr_blacklisted(const struct ata_port *ap,
-                              const struct ata_device *dev)
-{
-       printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, disabling DMA\n",
-               ap->id, dev->devno);
-}
-
 static const char * const ata_dma_blacklist [] = {
        "WDC AC11000H",
        "WDC AC22100H",
@@ -2518,128 +2598,45 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
        return 0;
 }
 
-static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift)
-{
-       const struct ata_device *master, *slave;
-       unsigned int mask;
-
-       master = &ap->device[0];
-       slave = &ap->device[1];
-
-       WARN_ON(!ata_dev_present(master) && !ata_dev_present(slave));
-
-       if (shift == ATA_SHIFT_UDMA) {
-               mask = ap->udma_mask;
-               if (ata_dev_present(master)) {
-                       mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff);
-                       if (ata_dma_blacklisted(master)) {
-                               mask = 0;
-                               ata_pr_blacklisted(ap, master);
-                       }
-               }
-               if (ata_dev_present(slave)) {
-                       mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff);
-                       if (ata_dma_blacklisted(slave)) {
-                               mask = 0;
-                               ata_pr_blacklisted(ap, slave);
-                       }
-               }
-       }
-       else if (shift == ATA_SHIFT_MWDMA) {
-               mask = ap->mwdma_mask;
-               if (ata_dev_present(master)) {
-                       mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07);
-                       if (ata_dma_blacklisted(master)) {
-                               mask = 0;
-                               ata_pr_blacklisted(ap, master);
-                       }
-               }
-               if (ata_dev_present(slave)) {
-                       mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07);
-                       if (ata_dma_blacklisted(slave)) {
-                               mask = 0;
-                               ata_pr_blacklisted(ap, slave);
-                       }
-               }
-       }
-       else if (shift == ATA_SHIFT_PIO) {
-               mask = ap->pio_mask;
-               if (ata_dev_present(master)) {
-                       /* spec doesn't return explicit support for
-                        * PIO0-2, so we fake it
-                        */
-                       u16 tmp_mode = master->id[ATA_ID_PIO_MODES] & 0x03;
-                       tmp_mode <<= 3;
-                       tmp_mode |= 0x7;
-                       mask &= tmp_mode;
-               }
-               if (ata_dev_present(slave)) {
-                       /* spec doesn't return explicit support for
-                        * PIO0-2, so we fake it
-                        */
-                       u16 tmp_mode = slave->id[ATA_ID_PIO_MODES] & 0x03;
-                       tmp_mode <<= 3;
-                       tmp_mode |= 0x7;
-                       mask &= tmp_mode;
-               }
-       }
-       else {
-               mask = 0xffffffff; /* shut up compiler warning */
-               BUG();
-       }
-
-       return mask;
-}
-
-/* find greatest bit */
-static int fgb(u32 bitmap)
-{
-       unsigned int i;
-       int x = -1;
-
-       for (i = 0; i < 32; i++)
-               if (bitmap & (1 << i))
-                       x = i;
-
-       return x;
-}
-
 /**
- *     ata_choose_xfer_mode - attempt to find best transfer mode
- *     @ap: Port for which an xfer mode will be selected
- *     @xfer_mode_out: (output) SET FEATURES - XFER MODE code
- *     @xfer_shift_out: (output) bit shift that selects this mode
+ *     ata_dev_xfermask - Compute supported xfermask of the given device
+ *     @ap: Port on which the device to compute xfermask for resides
+ *     @dev: Device to compute xfermask for
  *
- *     Based on host and device capabilities, determine the
- *     maximum transfer mode that is amenable to all.
+ *     Compute supported xfermask of @dev.  This function is
+ *     responsible for applying all known limits including host
+ *     controller limits, device blacklist, etc...
  *
  *     LOCKING:
- *     PCI/etc. bus probe sem.
+ *     None.
  *
  *     RETURNS:
- *     Zero on success, negative on error.
+ *     Computed xfermask.
  */
-
-static int ata_choose_xfer_mode(const struct ata_port *ap,
-                               u8 *xfer_mode_out,
-                               unsigned int *xfer_shift_out)
+static unsigned int ata_dev_xfermask(struct ata_port *ap,
+                                    struct ata_device *dev)
 {
-       unsigned int mask, shift;
-       int x, i;
+       unsigned long xfer_mask;
+       int i;
 
-       for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) {
-               shift = xfer_mode_classes[i].shift;
-               mask = ata_get_mode_mask(ap, shift);
+       xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
+                                     ap->udma_mask);
 
-               x = fgb(mask);
-               if (x >= 0) {
-                       *xfer_mode_out = xfer_mode_classes[i].base + x;
-                       *xfer_shift_out = shift;
-                       return 0;
-               }
+       /* use port-wide xfermask for now */
+       for (i = 0; i < ATA_MAX_DEVICES; i++) {
+               struct ata_device *d = &ap->device[i];
+               if (!ata_dev_present(d))
+                       continue;
+               xfer_mask &= ata_id_xfermask(d->id);
+               if (ata_dma_blacklisted(d))
+                       xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
        }
 
-       return -1;
+       if (ata_dma_blacklisted(dev))
+               printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, "
+                      "disabling DMA\n", ap->id, dev->devno);
+
+       return xfer_mask;
 }
 
 /**