Skip to content

Commit 295124d

Browse files
Grant GrundlerJeff Garzik
authored andcommitted
[libata] support for > 512 byte sectors (e.g. 4K Native)
This change 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> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
1 parent 1aadf5c commit 295124d

File tree

2 files changed

+105
-37
lines changed

2 files changed

+105
-37
lines changed

drivers/ata/libata-scsi.c

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
#include "libata.h"
5454
#include "libata-transport.h"
5555

56-
#define SECTOR_SIZE 512
5756
#define ATA_SCSI_RBUF_SIZE 4096
5857

5958
static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
@@ -503,7 +502,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
503502
memset(scsi_cmd, 0, sizeof(scsi_cmd));
504503

505504
if (args[3]) {
506-
argsize = SECTOR_SIZE * args[3];
505+
argsize = ATA_SECT_SIZE * args[3];
507506
argbuf = kmalloc(argsize, GFP_KERNEL);
508507
if (argbuf == NULL) {
509508
rc = -ENOMEM;
@@ -1137,8 +1136,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
11371136
blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
11381137
} else {
11391138
/* ATA devices must be sector aligned */
1139+
sdev->sector_size = ata_id_logical_sector_size(dev->id);
11401140
blk_queue_update_dma_alignment(sdev->request_queue,
1141-
ATA_SECT_SIZE - 1);
1141+
sdev->sector_size - 1);
11421142
sdev->manage_start_stop = 1;
11431143
}
11441144

@@ -1153,6 +1153,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
11531153
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
11541154
}
11551155

1156+
dev->sdev = sdev;
11561157
return 0;
11571158
}
11581159

@@ -1683,7 +1684,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
16831684
goto nothing_to_do;
16841685

16851686
qc->flags |= ATA_QCFLAG_IO;
1686-
qc->nbytes = n_block * ATA_SECT_SIZE;
1687+
qc->nbytes = n_block * scmd->device->sector_size;
16871688

16881689
rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags,
16891690
qc->tag);
@@ -2110,7 +2111,7 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
21102111

