Skip to content

Commit

Permalink
[PATCH] libata: Add CompactFlash support
Browse files Browse the repository at this point in the history
The CFA world has some additional rules and drive modes we need to support for
newer expansion cards and on embedded boxes

Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
  • Loading branch information
Alan Cox authored and Jeff Garzik committed Aug 14, 2006
1 parent cea0d33 commit b352e57
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 11 deletions.
62 changes: 54 additions & 8 deletions drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,9 +386,13 @@ static const char *ata_mode_string(unsigned int xfer_mask)
"PIO2",
"PIO3",
"PIO4",
"PIO5",
"PIO6",
"MWDMA0",
"MWDMA1",
"MWDMA2",
"MWDMA3",
"MWDMA4",
"UDMA/16",
"UDMA/25",
"UDMA/33",
Expand Down Expand Up @@ -875,6 +879,23 @@ static unsigned int ata_id_xfermask(const u16 *id)

mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07;

if (ata_id_is_cfa(id)) {
/*
* Process compact flash extended modes
*/
int pio = id[163] & 0x7;
int dma = (id[163] >> 3) & 7;

if (pio)
pio_mask |= (1 << 5);
if (pio > 1)
pio_mask |= (1 << 6);
if (dma)
mwdma_mask |= (1 << 3);
if (dma > 1)
mwdma_mask |= (1 << 4);
}

udma_mask = 0;
if (id[ATA_ID_FIELD_VALID] & (1 << 2))
udma_mask = id[ATA_ID_UDMA_MODES] & 0xff;
Expand Down Expand Up @@ -1356,6 +1377,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
struct ata_port *ap = dev->ap;
const u16 *id = dev->id;
unsigned int xfer_mask;
char revbuf[7]; /* XYZ-99\0 */
int rc;

if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
Expand Down Expand Up @@ -1399,6 +1421,15 @@ int ata_dev_configure(struct ata_device *dev, int print_info)

/* ATA-specific feature tests */
if (dev->class == ATA_DEV_ATA) {
if (ata_id_is_cfa(id)) {
if (id[162] & 1) /* CPRM may make this media unusable */
ata_dev_printk(dev, KERN_WARNING, "ata%u: device %u supports DRM functions and may not be fully accessable.\n",
ap->id, dev->devno);
snprintf(revbuf, 7, "CFA");
}
else
snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));

dev->n_sectors = ata_id_n_sectors(id);

