Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fe22e1c

Browse files
damien-lemoalaxboe
authored andcommitted
libata: support concurrent positioning ranges log
Add support to discover if an ATA device supports the Concurrent Positioning Ranges data log (address 0x47), indicating that the device is capable of seeking to multiple different locations in parallel using multiple actuators serving different LBA ranges. Also add support to translate the concurrent positioning ranges log into its equivalent Concurrent Positioning Ranges VPD page B9h in libata-scsi.c. The format of the Concurrent Positioning Ranges Log is defined in ACS-5 r9. Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Martin K. Petersen <[email protected]> Reviewed-by: Keith Busch <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent e815d36 commit fe22e1c

File tree

4 files changed

+110
-11
lines changed

4 files changed

+110
-11
lines changed

drivers/ata/libata-core.c

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2459,18 +2459,70 @@ static void ata_dev_config_devslp(struct ata_device *dev)
24592459
}
24602460
}
24612461

2462+
static void ata_dev_config_cpr(struct ata_device *dev)
2463+
{
2464+
unsigned int err_mask;
2465+
size_t buf_len;
2466+
int i, nr_cpr = 0;
2467+
struct ata_cpr_log *cpr_log = NULL;
2468+
u8 *desc, *buf = NULL;
2469+
2470+
if (!ata_identify_page_supported(dev,
2471+
ATA_LOG_CONCURRENT_POSITIONING_RANGES))
2472+
goto out;
2473+
2474+
/*
2475+
* Read IDENTIFY DEVICE data log, page 0x47
2476+
* (concurrent positioning ranges). We can have at most 255 32B range
2477+
* descriptors plus a 64B header.
2478+
*/
2479+
buf_len = (64 + 255 * 32 + 511) & ~511;
2480+
buf = kzalloc(buf_len, GFP_KERNEL);
2481+
if (!buf)
2482+
goto out;
2483+
2484+
err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE,
2485+
ATA_LOG_CONCURRENT_POSITIONING_RANGES,
2486+
buf, buf_len >> 9);
2487+
if (err_mask)
2488+
goto out;
2489+
2490+
nr_cpr = buf[0];
2491+
if (!nr_cpr)
2492+
goto out;
2493+
2494+
cpr_log = kzalloc(struct_size(cpr_log, cpr, nr_cpr), GFP_KERNEL);
2495+
if (!cpr_log)
2496+
goto out;
2497+
2498+
cpr_log->nr_cpr = nr_cpr;
2499+
desc = &buf[64];
2500+
for (i = 0; i < nr_cpr; i++, desc += 32) {
2501+
cpr_log->cpr[i].num = desc[0];
2502+
cpr_log->cpr[i].num_storage_elements = desc[1];
2503+
cpr_log->cpr[i].start_lba = get_unaligned_le64(&desc[8]);
2504+
cpr_log->cpr[i].num_lbas = get_unaligned_le64(&desc[16]);
2505+
}
2506+
2507+
out:
2508+
swap(dev->cpr_log, cpr_log);
2509+
kfree(cpr_log);
2510+
kfree(buf);
2511+
}
2512+
24622513
static void ata_dev_print_features(struct ata_device *dev)
24632514
{
24642515
if (!(dev->flags & ATA_DFLAG_FEATURES_MASK))
24652516
return;
24662517

24672518
ata_dev_info(dev,
2468-
"Features:%s%s%s%s%s\n",
2519+
"Features:%s%s%s%s%s%s\n",
24692520
dev->flags & ATA_DFLAG_TRUSTED ? " Trust" : "",
24702521
dev->flags & ATA_DFLAG_DA ? " Dev-Attention" : "",
24712522
dev->flags & ATA_DFLAG_DEVSLP ? " Dev-Sleep" : "",
24722523
dev->flags & ATA_DFLAG_NCQ_SEND_RECV ? " NCQ-sndrcv" : "",
2473-
dev->flags & ATA_DFLAG_NCQ_PRIO ? " NCQ-prio" : "");
2524+
dev->flags & ATA_DFLAG_NCQ_PRIO ? " NCQ-prio" : "",
2525+
dev->cpr_log ? " CPR" : "");
24742526
}
24752527

