ATA support for 4k sector size

5 messages, 3 authors, 2009-02-26 · open the first message on its own page

ATA support for 4k sector size

From: Matthew Wilcox <hidden>
Date: 2009-02-25 22:25:16

The two patches following this add support for drives which have sector
sizes other than 512 bytes.  I haven't been able to test this as I don't
have the hardware.

Individual host drivers will have to be updated to support sizes other
than 512 bytes.

Support for logical sector sizes that differ from physical sector sizes
depends on the READ CAPACITY 16 patch I posted in December that isn't in
scsi-misc yet.

The approach I've taken to generating the tables of which commands need
a 512-byte transfer size and which use the drive's sector size command is
'innovative'.  Review is encouraged ;-)

[PATCH 1/2] ata: Define new commands from ATA8

From: Matthew Wilcox <hidden>
Date: 2009-02-25 22:25:39

Later patches require knowledge of some commands which aren't currently
defined.  While I'm at it, add all the commands that are in ATA8 and
reorder the existing commands to be in the same order as ATA8.

Signed-off-by: Matthew Wilcox <redacted>
---
 include/linux/ata.h |  103 +++++++++++++++++++++++++++++++++-----------------
 1 files changed, 68 insertions(+), 35 deletions(-)
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 08a86d5..8d09d81 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -194,65 +194,98 @@ enum {
 	ATA_REG_IRQ		= ATA_REG_NSECT,
 
 	/* ATA device commands */
-	ATA_CMD_DEV_RESET	= 0x08, /* ATAPI device reset */
+	ATA_CMD_CFA_ERASE_SECTORS = 0xC0,
+	ATA_CMD_CFA_REQUEST_EXT_ERROR = 0x03,
+	ATA_CMD_CFA_TRANSLATE_SECTOR = 0x87,
+	ATA_CMD_CFA_WRITE_MULTI_WITHOUT_ERASE = 0xCD,
+	ATA_CMD_CFA_WRITE_SECTORS_WITHOUT_ERASE = 0x38,
+	ATA_CMD_CHK_MEDIA_CARD_TYPE = 0xD1,
 	ATA_CMD_CHK_POWER	= 0xE5, /* check power mode */
-	ATA_CMD_STANDBY		= 0xE2, /* place in standby power mode */
-	ATA_CMD_IDLE		= 0xE3, /* place in idle power mode */
+	ATA_CMD_CONFIG_STREAM	= 0x51,
+	ATA_CMD_CONF_OVERLAY	= 0xB1,
+	ATA_CMD_DEV_RESET	= 0x08, /* ATAPI device reset */
+	ATA_CMD_DLOAD_MCODE	= 0x92,
 	ATA_CMD_EDD		= 0x90,	/* execute device diagnostic */
 	ATA_CMD_FLUSH		= 0xE7,
 	ATA_CMD_FLUSH_EXT	= 0xEA,
 	ATA_CMD_ID_ATA		= 0xEC,
 	ATA_CMD_ID_ATAPI	= 0xA1,
-	ATA_CMD_READ		= 0xC8,
-	ATA_CMD_READ_EXT	= 0x25,
-	ATA_CMD_WRITE		= 0xCA,
-	ATA_CMD_WRITE_EXT	= 0x35,
-	ATA_CMD_WRITE_FUA_EXT	= 0x3D,
+	ATA_CMD_IDLE		= 0xE3, /* place in idle power mode */
+	ATA_CMD_IDLEIMMEDIATE	= 0xE1,
+	ATA_CMD_MEDIA_LOCK	= 0xDE,
+	ATA_CMD_MEDIA_UNLOCK	= 0xDF,
+	ATA_CMD_NVCACHE		= 0xB6,
+	ATA_CMD_NOP		= 0x00,
+	ATA_CMD_PACKET		= 0xA0,
+	ATA_CMD_PMP_READ	= 0xE4, /* aka READ BUFFER */
+	ATA_CMD_READ		= 0xC8, /* aka READ DMA */
+	ATA_CMD_READ_EXT	= 0x25, /* aka READ DMA EXT */
+	ATA_CMD_READ_QUEUED	= 0xC7,
+	ATA_CMD_READ_QUEUED_EXT	= 0x26,
 	ATA_CMD_FPDMA_READ	= 0x60,
-	ATA_CMD_FPDMA_WRITE	= 0x61,
-	ATA_CMD_PIO_READ	= 0x20,
-	ATA_CMD_PIO_READ_EXT	= 0x24,
-	ATA_CMD_PIO_WRITE	= 0x30,
-	ATA_CMD_PIO_WRITE_EXT	= 0x34,
+	ATA_CMD_READ_LOG_EXT	= 0x2F,
+	ATA_CMD_READ_LOG_DMA_EXT= 0x47,
 	ATA_CMD_READ_MULTI	= 0xC4,
 	ATA_CMD_READ_MULTI_EXT	= 0x29,
-	ATA_CMD_WRITE_MULTI	= 0xC5,
-	ATA_CMD_WRITE_MULTI_EXT	= 0x39,
-	ATA_CMD_WRITE_MULTI_FUA_EXT = 0xCE,
-	ATA_CMD_SET_FEATURES	= 0xEF,
-	ATA_CMD_SET_MULTI	= 0xC6,
-	ATA_CMD_PACKET		= 0xA0,
-	ATA_CMD_VERIFY		= 0x40,
-	ATA_CMD_VERIFY_EXT	= 0x42,
-	ATA_CMD_STANDBYNOW1	= 0xE0,
-	ATA_CMD_IDLEIMMEDIATE	= 0xE1,
-	ATA_CMD_SLEEP		= 0xE6,
-	ATA_CMD_INIT_DEV_PARAMS	= 0x91,
 	ATA_CMD_READ_NATIVE_MAX	= 0xF8,
 	ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
+	ATA_CMD_PIO_READ	= 0x20, /* aka READ SECTOR(S) */
+	ATA_CMD_PIO_READ_EXT	= 0x24, /* aka READ SECTOR(S) EXT */
+	ATA_CMD_READ_STREAM_DMA_EXT = 0x2A,
+	ATA_CMD_READ_STREAM_EXT	= 0x2B,
+	ATA_CMD_VERIFY		= 0x40, /* aka READ VERIFY SECTOR(S) */
+	ATA_CMD_VERIFY_EXT	= 0x42, /* aka READ VERIFY SECTOR(S) EXT */
+	ATA_CMD_SEC_DISABLE_PASSWORD = 0xF6,
+	ATA_CMD_SEC_ERASE_PREPARE = 0xF3,
+	ATA_CMD_SEC_ERASE_UNIT	= 0xF4,
+	ATA_CMD_SEC_FREEZE_LOCK	= 0xF5,
+	ATA_CMD_SEC_SET_PASSWORD = 0xF1,
+	ATA_CMD_SEC_UNLOCK	= 0xF2,
+	ATA_CMD_SERVICE		= 0xA2,
+	ATA_CMD_SET_FEATURES	= 0xEF,
 	ATA_CMD_SET_MAX		= 0xF9,
 	ATA_CMD_SET_MAX_EXT	= 0x37,
-	ATA_CMD_READ_LOG_EXT	= 0x2f,
-	ATA_CMD_PMP_READ	= 0xE4,
-	ATA_CMD_PMP_WRITE	= 0xE8,
-	ATA_CMD_CONF_OVERLAY	= 0xB1,
-	ATA_CMD_SEC_FREEZE_LOCK	= 0xF5,
+	ATA_CMD_SET_MULTI	= 0xC6,
+	ATA_CMD_SLEEP		= 0xE6,
 	ATA_CMD_SMART		= 0xB0,
-	ATA_CMD_MEDIA_LOCK	= 0xDE,
-	ATA_CMD_MEDIA_UNLOCK	= 0xDF,
-	/* marked obsolete in the ATA/ATAPI-7 spec */
-	ATA_CMD_RESTORE		= 0x10,
+	ATA_CMD_STANDBY		= 0xE2, /* place in standby power mode */
+	ATA_CMD_STANDBYNOW1	= 0xE0,
+	ATA_CMD_TRUSTED_NON_DATA = 0x5B,
+	ATA_CMD_TRUSTED_RECEIVE	= 0x5C,
+	ATA_CMD_TRUSTED_RECEIVE_DMA = 0x5D,
+	ATA_CMD_TRUSTED_SEND	= 0x5E,
+	ATA_CMD_TRUSTED_SEND_DMA = 0x5F,
+	ATA_CMD_PMP_WRITE	= 0xE8, /* aka WRITE BUFFER */
+	ATA_CMD_WRITE		= 0xCA, /* aka WRITE DMA */
+	ATA_CMD_WRITE_EXT	= 0x35, /* aka WRITE DMA EXT */
+	ATA_CMD_WRITE_FUA_EXT	= 0x3D, /* aka WRITE DMA FUA EXT */
+	ATA_CMD_WRITE_DMA_QUEUED = 0xCC,
+	ATA_CMD_WRITE_DMA_QUEUED_EXT = 0x36,
+	ATA_CMD_WRITE_DMA_QUEUED_FUA_EXT = 0x3E,
+	ATA_CMD_FPDMA_WRITE	= 0x61, /* aka WRITE FPDMA QUEUED */
+	ATA_CMD_WRITE_LOG_EXT	= 0x3F,
+	ATA_CMD_WRITE_LOG_DMA_EXT = 0x57,
+	ATA_CMD_WRITE_MULTI	= 0xC5,
+	ATA_CMD_WRITE_MULTI_EXT	= 0x39,
+	ATA_CMD_WRITE_MULTI_FUA_EXT = 0xCE,
+	ATA_CMD_PIO_WRITE	= 0x30, /* aka WRITE SECTOR(S) */
+	ATA_CMD_PIO_WRITE_EXT	= 0x34, /* aka WRITE SECTOR(S) EXT */
+	ATA_CMD_WRITE_STREAM_DMA_EXT = 0x3A,
+	ATA_CMD_WRITE_STREAM_EXT = 0x3B,
+	ATA_CMD_WRITE_UNCORRECTABLE_EXT = 0x45,
 	/* EXABYTE specific */
 	ATA_EXABYTE_ENABLE_NEST	= 0xF0,
 
 	/* READ_LOG_EXT pages */
 	ATA_LOG_SATA_NCQ	= 0x10,
 
-	/* READ/WRITE LONG (obsolete) */
+	/* Obsolete */
 	ATA_CMD_READ_LONG	= 0x22,
 	ATA_CMD_READ_LONG_ONCE	= 0x23,
 	ATA_CMD_WRITE_LONG	= 0x32,
 	ATA_CMD_WRITE_LONG_ONCE	= 0x33,
+	ATA_CMD_INIT_DEV_PARAMS	= 0x91,
+	ATA_CMD_RESTORE		= 0x10,
 
 	/* SETFEATURES stuff */
 	SETFEATURES_XFER	= 0x03,
-- 
1.5.6.5

[PATCH 2/2] ata: Add support for Long Logical Sectors and Long Physical Sectors

From: Matthew Wilcox <hidden>
Date: 2009-02-25 22:25:54

From: Matthew Wilcox <redacted>

ATA 8 permits devices that have sector sizes larger than 512 bytes.
We support this by recording the sector size in the ata_device and use
it instead of the ATA_SECT_SIZE when the data transfer is a multiple
of sectors.  Drivers must indicate their support for sector sizes other
than 512 by implementing the 'sector_size_supported' port operation.

Signed-off-by: Matthew Wilcox <redacted>
---
 drivers/ata/Makefile       |   11 ++++
 drivers/ata/ata-commands.c |  132 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/ata/bitops.c       |   77 +++++++++++++++++++++++++
 drivers/ata/bitops.h       |   12 ++++
 drivers/ata/libata-core.c  |   67 ++++++++++++++++++++++
 drivers/ata/libata-scsi.c  |   52 +++++++++++++-----
 include/linux/libata.h     |    3 +
 7 files changed, 340 insertions(+), 14 deletions(-)
 create mode 100644 drivers/ata/ata-commands.c
 create mode 100644 drivers/ata/bitops.c
 create mode 100644 drivers/ata/bitops.h
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 7f1ecf9..a67d5dc 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -84,3 +84,14 @@ libata-objs	:= libata-core.o libata-scsi.o libata-eh.o
 libata-$(CONFIG_ATA_SFF)	+= libata-sff.o
 libata-$(CONFIG_SATA_PMP)	+= libata-pmp.o
 libata-$(CONFIG_ATA_ACPI)	+= libata-acpi.o
+
+hostprogs-y := ata-commands
+ata-commands-objs := ata-commands.o bitops.o
+HOSTCFLAGS_ata-commands.o       := -Iinclude
+clean-files := all-commands sector-commands
+quiet_cmd_ata-cmds = ATA-CMD 
+      cmd_ata-cmds = $(obj)/ata-commands || (rm -f all-commands sector-commands)
+
+$(obj)/all-commands: $(obj)/ata-commands
+	$(call if_changed,ata-cmds)
+$(obj)/libata-core.o: $(obj)/all-commands
diff --git a/drivers/ata/ata-commands.c b/drivers/ata/ata-commands.c
new file mode 100644
index 0000000..afb40c1
--- /dev/null
+++ b/drivers/ata/ata-commands.c
@@ -0,0 +1,132 @@
+/*
+ * ata-commands.c
+ *
+ * Copyright (c) 2008 Intel Corporation
+ * Author: Matthew Wilcox <willy@linux.intel.com>
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License, version 2
+ */
+
+#include <stdio.h>
+
+#include "bitops.h"
+
+/* We have to define some types to include ata.h */
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned long long u64;
+typedef int bool;
+#define false 0
+#define true 1
+#define _LINUX_SWAB_H
+#include "linux/ata.h"
+
+void set_sector_bits(void)
+{
+	set_bit(ATA_CMD_CFA_TRANSLATE_SECTOR);
+	set_bit(ATA_CMD_CFA_WRITE_MULTI_WITHOUT_ERASE);
+	set_bit(ATA_CMD_CFA_WRITE_SECTORS_WITHOUT_ERASE);
+	set_bit(ATA_CMD_READ);
+	set_bit(ATA_CMD_READ_EXT);
+	set_bit(ATA_CMD_READ_QUEUED);
+	set_bit(ATA_CMD_READ_QUEUED_EXT);
+	set_bit(ATA_CMD_FPDMA_READ);
+	set_bit(ATA_CMD_READ_MULTI);
+	set_bit(ATA_CMD_READ_MULTI_EXT);
+	set_bit(ATA_CMD_PIO_READ);
+	set_bit(ATA_CMD_PIO_READ_EXT);
+	set_bit(ATA_CMD_READ_STREAM_DMA_EXT);
+	set_bit(ATA_CMD_READ_STREAM_EXT);
+	set_bit(ATA_CMD_VERIFY);
+	set_bit(ATA_CMD_VERIFY_EXT);
+	set_bit(ATA_CMD_WRITE);
+	set_bit(ATA_CMD_WRITE_EXT);
+	set_bit(ATA_CMD_WRITE_FUA_EXT);
+	set_bit(ATA_CMD_WRITE_DMA_QUEUED);
+	set_bit(ATA_CMD_WRITE_DMA_QUEUED_EXT);
+	set_bit(ATA_CMD_WRITE_DMA_QUEUED_FUA_EXT);
+	set_bit(ATA_CMD_FPDMA_WRITE);
+	set_bit(ATA_CMD_WRITE_MULTI);
+	set_bit(ATA_CMD_WRITE_MULTI_EXT);
+	set_bit(ATA_CMD_WRITE_MULTI_FUA_EXT);
+	set_bit(ATA_CMD_PIO_WRITE);
+	set_bit(ATA_CMD_PIO_WRITE_EXT);
+	set_bit(ATA_CMD_WRITE_STREAM_DMA_EXT);
+	set_bit(ATA_CMD_WRITE_STREAM_EXT);
+}
+
+void set_512_bits(void)
+{
+	set_bit(ATA_CMD_CFA_ERASE_SECTORS);
+	set_bit(ATA_CMD_CFA_REQUEST_EXT_ERROR);
+	set_bit(ATA_CMD_CHK_MEDIA_CARD_TYPE);
+	set_bit(ATA_CMD_CHK_POWER);
+	set_bit(ATA_CMD_CONFIG_STREAM);
+	set_bit(ATA_CMD_CONF_OVERLAY);
+	set_bit(ATA_CMD_DEV_RESET);
+	set_bit(ATA_CMD_DLOAD_MCODE);
+	set_bit(ATA_CMD_EDD);
+	set_bit(ATA_CMD_FLUSH);
+	set_bit(ATA_CMD_FLUSH_EXT);
+	set_bit(ATA_CMD_ID_ATA);
+	set_bit(ATA_CMD_ID_ATAPI);
+	set_bit(ATA_CMD_IDLE);
+	set_bit(ATA_CMD_IDLEIMMEDIATE);
+	set_bit(ATA_CMD_MEDIA_LOCK);
+	set_bit(ATA_CMD_MEDIA_UNLOCK);
+	set_bit(ATA_CMD_NVCACHE);
+	set_bit(ATA_CMD_NOP);
+	set_bit(ATA_CMD_PACKET);
+	set_bit(ATA_CMD_PMP_READ);
+	set_bit(ATA_CMD_READ_LOG_EXT);
+	set_bit(ATA_CMD_READ_LOG_DMA_EXT);
+	set_bit(ATA_CMD_READ_NATIVE_MAX);
+	set_bit(ATA_CMD_READ_NATIVE_MAX_EXT);
+	set_bit(ATA_CMD_RESTORE);
+	set_bit(ATA_CMD_SEC_DISABLE_PASSWORD);
+	set_bit(ATA_CMD_SEC_ERASE_PREPARE);
+	set_bit(ATA_CMD_SEC_ERASE_UNIT);
+	set_bit(ATA_CMD_SEC_FREEZE_LOCK);
+	set_bit(ATA_CMD_SEC_SET_PASSWORD);
+	set_bit(ATA_CMD_SEC_UNLOCK);
+	set_bit(ATA_CMD_SERVICE);
+	set_bit(ATA_CMD_SET_FEATURES);
+	set_bit(ATA_CMD_SET_MAX);
+	set_bit(ATA_CMD_SET_MAX_EXT);
+	set_bit(ATA_CMD_SET_MULTI);
+	set_bit(ATA_CMD_SLEEP);
+	set_bit(ATA_CMD_SMART);
+	set_bit(ATA_CMD_STANDBY);
+	set_bit(ATA_CMD_STANDBYNOW1);
+	set_bit(ATA_CMD_TRUSTED_NON_DATA);
+	set_bit(ATA_CMD_TRUSTED_RECEIVE);
+	set_bit(ATA_CMD_TRUSTED_RECEIVE_DMA);
+	set_bit(ATA_CMD_TRUSTED_SEND);
+	set_bit(ATA_CMD_TRUSTED_SEND_DMA);
+	set_bit(ATA_CMD_PMP_WRITE);
+	set_bit(ATA_CMD_WRITE_LOG_EXT);
+	set_bit(ATA_CMD_WRITE_LOG_DMA_EXT);
+	set_bit(ATA_CMD_WRITE_UNCORRECTABLE_EXT);
+	set_bit(ATA_CMD_INIT_DEV_PARAMS);
+	set_bit(ATA_EXABYTE_ENABLE_NEST);
+}
+
+int main(int argc, char **argv)
+{
+	FILE *out;
+
+	set_sector_bits();
+	out = fopen("drivers/ata/sector-commands", "w");
+	output_array(out);
+	fclose(out);
+
+	set_512_bits();
+	out = fopen("drivers/ata/all-commands", "w");
+	output_array(out);
+	fclose(out);
+
+	return 0;
+}
diff --git a/drivers/ata/bitops.c b/drivers/ata/bitops.c
new file mode 100644
index 0000000..f6a6f06
--- /dev/null
+++ b/drivers/ata/bitops.c
@@ -0,0 +1,77 @@
+/*
+ * bitops.c
+ *
+ * Copyright 2008 Intel Corporation
+ * Author: Matthew Wilcox <willy@linux.intel.com>
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License, version 2
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bitops.h"
+
+static unsigned int *array;
+static unsigned maxbit, allocbit;
+
+static void expand_array(unsigned bit)
+{
+	unsigned size;
+	void *tmp;
+
+	if (bit > maxbit)
+		maxbit = bit;
+	if (bit < allocbit)
+		return;
+
+	size = ((bit + 63) / 64) * 8;
+	tmp = realloc(array, size);
+	if (!tmp) {
+		fprintf(stderr, "Memory allocation failure\n");
+		exit(1);
+	}
+	array = tmp;
+	memset(array + allocbit / 8, 0, size - allocbit / 8);
+	allocbit = size * 8;
+}
+
+void set_bit(unsigned bit)
+{
+	expand_array(bit);
+	array[bit / 32] |= 1 << (bit % 32);
+}
+
+static const char *sep(unsigned i, unsigned w)
+{
+	if (i >= w - 1)
+		return "\n";
+	if (i % 6 == 5)
+		return "\n\t";
+	return " ";
+}
+
+void output_array(FILE *file)
+{
+	unsigned i, words = (maxbit + 32) / 32;
+
+	fprintf(file, "{\n#ifdef CONFIG_64BIT\n\t");
+	for (i = 0; i < words; i += 2) {
+		fprintf(file, "0x%08x%08xULL,%s", array[i + 1], array[i],
+							sep(i + 1, words));
+	}
+	fprintf(file, "#else\n\t");
+	for (i = 0; i < words; i++) {
+		fprintf(file, "0x%08x,%s", array[i], sep(i, words));
+	}
+	fprintf(file, "#endif\n};\n");
+}
+
+void free_array(void)
+{
+	free(array);
+	array = NULL;
+	maxbit = allocbit = 0;
+}
diff --git a/drivers/ata/bitops.h b/drivers/ata/bitops.h
new file mode 100644
index 0000000..3da560c
--- /dev/null
+++ b/drivers/ata/bitops.h
@@ -0,0 +1,12 @@
+/*
+ * A library for creating statically initialised bit arrays
+ */
+
+/* Call this to set a bit. */
+extern void set_bit(unsigned bit);
+
+/* Call this to output the array. */
+extern void output_array(FILE *file);
+
+/* Remove all bits from the array. */
+extern void free_array(void);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 9fbf059..61378d8 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -600,6 +600,32 @@ void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf)
 	tf->hob_nsect	= fis[13];
 }
 