if (ata_id_has_lba(id)) {
Expand All @@ -1417,9 +1448,9 @@ int ata_dev_configure(struct ata_device *dev, int print_info)

/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
ata_dev_printk(dev, KERN_INFO, "%s, "
"max %s, %Lu sectors: %s %s\n",
ata_id_major_version(id),
revbuf,
ata_mode_string(xfer_mask),
(unsigned long long)dev->n_sectors,
lba_desc, ncq_desc);
Expand All @@ -1440,9 +1471,9 @@ int ata_dev_configure(struct ata_device *dev, int print_info)

/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
ata_dev_printk(dev, KERN_INFO, "%s, "
"max %s, %Lu sectors: CHS %u/%u/%u\n",
ata_id_major_version(id),
revbuf,
ata_mode_string(xfer_mask),
(unsigned long long)dev->n_sectors,
dev->cylinders, dev->heads,
Expand Down Expand Up @@ -1900,10 +1931,11 @@ int sata_set_spd(struct ata_port *ap)
* drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik
*/
/*
* PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
* PIO 0-4, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
* These were taken from ATA/ATAPI-6 standard, rev 0a, except
* for PIO 5, which is a nonstandard extension and UDMA6, which
* is currently supported only by Maxtor drives.
* for UDMA6, which is currently supported only by Maxtor drives.
*
* For PIO 5/6 MWDMA 3/4 see the CFA specification 3.0.
*/

static const struct ata_timing ata_timing[] = {
Expand All @@ -1913,6 +1945,8 @@ static const struct ata_timing ata_timing[] = {
{ XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 },
{ XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 },

{ XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 },
{ XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 },
{ XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 },
{ XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 },
{ XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 },
Expand All @@ -1927,7 +1961,8 @@ static const struct ata_timing ata_timing[] = {
{ XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 },
{ XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 },

/* { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 }, */
{ XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 },
{ XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 },
{ XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 },
{ XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 },

Expand Down Expand Up @@ -3062,6 +3097,17 @@ static void ata_dev_xfermask(struct ata_device *dev)
dev->mwdma_mask, dev->udma_mask);
xfer_mask &= ata_id_xfermask(dev->id);

/*
* CFA Advanced TrueIDE timings are not allowed on a shared
* cable
*/
if (ata_dev_pair(dev)) {
/* No PIO5 or PIO6 */
xfer_mask &= ~(0x03 << (ATA_SHIFT_PIO + 5));
/* No MWDMA3 or MWDMA 4 */
xfer_mask &= ~(0x03 << (ATA_SHIFT_MWDMA + 3));
}

if (ata_dma_blacklisted(dev)) {
xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
ata_dev_printk(dev, KERN_WARNING,
Expand Down
20 changes: 19 additions & 1 deletion include/linux/ata.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,16 @@ enum {
XFER_UDMA_2 = 0x42,
XFER_UDMA_1 = 0x41,
XFER_UDMA_0 = 0x40,
XFER_MW_DMA_4 = 0x24, /* CFA only */
XFER_MW_DMA_3 = 0x23, /* CFA only */
XFER_MW_DMA_2 = 0x22,
XFER_MW_DMA_1 = 0x21,
XFER_MW_DMA_0 = 0x20,
XFER_SW_DMA_2 = 0x12,
XFER_SW_DMA_1 = 0x11,
XFER_SW_DMA_0 = 0x10,
XFER_PIO_6 = 0x0E, /* CFA only */
XFER_PIO_5 = 0x0D, /* CFA only */
XFER_PIO_4 = 0x0C,
XFER_PIO_3 = 0x0B,
XFER_PIO_2 = 0x0A,
Expand Down Expand Up @@ -274,7 +278,6 @@ struct ata_taskfile {
};

#define ata_id_is_ata(id) (((id)[0] & (1 << 15)) == 0)
#define ata_id_is_cfa(id) ((id)[0] == 0x848A)
#define ata_id_is_sata(id) ((id)[93] == 0)
#define ata_id_rahead_enabled(id) ((id)[85] & (1 << 6))
#define ata_id_wcache_enabled(id) ((id)[85] & (1 << 5))
Expand Down Expand Up @@ -306,6 +309,9 @@ static inline unsigned int ata_id_major_version(const u16 *id)
{
unsigned int mver;

if (id[ATA_ID_MAJOR_VER] == 0xFFFF)
return 0;

for (mver = 14; mver >= 1; mver--)
if (id[ATA_ID_MAJOR_VER] & (1 << mver))
break;
Expand All @@ -324,6 +330,18 @@ static inline int ata_id_current_chs_valid(const u16 *id)
id[56]; /* sectors in current translation */
}

static inline int ata_id_is_cfa(const u16 *id)
{
u16 v = id[0];
if (v == 0x848A) /* Standard CF */
return 1;
/* Could be CF hiding as standard ATA */
if (ata_id_major_version(id) >= 3 && id[82] != 0xFFFF &&
(id[82] & ( 1 << 2)))
return 1;
return 0;
}

static inline int atapi_cdb_len(const u16 *dev_id)
{
u16 tmp = dev_id[0] & 0x3;
Expand Down
4 changes: 2 additions & 2 deletions include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ enum {
/* encoding various smaller bitmaps into a single
* unsigned int bitmap
*/
ATA_BITS_PIO = 5,
ATA_BITS_MWDMA = 3,
ATA_BITS_PIO = 7,
ATA_BITS_MWDMA = 5,
ATA_BITS_UDMA = 8,

ATA_SHIFT_PIO = 0,
Expand Down

0 comments on commit b352e57

Please sign in to comment.