24762528
/**
@@ -2634,6 +2686,7 @@ int ata_dev_configure(struct ata_device *dev)
26342686
ata_dev_config_sense_reporting(dev);
26352687
ata_dev_config_zac(dev);
26362688
ata_dev_config_trusted(dev);
2689+
ata_dev_config_cpr(dev);
26372690
dev->cdb_len = 32;
26382691

26392692
if (ata_msg_drv(ap) && print_info)

drivers/ata/libata-scsi.c

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1895,7 +1895,7 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
18951895
*/
18961896
static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)
18971897
{
1898-
int num_pages;
1898+
int i, num_pages = 0;
18991899
static const u8 pages[] = {
19001900
0x00, /* page 0x00, this page */
19011901
0x80, /* page 0x80, unit serial no page */
@@ -1905,13 +1905,17 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)
19051905
0xb1, /* page 0xb1, block device characteristics page */
19061906
0xb2, /* page 0xb2, thin provisioning page */
19071907
0xb6, /* page 0xb6, zoned block device characteristics */
1908+
0xb9, /* page 0xb9, concurrent positioning ranges */
19081909
};
19091910

1910-
num_pages = sizeof(pages);
1911-
if (!(args->dev->flags & ATA_DFLAG_ZAC))
1912-
num_pages--;
1911+
for (i = 0; i < sizeof(pages); i++) {
1912+
if (pages[i] == 0xb6 &&
1913+
!(args->dev->flags & ATA_DFLAG_ZAC))
1914+
continue;
1915+
rbuf[num_pages + 4] = pages[i];
1916+
num_pages++;
1917+
}
19131918
rbuf[3] = num_pages; /* number of supported VPD pages */
1914-
memcpy(rbuf + 4, pages, num_pages);
19151919
return 0;
19161920
}
19171921

@@ -2121,6 +2125,26 @@ static unsigned int ata_scsiop_inq_b6(struct ata_scsi_args *args, u8 *rbuf)
21212125
return 0;
21222126
}
21232127

2128+
static unsigned int ata_scsiop_inq_b9(struct ata_scsi_args *args, u8 *rbuf)
2129+
{
2130+
struct ata_cpr_log *cpr_log = args->dev->cpr_log;
2131+
u8 *desc = &rbuf[64];
2132+
int i;
2133+
2134+
/* SCSI Concurrent Positioning Ranges VPD page: SBC-5 rev 1 or later */
2135+
rbuf[1] = 0xb9;
2136+
put_unaligned_be16(64 + (int)cpr_log->nr_cpr * 32 - 4, &rbuf[3]);
2137+
2138+
for (i = 0; i < cpr_log->nr_cpr; i++, desc += 32) {
2139+
desc[0] = cpr_log->cpr[i].num;
2140+
desc[1] = cpr_log->cpr[i].num_storage_elements;
2141+
put_unaligned_be64(cpr_log->cpr[i].start_lba, &desc[8]);
2142+
put_unaligned_be64(cpr_log->cpr[i].num_lbas, &desc[16]);
2143+
}
2144+
2145+
return 0;
2146+
}
2147+
21242148
/**
21252149
* modecpy - Prepare response for MODE SENSE
21262150
* @dest: output buffer
@@ -4120,11 +4144,17 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
41204144
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2);
41214145
break;
41224146
case 0xb6:
4123-
if (dev->flags & ATA_DFLAG_ZAC) {
4147+
if (dev->flags & ATA_DFLAG_ZAC)
41244148
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b6);
4125-
break;
4126-
}
4127-
fallthrough;
4149+
else
4150+
ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
4151+
break;
4152+
case 0xb9:
4153+
if (dev->cpr_log)
4154+
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b9);
4155+
else
4156+
ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
4157+
break;
41284158
default:
41294159
ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
41304160
break;

include/linux/ata.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ enum {
329329
ATA_LOG_SECURITY = 0x06,
330330
ATA_LOG_SATA_SETTINGS = 0x08,
331331
ATA_LOG_ZONED_INFORMATION = 0x09,
332+
ATA_LOG_CONCURRENT_POSITIONING_RANGES = 0x47,
332333

333334
/* Identify device SATA settings log:*/
334335
ATA_LOG_DEVSLP_OFFSET = 0x30,

include/linux/libata.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,18 @@ struct ata_ering {
676676
struct ata_ering_entry ring[ATA_ERING_SIZE];
677677
};
678678

679+
struct ata_cpr {
680+
u8 num;
681+
u8 num_storage_elements;
682+
u64 start_lba;
683+
u64 num_lbas;
684+
};
685+
686+
struct ata_cpr_log {
687+
u8 nr_cpr;
688+
struct ata_cpr cpr[];
689+
};
690+
679691
struct ata_device {
680692
struct ata_link *link;
681693
unsigned int devno; /* 0 or 1 */
@@ -735,6 +747,9 @@ struct ata_device {
735747
u32 zac_zones_optimal_nonseq;
736748
u32 zac_zones_max_open;
737749

750+
/* Concurrent positioning ranges */
751+
struct ata_cpr_log *cpr_log;
752+
738753
/* error history */
739754
int spdn_cnt;
740755
/* ering is CLEAR_END, read comment above CLEAR_END */

0 commit comments

Comments
 (0)