+/**
+ * ata_sect_size - Returns the sector size to use for a command
+ * @command: The ATA command byte
+ * @dev_sect_size: The size of the drive's sectors
+ *
+ * Some commands are specified to transfer (a multiple of) 512 bytes of data
+ * while others transfer a multiple of the number of bytes in a sector.  This
+ * function knows which commands transfer how much data.
+ */
+unsigned ata_sect_size(u8 command, unsigned dev_sect_size)
+{
+	static const unsigned long sector_commands[] =
+#include "sector-commands"
+	static unsigned long known_commands[] =
+#include "all-commands"
+
+	if (test_bit(command, sector_commands))
+		return dev_sect_size;
+	if (!test_bit(command, known_commands)) {
+		printk(KERN_ERR "Unknown ata cmd %d, assuming "
+				"512 byte sector size\n", command);
+		set_bit(command, known_commands);
+	}
+	return 512;
+}
+
 static const u8 ata_rw_cmds[] = {
 	/* pio multi */
 	ATA_CMD_READ_MULTI,
@@ -1333,6 +1359,25 @@ static u64 ata_id_n_sectors(const u16 *id)
 	}
 }
 
+/*
+ * ATA supports sector sizes up to 2^33 - 1.  The reported sector size may
+ * not be a power of two.  The extra bytes are used for user-visible data
+ * integrity calculations.  Note this is not the same as the ECC which is
+ * accessed through the SCT Command Transport or READ / WRITE LONG.
+ */
+static u64 ata_id_sect_size(const u16 *id)
+{
+	u16 word_106 = id[106];
+	u64 sz;
+
+	if ((word_106 & 0xc000) != 0x4000)
+		return ATA_SECT_SIZE;
+	if (!(word_106 & (1 << 12)))
+		return ATA_SECT_SIZE;
+	sz = (id[117] | ((u64)id[118] << 16)) * 2;
+	return sz;
+}
+
 u64 ata_tf_to_lba48(const struct ata_taskfile *tf)
 {
 	u64 sectors = 0;
@@ -2301,6 +2346,20 @@ static void ata_dev_config_ncq(struct ata_device *dev,
 		snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
 }
 
+static int ata_check_sect_size(struct ata_device *dev)
+{
+	/* Every host can handle 512 byte sectors */
+	if (dev->sect_size == 512)
+		return 0;
+	/* Linux doesn't handle sectors larger than 4GB.  This may be
+	 * a problem around 2050 or so.  Deal with it then.  */
+	if (dev->sect_size > 0xffffffffULL)
+		return -EINVAL;
+	if (!dev->link->ap->ops->sector_size_supported)
+		return -EINVAL;
+	return dev->link->ap->ops->sector_size_supported(dev) ? 0 : -EINVAL;
+}
+
 /**
  *	ata_dev_configure - Configure the specified ATA/ATAPI device
  *	@dev: Target device to configure
@@ -2384,6 +2443,7 @@ int ata_dev_configure(struct ata_device *dev)
 	dev->max_sectors = 0;
 	dev->cdb_len = 0;
 	dev->n_sectors = 0;
+	dev->sect_size = ATA_SECT_SIZE;
 	dev->cylinders = 0;
 	dev->heads = 0;
 	dev->sectors = 0;
@@ -2423,6 +2483,13 @@ int ata_dev_configure(struct ata_device *dev)
 		}
 
 		dev->n_sectors = ata_id_n_sectors(id);
+		dev->sect_size = ata_id_sect_size(id);
+		rc = ata_check_sect_size(dev);
+		if (rc) {
+			ata_dev_printk(dev, KERN_ERR, "sector size %lld not "
+					"supported.\n", dev->sect_size);
+			goto err_out_nosup;
+		}
 
 		if (dev->id[59] & 0x100)
 			dev->multi_count = dev->id[59] & 0xff;
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index b9747fa..9e89601 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -50,7 +50,6 @@
 
 #include "libata.h"
 
-#define SECTOR_SIZE		512
 #define ATA_SCSI_RBUF_SIZE	4096
 
 static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
@@ -455,7 +454,7 @@ static int ata_get_identity(struct ata_port *ap, struct scsi_device *sdev,
 
 /**
  *	ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl
- *	@scsidev: Device to which we are issuing command
+ *	@sdev: Device to which we are issuing command
  *	@arg: User provided data for issuing command
  *
  *	LOCKING:
@@ -464,7 +463,7 @@ static int ata_get_identity(struct ata_port *ap, struct scsi_device *sdev,
  *	RETURNS:
  *	Zero on success, negative errno on error.
  */
-int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
+int ata_cmd_ioctl(struct scsi_device *sdev, void __user *arg)
 {
 	int rc = 0;
 	u8 scsi_cmd[MAX_COMMAND_SIZE];
@@ -486,7 +485,8 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
 	memset(scsi_cmd, 0, sizeof(scsi_cmd));
 
 	if (args[3]) {
-		argsize = SECTOR_SIZE * args[3];
+		unsigned sect_size = ata_sect_size(args[0], sdev->sector_size);
+		argsize = sect_size * args[3];
 		argbuf = kmalloc(argsize, GFP_KERNEL);
 		if (argbuf == NULL) {
 			rc = -ENOMEM;
@@ -518,7 +518,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
 
 	/* Good values for timeout and retries?  Values below
 	   from scsi_ioctl_send_command() for default case... */
-	cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize,
+	cmd_result = scsi_execute(sdev, scsi_cmd, data_dir, argbuf, argsize,
 				  sensebuf, (10*HZ), 5, 0, NULL);
 
 	if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */
@@ -1630,6 +1630,7 @@ nothing_to_do:
 static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
 {
 	struct scsi_cmnd *scmd = qc->scsicmd;
+	struct ata_device *dev = qc->dev;
 	const u8 *cdb = scmd->cmnd;
 	unsigned int tf_flags = 0;
 	u64 block;
@@ -1686,9 +1687,9 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
 		goto nothing_to_do;
 
 	qc->flags |= ATA_QCFLAG_IO;
-	qc->nbytes = n_block * ATA_SECT_SIZE;
+	qc->nbytes = n_block * dev->sect_size;
 
-	rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags,
+	rc = ata_build_rw_tf(&qc->tf, dev, block, n_block, tf_flags,
 			     qc->tag);
 	if (likely(rc == 0))
 		return 0;
@@ -2354,10 +2355,25 @@ saving_not_supp:
  */
 static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
 {
-	u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */
+	struct ata_device *dev = args->dev;
+	u64 last_lba = dev->n_sectors - 1; /* LBA of the last block */
+	u32 sector_size;
+	u8 log_per_phys = 1;
+	u16 first_sector_offset = 0;
+	u16 word_106 = dev->id[106];
 
 	VPRINTK("ENTER\n");
 
+	if ((word_106 & 0xc000) == 0x4000) {
+		/* Number and offset of logical sectors per physical sector */
+		if (word_106 & (1 << 13))
+			log_per_phys = word_106 & 0xf;
+		if ((dev->id[209] & 0xc000) == 0x4000)
+			first_sector_offset = dev->id[209] & 0x3fff;
+	}
+
+	sector_size = dev->sect_size;
+
 	if (args->cmd->cmnd[0] == READ_CAPACITY) {
 		if (last_lba >= 0xffffffffULL)
 			last_lba = 0xffffffff;
@@ -2368,9 +2384,10 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
 		rbuf[2] = last_lba >> (8 * 1);
 		rbuf[3] = last_lba;
 
-		/* sector size */
-		rbuf[6] = ATA_SECT_SIZE >> 8;
-		rbuf[7] = ATA_SECT_SIZE & 0xff;
+		rbuf[4] = sector_size >> (8 * 3);
+		rbuf[5] = sector_size >> (8 * 2);
+		rbuf[6] = sector_size >> (8 * 1);
+		rbuf[7] = sector_size;
 	} else {
 		/* sector count, 64-bit */
 		rbuf[0] = last_lba >> (8 * 7);
@@ -2383,8 +2400,15 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
 		rbuf[7] = last_lba;
 
 		/* sector size */
-		rbuf[10] = ATA_SECT_SIZE >> 8;
-		rbuf[11] = ATA_SECT_SIZE & 0xff;
+		rbuf[8] = sector_size >> (8 * 3);
+		rbuf[9] = sector_size >> (8 * 2);
+		rbuf[10] = sector_size >> (8 * 1);
+		rbuf[11] = sector_size;
+
+		rbuf[12] = 0;
+		rbuf[13] = log_per_phys;
+		rbuf[14] = first_sector_offset >> 8;
+		rbuf[15] = first_sector_offset;
 	}
 
 	return 0;
@@ -2858,7 +2882,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
 	}
 
 	/* READ/WRITE LONG use a non-standard sect_size */
-	qc->sect_size = ATA_SECT_SIZE;
+	qc->sect_size = ata_sect_size(tf->command, dev->sect_size);
 	switch (tf->command) {
 	case ATA_CMD_READ_LONG:
 	case ATA_CMD_READ_LONG_ONCE:
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 5d87bc0..e0d17ec 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -583,6 +583,7 @@ struct ata_device {
 #endif
 	/* n_sector is CLEAR_BEGIN, read comment above CLEAR_BEGIN */
 	u64			n_sectors;	/* size of device, if ATA */
+	u64			sect_size;	/* Logical, not physical */
 	unsigned int		class;		/* ATA_DEV_xxx */
 	unsigned long		unpark_deadline;
 
@@ -781,6 +782,7 @@ struct ata_port_operations {
 	unsigned int (*read_id)(struct ata_device *dev, struct ata_taskfile *tf, u16 *id);
 
 	void (*dev_config)(struct ata_device *dev);
+	bool (*sector_size_supported)(struct ata_device *dev);
 
 	void (*freeze)(struct ata_port *ap);
 	void (*thaw)(struct ata_port *ap);
@@ -988,6 +990,7 @@ extern unsigned int ata_do_dev_read_id(struct ata_device *dev,
 					struct ata_taskfile *tf, u16 *id);
 extern void ata_qc_complete(struct ata_queued_cmd *qc);
 extern int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active);
+extern unsigned ata_sect_size(u8 command, unsigned dev_sect_size);
 extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
 			      void (*done)(struct scsi_cmnd *));
 extern int ata_std_bios_param(struct scsi_device *sdev,
-- 
1.5.6.5

Re: ATA support for 4k sector size

From: "H. Peter Anvin" <hpa@zytor.com>
Date: 2009-02-25 22:54:01

Matthew Wilcox wrote:
The two patches following this add support for drives which have sector
sizes other than 512 bytes.  I haven't been able to test this as I don't
have the hardware.

Individual host drivers will have to be updated to support sizes other
than 512 bytes.

Support for logical sector sizes that differ from physical sector sizes
depends on the READ CAPACITY 16 patch I posted in December that isn't in
scsi-misc yet.

The approach I've taken to generating the tables of which commands need
a 512-byte transfer size and which use the drive's sector size command is
'innovative'.  Review is encouraged ;-)
What sector size do we report to user space for this?  I'm asking because logical sector size is visible in most partition formats.

	-hpa

hdparm-9.12 released

From: Mark Lord <hidden>
Date: 2009-02-26 18:22:21

hdparm-9.12 is now available for download from sourceforge.net.

Changes from 9.11 include:
  - added logical/physical sector size reporting
  - updated -I output with SATA-2.6 additions
  - support APM level retrieval with -B flag
  - updated -C output to match ATA8
  - added "form factor" and "rotation" display to -I,
         courtesy of Martin K.Petersen.

Cheers
-- 
Mark Lord
Real-Time Remedies Inc.
mlord@pobox.com
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help