Skip to content

Commit 602bcf2

Browse files
committed
ata: libata: Improve CDL resource management
The ncq_sense_buf buffer field of struct ata_port is allocated and used only for devices that support the Command Duration Limits (CDL) feature. However, the cdl buffer of struct ata_device, which is used to cache the command duration limits log page for devices supporting CDL is always allocated as part of struct ata_device, which is wasteful of memory for devices that do not support this feature. Clean this up by defining both buffers as part of the new ata_cdl structure and allocating this structure only for devices that support the CDL feature. This new structure is attached to struct ata_device using the cdl pointer. The functions ata_dev_init_cdl_resources() and ata_dev_cleanup_cdl_resources() are defined to manage this new structure allocation, initialization and freeing when a port is removed or a device disabled. ata_dev_init_cdl_resources() is called from ata_dev_config_cdl() only for devices that support CDL. ata_dev_cleanup_cdl_resources() is called from ata_dev_free_resources() to free the ata_cdl structure when a device is being disabled by EH. Note that the name of the former cdl log buffer of struct ata_device is changed to desc_log_buf to make it clearer that it is a buffer for the limit descriptors log page. This change reduces the size of struct ata_device, thus reducing memory usage for ATA devices that do not support the CDL feature. Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Niklas Cassel <[email protected]>
1 parent 5f8319c commit 602bcf2

File tree

5 files changed

+57
-30
lines changed

5 files changed

+57
-30
lines changed

drivers/ata/libata-core.c

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2464,12 +2464,41 @@ static void ata_dev_config_trusted(struct ata_device *dev)
24642464
dev->flags |= ATA_DFLAG_TRUSTED;
24652465
}
24662466

2467+
void ata_dev_cleanup_cdl_resources(struct ata_device *dev)
2468+
{
2469+
kfree(dev->cdl);
2470+
dev->cdl = NULL;
2471+
}
2472+
2473+
static int ata_dev_init_cdl_resources(struct ata_device *dev)
2474+
{
2475+
struct ata_cdl *cdl = dev->cdl;
2476+
unsigned int err_mask;
2477+
2478+
if (!cdl) {
2479+
cdl = kzalloc(sizeof(*cdl), GFP_KERNEL);
2480+
if (!cdl)
2481+
return -ENOMEM;
2482+
dev->cdl = cdl;
2483+
}
2484+
2485+
err_mask = ata_read_log_page(dev, ATA_LOG_CDL, 0, cdl->desc_log_buf,
2486+
ATA_LOG_CDL_SIZE / ATA_SECT_SIZE);
2487+
if (err_mask) {
2488+
ata_dev_warn(dev, "Read Command Duration Limits log failed\n");
2489+
ata_dev_cleanup_cdl_resources(dev);
2490+
return -EIO;
2491+
}
2492+
2493+
return 0;
2494+
}
2495+
24672496
static void ata_dev_config_cdl(struct ata_device *dev)
24682497
{
2469-
struct ata_port *ap = dev->link->ap;
24702498
unsigned int err_mask;
24712499
bool cdl_enabled;
24722500
u64 val;
2501+
int ret;
24732502

24742503
if (ata_id_major_version(dev->id) < 11)
24752504
goto not_supported;
@@ -2564,37 +2593,20 @@ static void ata_dev_config_cdl(struct ata_device *dev)
25642593
}
25652594
}
25662595

2567-
/*
2568-
* Allocate a buffer to handle reading the sense data for successful
2569-
* NCQ Commands log page for commands using a CDL with one of the limit
2570-
* policy set to 0xD (successful completion with sense data available
2571-
* bit set).
2572-
*/
2573-
if (!ap->ncq_sense_buf) {
2574-
ap->ncq_sense_buf = kmalloc(ATA_LOG_SENSE_NCQ_SIZE, GFP_KERNEL);
2575-
if (!ap->ncq_sense_buf)
2576-
goto not_supported;
2577-
}
2578-
2579-
/*
2580-
* Command duration limits is supported: cache the CDL log page 18h
2581-
* (command duration descriptors).
2582-
*/
2583-
err_mask = ata_read_log_page(dev, ATA_LOG_CDL, 0, dev->sector_buf, 1);
2584-
if (err_mask) {
2585-
ata_dev_warn(dev, "Read Command Duration Limits log failed\n");
2596+
/* CDL is supported: allocate and initialize needed resources. */
2597+
ret = ata_dev_init_cdl_resources(dev);
2598+
if (ret) {
2599+
ata_dev_warn(dev, "Initialize CDL resources failed\n");
25862600
goto not_supported;
25872601
}
25882602

2589-
memcpy(dev->cdl, dev->sector_buf, ATA_LOG_CDL_SIZE);
25902603
dev->flags |= ATA_DFLAG_CDL;
25912604

25922605
return;
25932606

25942607
not_supported:
25952608
dev->flags &= ~(ATA_DFLAG_CDL | ATA_DFLAG_CDL_ENABLED);
2596-
kfree(ap->ncq_sense_buf);
2597-
ap->ncq_sense_buf = NULL;
2609+
ata_dev_cleanup_cdl_resources(dev);
25982610
}
25992611

