* [PATCH] V2 2.6.35 libata support for > 512 byte sectors (e.g. 4K Native)
@ 2010-08-17 17:56 Grant Grundler
2010-08-18 15:04 ` Arnd Bergmann
0 siblings, 1 reply; 4+ messages in thread
From: Grant Grundler @ 2010-08-17 17:56 UTC (permalink / raw)
To: Jeff Garzik, Tejun Heo
Cc: Linux IDE, Gwendal Grignou, LKML, Matthew Wilcox, Matthew Wilcox
[-- Attachment #1: Type: text/plain, Size: 1727 bytes --]
Attached patch enables my x86 machine to recognize and talk to a
"Native 4K" SATA device.
When I started working on this, I didn't know Matthew Wilcox had
posted a similar patch 2 years ago:
http://git.kernel.org/?p=linux/kernel/git/willy/ata.git;a=shortlog;h=refs/heads/ata-large-sectors
Gwendal Grignou pointed me at the the above code and small portions of
this patch include Matthew's work. That's why Mathew is first on the
"Signed-off-by:". I've NOT included his use of a bitmap to determine
512 vs Native for ATA command block size - just used a simple table.
And bugs are almost certainly mine.
Lastly, the patch has been tested with a native 4K 'Engineering
Sample' drive provided by Hitachi GST.
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Signed-off-by: Grant Grundler <grundler@google.com>
Reviewed-by: Gwendal Grignou <gwendal@google.com>
----
V1: Gwendal reviewed had concerns about dev->sdev->sector_size which
seems to be ok.
V2: Matthew Wilcox suggested:
o remove comment about Big Endian (already handled)
o use "scmd->device->sector_size" instead of "dev->sdev->sector_size"
o ata_cmd_ioctl() does PIO data IN and thus should use native size.
o add "safe for large sectors" flag in the case that a
controller can't tolerate >512byte sector commands.
I did NOT add such a flag since I think the right answer would
be "Don't attach a Native 4K block device to that controller" - it
just won't work.
Tejun Heo (and I) prefer to leave ata_cmd_ioctl() hard coded to
512 byte since this ioctl is "should probably be deprecated one day".
thanks,
grant
[ patch NOT inlined because gmail will word-wrap and make a mess of
it. Please use attached file.]
[-- Attachment #2: 2.6.35-libata_4k_block_support-02 --]
[-- Type: application/octet-stream, Size: 8499 bytes --]
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index a54273d..d108ab9 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -52,7 +52,6 @@
#include "libata.h"
-#define SECTOR_SIZE 512
#define ATA_SCSI_RBUF_SIZE 4096
static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
@@ -516,7 +515,7 @@ 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];
+ argsize = ATA_SECT_SIZE * args[3];
argbuf = kmalloc(argsize, GFP_KERNEL);
if (argbuf == NULL) {
rc = -ENOMEM;
@@ -1150,8 +1149,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
} else {
/* ATA devices must be sector aligned */
+ sdev->sector_size = ata_id_logical_sector_size(dev->id);
blk_queue_update_dma_alignment(sdev->request_queue,
- ATA_SECT_SIZE - 1);
+ sdev->sector_size - 1);
sdev->manage_start_stop = 1;
}
@@ -1166,6 +1166,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
}
+ dev->sdev = sdev;
return 0;
}
@@ -1696,7 +1697,7 @@ 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 * scmd->device->sector_size;
rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags,
qc->tag);
@@ -2123,7 +2124,7 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
{
- u32 min_io_sectors;
+ u16 min_io_sectors;
rbuf[1] = 0xb0;
rbuf[3] = 0x3c; /* required VPD size with unmap support */
@@ -2135,10 +2136,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
* logical than physical sector size we need to figure out what the
* latter is.
*/
- if (ata_id_has_large_logical_sectors(args->id))
- min_io_sectors = ata_id_logical_per_physical_sectors(args->id);
- else
- min_io_sectors = 1;
+ min_io_sectors = 1 << ata_id_log2_per_physical_sector(args->id);
put_unaligned_be16(min_io_sectors, &rbuf[6]);
/*
@@ -2397,21 +2395,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
{
struct ata_device *dev = args->dev;
u64 last_lba = dev->n_sectors - 1; /* LBA of the last block */
- u8 log_per_phys = 0;
- u16 lowest_aligned = 0;
- u16 word_106 = dev->id[106];
- u16 word_209 = dev->id[209];
-
- 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 ((word_209 & 0xc000) == 0x4000) {
- u16 first = dev->id[209] & 0x3fff;
- if (first > 0)
- lowest_aligned = (1 << log_per_phys) - first;
- }
- }
+ u32 sector_size; /* physical sector size in bytes */
+ u8 log2_per_phys;
+ u16 lowest_aligned;
+
+ sector_size = ata_id_logical_sector_size(dev->id);
+ log2_per_phys = ata_id_log2_per_physical_sector(dev->id);
+ lowest_aligned = ata_id_logical_sector_offset(dev->id, log2_per_phys);
VPRINTK("ENTER\n");
@@ -2426,8 +2416,10 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
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);
@@ -2440,11 +2432,13 @@ 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[13] = log2_per_phys;
rbuf[14] = (lowest_aligned >> 8) & 0x3f;
rbuf[15] = lowest_aligned;
@@ -2888,9 +2882,8 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
tf->device = dev->devno ?
tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
- /* READ/WRITE LONG use a non-standard sect_size */
- qc->sect_size = ATA_SECT_SIZE;
switch (tf->command) {
+ /* READ/WRITE LONG use a non-standard sect_size */
case ATA_CMD_READ_LONG:
case ATA_CMD_READ_LONG_ONCE:
case ATA_CMD_WRITE_LONG:
@@ -2898,6 +2891,45 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
goto invalid_fld;
qc->sect_size = scsi_bufflen(scmd);
+ break;
+
+ /* commands using reported Logical Block size (e.g. 512 or 4K) */
+ case ATA_CMD_CFA_WRITE_NE:
+ case ATA_CMD_CFA_TRANS_SECT:
+ case ATA_CMD_CFA_WRITE_MULT_NE:
+ /* XXX: case ATA_CMD_CFA_WRITE_SECTORS_WITHOUT_ERASE: */
+ case ATA_CMD_READ:
+ case ATA_CMD_READ_EXT:
+ case ATA_CMD_READ_QUEUED:
+ /* XXX: case ATA_CMD_READ_QUEUED_EXT: */
+ case ATA_CMD_FPDMA_READ:
+ case ATA_CMD_READ_MULTI:
+ case ATA_CMD_READ_MULTI_EXT:
+ case ATA_CMD_PIO_READ:
+ case ATA_CMD_PIO_READ_EXT:
+ case ATA_CMD_READ_STREAM_DMA_EXT:
+ case ATA_CMD_READ_STREAM_EXT:
+ case ATA_CMD_VERIFY:
+ case ATA_CMD_VERIFY_EXT:
+ case ATA_CMD_WRITE:
+ case ATA_CMD_WRITE_EXT:
+ case ATA_CMD_WRITE_FUA_EXT:
+ case ATA_CMD_WRITE_QUEUED:
+ case ATA_CMD_WRITE_QUEUED_FUA_EXT:
+ case ATA_CMD_FPDMA_WRITE:
+ case ATA_CMD_WRITE_MULTI:
+ case ATA_CMD_WRITE_MULTI_EXT:
+ case ATA_CMD_WRITE_MULTI_FUA_EXT:
+ case ATA_CMD_PIO_WRITE:
+ case ATA_CMD_PIO_WRITE_EXT:
+ case ATA_CMD_WRITE_STREAM_DMA_EXT:
+ case ATA_CMD_WRITE_STREAM_EXT:
+ qc->sect_size = scmd->device->sector_size;
+ break;
+
+ /* Everything else uses 512 byte "sectors" */
+ default:
+ qc->sect_size = ATA_SECT_SIZE;
}
/*
@@ -3393,6 +3425,8 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
if (!IS_ERR(sdev)) {
dev->sdev = sdev;
scsi_device_put(sdev);
+ } else {
+ dev->sdev = NULL;
}
}
}
diff --git a/include/linux/ata.h b/include/linux/ata.h
index fe6e681..0c4929f 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -89,6 +89,7 @@ enum {
ATA_ID_SPG = 98,
ATA_ID_LBA_CAPACITY_2 = 100,
ATA_ID_SECTOR_SIZE = 106,
+ ATA_ID_LOGICAL_SECTOR_SIZE = 117, /* and 118 */
ATA_ID_LAST_LUN = 126,
ATA_ID_DLF = 128,
ATA_ID_CSFO = 129,
@@ -640,16 +641,49 @@ static inline int ata_id_flush_ext_enabled(const u16 *id)
return (id[ATA_ID_CFS_ENABLE_2] & 0x2400) == 0x2400;
}
-static inline int ata_id_has_large_logical_sectors(const u16 *id)
+static inline u32 ata_id_logical_sector_size(const u16 *id)
{
- if ((id[ATA_ID_SECTOR_SIZE] & 0xc000) != 0x4000)
- return 0;
- return id[ATA_ID_SECTOR_SIZE] & (1 << 13);
+ /* T13/1699-D Revision 6a, Sep 6, 2008. Page 128.
+ * IDENTIFY DEVICE data, word 117-118.
+ * 0xd000 ignores bit 13 (logical:physical > 1)
+ */
+ if ((id[ATA_ID_SECTOR_SIZE] & 0xd000) == 0x5000)
+ return (((id[ATA_ID_LOGICAL_SECTOR_SIZE+1] << 16)
+ + id[ATA_ID_LOGICAL_SECTOR_SIZE]) * sizeof(u16)) ;
+ return ATA_SECT_SIZE;
+}
+
+static inline u8 ata_id_log2_per_physical_sector(const u16 *id)
+{
+ /* T13/1699-D Revision 6a, Sep 6, 2008. Page 128.
+ * IDENTIFY DEVICE data, word 106.
+ * 0xe000 ignores bit 12 (logical sector > 512 bytes)
+ */
+ if ((id[ATA_ID_SECTOR_SIZE] & 0xe000) == 0x6000)
+ return (id[ATA_ID_SECTOR_SIZE] & 0xf);
+ return 0;
}
-static inline u16 ata_id_logical_per_physical_sectors(const u16 *id)
+/* Offset of logical sectors relative to physical sectors.
+ *
+ * If device has more than one logical sector per physical sector
+ * (aka 512 byte emulation), vendors might offset the "sector 0" address
+ * so sector 63 is "naturally aligned" - e.g. FAT partition table.
+ * This avoids Read/Mod/Write penalties when using FAT partition table
+ * and updating "well aligned" (FS perspective) physical sectors on every
+ * transaction.
+ */
+static inline u16 ata_id_logical_sector_offset(const u16 *id,
+ u8 log2_per_phys)
{
- return 1 << (id[ATA_ID_SECTOR_SIZE] & 0xf);
+ u16 word_209 = id[209];
+
+ if ((log2_per_phys > 1) && (word_209 & 0xc000) == 0x4000) {
+ u16 first = word_209 & 0x3fff;
+ if (first > 0)
+ return (1 << log2_per_phys) - first;
+ }
+ return 0;
}
static inline int ata_id_has_lba48(const u16 *id)
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] V2 2.6.35 libata support for > 512 byte sectors (e.g. 4K Native)
2010-08-17 17:56 [PATCH] V2 2.6.35 libata support for > 512 byte sectors (e.g. 4K Native) Grant Grundler
@ 2010-08-18 15:04 ` Arnd Bergmann
2010-08-18 15:30 ` Christoph Hellwig
0 siblings, 1 reply; 4+ messages in thread
From: Arnd Bergmann @ 2010-08-18 15:04 UTC (permalink / raw)
To: Grant Grundler
Cc: Jeff Garzik, Tejun Heo, Linux IDE, Gwendal Grignou, LKML,
Matthew Wilcox, Matthew Wilcox
On Tuesday 17 August 2010, Grant Grundler wrote:
> [ patch NOT inlined because gmail will word-wrap and make a mess of
> it. Please use attached file.]
You should be able to use git-send-email with a gmail account to fix this.
Arnd
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] V2 2.6.35 libata support for > 512 byte sectors (e.g. 4K Native)
2010-08-18 15:04 ` Arnd Bergmann
@ 2010-08-18 15:30 ` Christoph Hellwig
2010-08-18 16:36 ` Grant Grundler
0 siblings, 1 reply; 4+ messages in thread
From: Christoph Hellwig @ 2010-08-18 15:30 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Grant Grundler, Jeff Garzik, Tejun Heo, Linux IDE,
Gwendal Grignou, LKML, Matthew Wilcox, Matthew Wilcox
On Wed, Aug 18, 2010 at 05:04:51PM +0200, Arnd Bergmann wrote:
> On Tuesday 17 August 2010, Grant Grundler wrote:
> > [ patch NOT inlined because gmail will word-wrap and make a mess of
> > it. Please use attached file.]
>
> You should be able to use git-send-email with a gmail account to fix this.
Or find an google insider that could fix gmail..
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] V2 2.6.35 libata support for > 512 byte sectors (e.g. 4K Native)
2010-08-18 15:30 ` Christoph Hellwig
@ 2010-08-18 16:36 ` Grant Grundler
0 siblings, 0 replies; 4+ messages in thread
From: Grant Grundler @ 2010-08-18 16:36 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Arnd Bergmann, Jeff Garzik, Tejun Heo, Linux IDE,
Gwendal Grignou, LKML, Matthew Wilcox, Matthew Wilcox
On Wed, Aug 18, 2010 at 8:30 AM, Christoph Hellwig <hch@infradead.org> wrote:
> On Wed, Aug 18, 2010 at 05:04:51PM +0200, Arnd Bergmann wrote:
>> On Tuesday 17 August 2010, Grant Grundler wrote:
>> > [ patch NOT inlined because gmail will word-wrap and make a mess of
>> > it. Please use attached file.]
>>
>> You should be able to use git-send-email with a gmail account to fix this.
I'll try git-send-email next time - thanks Arndt.
> Or find an google insider that could fix gmail..
You have no idea how many people have already tried this. Just feels
like another windmill at this point. :)
thanks,
grant
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2010-08-18 16:36 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-17 17:56 [PATCH] V2 2.6.35 libata support for > 512 byte sectors (e.g. 4K Native) Grant Grundler
2010-08-18 15:04 ` Arnd Bergmann
2010-08-18 15:30 ` Christoph Hellwig
2010-08-18 16:36 ` Grant Grundler
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.