21112112
static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
21122113
{
2113-
u32 min_io_sectors;
2114+
u16 min_io_sectors;
21142115

21152116
rbuf[1] = 0xb0;
21162117
rbuf[3] = 0x3c; /* required VPD size with unmap support */
@@ -2122,10 +2123,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
21222123
* logical than physical sector size we need to figure out what the
21232124
* latter is.
21242125
*/
2125-
if (ata_id_has_large_logical_sectors(args->id))
2126-
min_io_sectors = ata_id_logical_per_physical_sectors(args->id);
2127-
else
2128-
min_io_sectors = 1;
2126+
min_io_sectors = 1 << ata_id_log2_per_physical_sector(args->id);
21292127
put_unaligned_be16(min_io_sectors, &rbuf[6]);
21302128

21312129
/*
@@ -2384,21 +2382,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
23842382
{
23852383
struct ata_device *dev = args->dev;
23862384
u64 last_lba = dev->n_sectors - 1; /* LBA of the last block */
2387-
u8 log_per_phys = 0;
2388-
u16 lowest_aligned = 0;
2389-
u16 word_106 = dev->id[106];
2390-
u16 word_209 = dev->id[209];
2391-
2392-
if ((word_106 & 0xc000) == 0x4000) {
2393-
/* Number and offset of logical sectors per physical sector */
2394-
if (word_106 & (1 << 13))
2395-
log_per_phys = word_106 & 0xf;
2396-
if ((word_209 & 0xc000) == 0x4000) {
2397-
u16 first = dev->id[209] & 0x3fff;
2398-
if (first > 0)
2399-
lowest_aligned = (1 << log_per_phys) - first;
2400-
}
2401-
}
2385+
u32 sector_size; /* physical sector size in bytes */
2386+
u8 log2_per_phys;
2387+
u16 lowest_aligned;
2388+
2389+
sector_size = ata_id_logical_sector_size(dev->id);
2390+
log2_per_phys = ata_id_log2_per_physical_sector(dev->id);
2391+
lowest_aligned = ata_id_logical_sector_offset(dev->id, log2_per_phys);
24022392

24032393
VPRINTK("ENTER\n");
24042394

@@ -2413,8 +2403,10 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
24132403
rbuf[3] = last_lba;
24142404

24152405
/* sector size */
2416-
rbuf[6] = ATA_SECT_SIZE >> 8;
2417-
rbuf[7] = ATA_SECT_SIZE & 0xff;
2406+
rbuf[4] = sector_size >> (8 * 3);
2407+
rbuf[5] = sector_size >> (8 * 2);
2408+
rbuf[6] = sector_size >> (8 * 1);
2409+
rbuf[7] = sector_size;
24182410
} else {
24192411
/* sector count, 64-bit */
24202412
rbuf[0] = last_lba >> (8 * 7);
@@ -2427,11 +2419,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
24272419
rbuf[7] = last_lba;
24282420

24292421
/* sector size */
2430-
rbuf[10] = ATA_SECT_SIZE >> 8;
2431-
rbuf[11] = ATA_SECT_SIZE & 0xff;
2422+
rbuf[ 8] = sector_size >> (8 * 3);
2423+
rbuf[ 9] = sector_size >> (8 * 2);
2424+
rbuf[10] = sector_size >> (8 * 1);
2425+
rbuf[11] = sector_size;
24322426

24332427
rbuf[12] = 0;
2434-
rbuf[13] = log_per_phys;
2428+
rbuf[13] = log2_per_phys;
24352429
rbuf[14] = (lowest_aligned >> 8) & 0x3f;
24362430
rbuf[15] = lowest_aligned;
24372431

@@ -2875,16 +2869,54 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
28752869
tf->device = dev->devno ?
28762870
tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
28772871

2878-
/* READ/WRITE LONG use a non-standard sect_size */
2879-
qc->sect_size = ATA_SECT_SIZE;
28802872
switch (tf->command) {
2873+
/* READ/WRITE LONG use a non-standard sect_size */
28812874
case ATA_CMD_READ_LONG:
28822875
case ATA_CMD_READ_LONG_ONCE:
28832876
case ATA_CMD_WRITE_LONG:
28842877
case ATA_CMD_WRITE_LONG_ONCE:
28852878
if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
28862879
goto invalid_fld;
28872880
qc->sect_size = scsi_bufflen(scmd);
2881+
break;
2882+
2883+
/* commands using reported Logical Block size (e.g. 512 or 4K) */
2884+
case ATA_CMD_CFA_WRITE_NE:
2885+
case ATA_CMD_CFA_TRANS_SECT:
2886+
case ATA_CMD_CFA_WRITE_MULT_NE:
2887+
/* XXX: case ATA_CMD_CFA_WRITE_SECTORS_WITHOUT_ERASE: */
2888+
case ATA_CMD_READ:
2889+
case ATA_CMD_READ_EXT:
2890+
case ATA_CMD_READ_QUEUED:
2891+
/* XXX: case ATA_CMD_READ_QUEUED_EXT: */
2892+
case ATA_CMD_FPDMA_READ:
2893+
case ATA_CMD_READ_MULTI:
2894+
case ATA_CMD_READ_MULTI_EXT:
2895+
case ATA_CMD_PIO_READ:
2896+
case ATA_CMD_PIO_READ_EXT:
2897+
case ATA_CMD_READ_STREAM_DMA_EXT:
2898+
case ATA_CMD_READ_STREAM_EXT:
2899+
case ATA_CMD_VERIFY:
2900+
case ATA_CMD_VERIFY_EXT:
2901+
case ATA_CMD_WRITE:
2902+
case ATA_CMD_WRITE_EXT:
2903+
case ATA_CMD_WRITE_FUA_EXT:
2904+
case ATA_CMD_WRITE_QUEUED:
2905+
case ATA_CMD_WRITE_QUEUED_FUA_EXT:
2906+
case ATA_CMD_FPDMA_WRITE:
2907+
case ATA_CMD_WRITE_MULTI:
2908+
case ATA_CMD_WRITE_MULTI_EXT:
2909+
case ATA_CMD_WRITE_MULTI_FUA_EXT:
2910+
case ATA_CMD_PIO_WRITE:
2911+
case ATA_CMD_PIO_WRITE_EXT:
2912+
case ATA_CMD_WRITE_STREAM_DMA_EXT:
2913+
case ATA_CMD_WRITE_STREAM_EXT:
2914+
qc->sect_size = scmd->device->sector_size;
2915+
break;
2916+
2917+
/* Everything else uses 512 byte "sectors" */
2918+
default:
2919+
qc->sect_size = ATA_SECT_SIZE;
28882920
}
28892921

28902922
/*
@@ -3380,6 +3412,8 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
33803412
if (!IS_ERR(sdev)) {
33813413
dev->sdev = sdev;
33823414
scsi_device_put(sdev);
3415+
} else {
3416+
dev->sdev = NULL;
33833417
}
33843418
}
33853419
}

include/linux/ata.h

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ enum {
8989
ATA_ID_SPG = 98,
9090
ATA_ID_LBA_CAPACITY_2 = 100,
9191
ATA_ID_SECTOR_SIZE = 106,
92+
ATA_ID_LOGICAL_SECTOR_SIZE = 117, /* and 118 */
9293
ATA_ID_LAST_LUN = 126,
9394
ATA_ID_DLF = 128,
9495
ATA_ID_CSFO = 129,
@@ -640,16 +641,49 @@ static inline int ata_id_flush_ext_enabled(const u16 *id)
640641
return (id[ATA_ID_CFS_ENABLE_2] & 0x2400) == 0x2400;
641642
}
642643