26002612
static int ata_dev_config_lba(struct ata_device *dev)
@@ -5451,7 +5463,6 @@ void ata_port_free(struct ata_port *ap)
54515463

54525464
kfree(ap->pmp_link);
54535465
kfree(ap->slave_link);
5454-
kfree(ap->ncq_sense_buf);
54555466
ida_free(&ata_ida, ap->print_id);
54565467
kfree(ap);
54575468
}
@@ -5989,6 +6000,8 @@ void ata_dev_free_resources(struct ata_device *dev)
59896000
{
59906001
if (zpodd_dev_enabled(dev))
59916002
zpodd_exit(dev);
6003+
6004+
ata_dev_cleanup_cdl_resources(dev);
59926005
}
59936006

59946007
/**

drivers/ata/libata-sata.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1505,7 +1505,7 @@ int ata_eh_get_ncq_success_sense(struct ata_link *link)
15051505
{
15061506
struct ata_device *dev = link->device;
15071507
struct ata_port *ap = dev->link->ap;
1508-
u8 *buf = ap->ncq_sense_buf;
1508+
u8 *buf = dev->cdl->ncq_sense_log_buf;
15091509
struct ata_queued_cmd *qc;
15101510
unsigned int err_mask, tag;
15111511
u8 *sense, sk = 0, asc = 0, ascq = 0;

drivers/ata/libata-scsi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2248,7 +2248,7 @@ static inline u16 ata_xlat_cdl_limit(u8 *buf)
22482248
static unsigned int ata_msense_control_spgt2(struct ata_device *dev, u8 *buf,
22492249
u8 spg)
22502250
{
2251-
u8 *b, *cdl = dev->cdl, *desc;
2251+
u8 *b, *cdl = dev->cdl->desc_log_buf, *desc;
22522252
u32 policy;
22532253
int i;
22542254

drivers/ata/libata.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
9090
extern const char *sata_spd_string(unsigned int spd);
9191
extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
9292
u8 page, void *buf, unsigned int sectors);
93+
void ata_dev_cleanup_cdl_resources(struct ata_device *dev);
9394

9495
#define to_ata_port(d) container_of(d, struct ata_port, tdev)
9596

include/linux/libata.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,21 @@ struct ata_cpr_log {
700700
struct ata_cpr cpr[] __counted_by(nr_cpr);
701701
};
702702

703+
struct ata_cdl {
704+
/*
705+
* Buffer to cache the CDL log page 18h (command duration descriptors)
706+
* for SCSI-ATA translation.
707+
*/
708+
u8 desc_log_buf[ATA_LOG_CDL_SIZE];
709+
710+
/*
711+
* Buffer to handle reading the sense data for successful NCQ Commands
712+
* log page for commands using a CDL with one of the limits policy set
713+
* to 0xD (successful completion with sense data available bit set).
714+
*/
715+
u8 ncq_sense_log_buf[ATA_LOG_SENSE_NCQ_SIZE];
716+
};
717+
703718
struct ata_device {
704719
struct ata_link *link;
705720
unsigned int devno; /* 0 or 1 */
@@ -762,8 +777,8 @@ struct ata_device {
762777
/* Concurrent positioning ranges */
763778
struct ata_cpr_log *cpr_log;
764779

765-
/* Command Duration Limits log support */
766-
u8 cdl[ATA_LOG_CDL_SIZE];
780+
/* Command Duration Limits support */
781+
struct ata_cdl *cdl;
767782

768783
/* error history */
769784
int spdn_cnt;
@@ -917,8 +932,6 @@ struct ata_port {
917932
#ifdef CONFIG_ATA_ACPI
918933
struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */
919934
#endif
920-
/* owned by EH */
921-
u8 *ncq_sense_buf;
922935
};
923936

924937
/* The following initializer overrides a method to NULL whether one of

0 commit comments

Comments
 (0)