643-
static inline int ata_id_has_large_logical_sectors(const u16 *id)
644+
static inline u32 ata_id_logical_sector_size(const u16 *id)
644645
{
645-
if ((id[ATA_ID_SECTOR_SIZE] & 0xc000) != 0x4000)
646-
return 0;
647-
return id[ATA_ID_SECTOR_SIZE] & (1 << 13);
646+
/* T13/1699-D Revision 6a, Sep 6, 2008. Page 128.
647+
* IDENTIFY DEVICE data, word 117-118.
648+
* 0xd000 ignores bit 13 (logical:physical > 1)
649+
*/
650+
if ((id[ATA_ID_SECTOR_SIZE] & 0xd000) == 0x5000)
651+
return (((id[ATA_ID_LOGICAL_SECTOR_SIZE+1] << 16)
652+
+ id[ATA_ID_LOGICAL_SECTOR_SIZE]) * sizeof(u16)) ;
653+
return ATA_SECT_SIZE;
654+
}
655+
656+
static inline u8 ata_id_log2_per_physical_sector(const u16 *id)
657+
{
658+
/* T13/1699-D Revision 6a, Sep 6, 2008. Page 128.
659+
* IDENTIFY DEVICE data, word 106.
660+
* 0xe000 ignores bit 12 (logical sector > 512 bytes)
661+
*/
662+
if ((id[ATA_ID_SECTOR_SIZE] & 0xe000) == 0x6000)
663+
return (id[ATA_ID_SECTOR_SIZE] & 0xf);
664+
return 0;
648665
}
649666

650-
static inline u16 ata_id_logical_per_physical_sectors(const u16 *id)
667+
/* Offset of logical sectors relative to physical sectors.
668+
*
669+
* If device has more than one logical sector per physical sector
670+
* (aka 512 byte emulation), vendors might offset the "sector 0" address
671+
* so sector 63 is "naturally aligned" - e.g. FAT partition table.
672+
* This avoids Read/Mod/Write penalties when using FAT partition table
673+
* and updating "well aligned" (FS perspective) physical sectors on every
674+
* transaction.
675+
*/
676+
static inline u16 ata_id_logical_sector_offset(const u16 *id,
677+
u8 log2_per_phys)
651678
{
652-
return 1 << (id[ATA_ID_SECTOR_SIZE] & 0xf);
679+
u16 word_209 = id[209];
680+
681+
if ((log2_per_phys > 1) && (word_209 & 0xc000) == 0x4000) {
682+
u16 first = word_209 & 0x3fff;
683+
if (first > 0)
684+
return (1 << log2_per_phys) - first;
685+
}
686+
return 0;
653687
}
654688

655689
static inline int ata_id_has_lba48(const u16 *id)

0 commit comments

Comments
 (0)