libata: support host-aware and host-managed ZAC devices
Byte 69 bits 0:1 in the IDENTIFY DEVICE data indicate a host-aware ZAC device. Host-managed ZAC devices have their own individual signature, and to not set the bits in the IDENTIFY DEVICE data. And whenever we detect a ZAC-compatible device we should be displaying the zoned block characteristics VPD page. Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
Родитель
856c466393
Коммит
6d1003ae8d
|
@ -2227,6 +2227,99 @@ static void ata_dev_config_sense_reporting(struct ata_device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static void ata_dev_config_zac(struct ata_device *dev)
|
||||
{
|
||||
struct ata_port *ap = dev->link->ap;
|
||||
unsigned int err_mask;
|
||||
u8 *identify_buf = ap->sector_buf;
|
||||
int log_index = ATA_LOG_SATA_ID_DEV_DATA * 2, i, found = 0;
|
||||
u16 log_pages;
|
||||
|
||||
dev->zac_zones_optimal_open = U32_MAX;
|
||||
dev->zac_zones_optimal_nonseq = U32_MAX;
|
||||
dev->zac_zones_max_open = U32_MAX;
|
||||
|
||||
/*
|
||||
* Always set the 'ZAC' flag for Host-managed devices.
|
||||
*/
|
||||
if (dev->class == ATA_DEV_ZAC)
|
||||
dev->flags |= ATA_DFLAG_ZAC;
|
||||
else if (ata_id_zoned_cap(dev->id) == 0x01)
|
||||
/*
|
||||
* Check for host-aware devices.
|
||||
*/
|
||||
dev->flags |= ATA_DFLAG_ZAC;
|
||||
|
||||
if (!(dev->flags & ATA_DFLAG_ZAC))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Read Log Directory to figure out if IDENTIFY DEVICE log
|
||||
* is supported.
|
||||
*/
|
||||
err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY,
|
||||
0, ap->sector_buf, 1);
|
||||
if (err_mask) {
|
||||
ata_dev_info(dev,
|
||||
"failed to get Log Directory Emask 0x%x\n",
|
||||
err_mask);
|
||||
return;
|
||||
}
|
||||
log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
|
||||
if (log_pages == 0) {
|
||||
ata_dev_warn(dev,
|
||||
"ATA Identify Device Log not supported\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Read IDENTIFY DEVICE data log, page 0, to figure out
|
||||
* if page 9 is supported.
|
||||
*/
|
||||
err_mask = ata_read_log_page(dev, ATA_LOG_SATA_ID_DEV_DATA, 0,
|
||||
identify_buf, 1);
|
||||
if (err_mask) {
|
||||
ata_dev_info(dev,
|
||||
"failed to get Device Identify Log Emask 0x%x\n",
|
||||
err_mask);
|
||||
return;
|
||||
}
|
||||
log_pages = identify_buf[8];
|
||||
for (i = 0; i < log_pages; i++) {
|
||||
if (identify_buf[9 + i] == ATA_LOG_ZONED_INFORMATION) {
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ata_dev_warn(dev,
|
||||
"ATA Zoned Information Log not supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read IDENTIFY DEVICE data log, page 9 (Zoned-device information)
|
||||
*/
|
||||
err_mask = ata_read_log_page(dev, ATA_LOG_SATA_ID_DEV_DATA,
|
||||
ATA_LOG_ZONED_INFORMATION,
|
||||
identify_buf, 1);
|
||||
if (!err_mask) {
|
||||
u64 zoned_cap, opt_open, opt_nonseq, max_open;
|
||||
|
||||
zoned_cap = get_unaligned_le64(&identify_buf[8]);
|
||||
if ((zoned_cap >> 63))
|
||||
dev->zac_zoned_cap = (zoned_cap & 1);
|
||||
opt_open = get_unaligned_le64(&identify_buf[24]);
|
||||
if ((opt_open >> 63))
|
||||
dev->zac_zones_optimal_open = (u32)opt_open;
|
||||
opt_nonseq = get_unaligned_le64(&identify_buf[32]);
|
||||
if ((opt_nonseq >> 63))
|
||||
dev->zac_zones_optimal_nonseq = (u32)opt_nonseq;
|
||||
max_open = get_unaligned_le64(&identify_buf[40]);
|
||||
if ((max_open >> 63))
|
||||
dev->zac_zones_max_open = (u32)max_open;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_dev_configure - Configure the specified ATA/ATAPI device
|
||||
* @dev: Target device to configure
|
||||
|
@ -2450,6 +2543,7 @@ int ata_dev_configure(struct ata_device *dev)
|
|||
}
|
||||
}
|
||||
ata_dev_config_sense_reporting(dev);
|
||||
ata_dev_config_zac(dev);
|
||||
dev->cdb_len = 16;
|
||||
}
|
||||
|
||||
|
|
|
@ -2144,6 +2144,7 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
|
|||
*/
|
||||
static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)
|
||||
{
|
||||
int num_pages;
|
||||
const u8 pages[] = {
|
||||
0x00, /* page 0x00, this page */
|
||||
0x80, /* page 0x80, unit serial no page */
|
||||
|
@ -2152,10 +2153,14 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)
|
|||
0xb0, /* page 0xb0, block limits page */
|
||||
0xb1, /* page 0xb1, block device characteristics page */
|
||||
0xb2, /* page 0xb2, thin provisioning page */
|
||||
0xb6, /* page 0xb6, zoned block device characteristics */
|
||||
};
|
||||
|
||||
rbuf[3] = sizeof(pages); /* number of supported VPD pages */
|
||||
memcpy(rbuf + 4, pages, sizeof(pages));
|
||||
num_pages = sizeof(pages);
|
||||
if (!(args->dev->flags & ATA_DFLAG_ZAC))
|
||||
num_pages--;
|
||||
rbuf[3] = num_pages; /* number of supported VPD pages */
|
||||
memcpy(rbuf + 4, pages, num_pages);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2343,6 +2348,26 @@ static unsigned int ata_scsiop_inq_b2(struct ata_scsi_args *args, u8 *rbuf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int ata_scsiop_inq_b6(struct ata_scsi_args *args, u8 *rbuf)
|
||||
{
|
||||
/*
|
||||
* zbc-r05 SCSI Zoned Block device characteristics VPD page
|
||||
*/
|
||||
rbuf[1] = 0xb6;
|
||||
rbuf[3] = 0x3C;
|
||||
|
||||
/*
|
||||
* URSWRZ bit is only meaningful for host-managed ZAC drives
|
||||
*/
|
||||
if (args->dev->zac_zoned_cap & 1)
|
||||
rbuf[4] |= 1;
|
||||
put_unaligned_be32(args->dev->zac_zones_optimal_open, &rbuf[8]);
|
||||
put_unaligned_be32(args->dev->zac_zones_optimal_nonseq, &rbuf[12]);
|
||||
put_unaligned_be32(args->dev->zac_zones_max_open, &rbuf[16]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_scsiop_noop - Command handler that simply returns success.
|
||||
* @args: device IDENTIFY data / SCSI command of interest.
|
||||
|
@ -2661,6 +2686,9 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
|
|||
rbuf[14] |= 0x40; /* LBPRZ */
|
||||
}
|
||||
}
|
||||
if (ata_id_zoned_cap(args->id) ||
|
||||
args->dev->class == ATA_DEV_ZAC)
|
||||
rbuf[12] = (1 << 4); /* RC_BASIS */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -4046,6 +4074,12 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
|
|||
case 0xb2:
|
||||
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2);
|
||||
break;
|
||||
case 0xb6:
|
||||
if (dev->flags & ATA_DFLAG_ZAC) {
|
||||
ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b6);
|
||||
break;
|
||||
}
|
||||
/* Fallthrough */
|
||||
default:
|
||||
ata_scsi_invalid_field(dev, cmd, 2);
|
||||
break;
|
||||
|
|
|
@ -338,6 +338,7 @@ enum {
|
|||
ATA_LOG_NCQ_SEND_RECV = 0x13,
|
||||
ATA_LOG_SATA_ID_DEV_DATA = 0x30,
|
||||
ATA_LOG_SATA_SETTINGS = 0x08,
|
||||
ATA_LOG_ZONED_INFORMATION = 0x09,
|
||||
ATA_LOG_DEVSLP_OFFSET = 0x30,
|
||||
ATA_LOG_DEVSLP_SIZE = 0x08,
|
||||
ATA_LOG_DEVSLP_MDAT = 0x00,
|
||||
|
|
|
@ -181,6 +181,7 @@ enum {
|
|||
ATA_DFLAG_DEVSLP = (1 << 27), /* device supports Device Sleep */
|
||||
ATA_DFLAG_ACPI_DISABLED = (1 << 28), /* ACPI for the device is disabled */
|
||||
ATA_DFLAG_D_SENSE = (1 << 29), /* Descriptor sense requested */
|
||||
ATA_DFLAG_ZAC = (1 << 30), /* ZAC device */
|
||||
|
||||
ATA_DEV_UNKNOWN = 0, /* unknown device */
|
||||
ATA_DEV_ATA = 1, /* ATA device */
|
||||
|
@ -731,6 +732,12 @@ struct ata_device {
|
|||
u8 ncq_send_recv_cmds[ATA_LOG_NCQ_SEND_RECV_SIZE];
|
||||
u8 ncq_non_data_cmds[ATA_LOG_NCQ_NON_DATA_SIZE];
|
||||
|
||||
/* ZAC zone configuration */
|
||||
u32 zac_zoned_cap;
|
||||
u32 zac_zones_optimal_open;
|
||||
u32 zac_zones_optimal_nonseq;
|
||||
u32 zac_zones_max_open;
|
||||
|
||||
/* error history */
|
||||
int spdn_cnt;
|
||||
/* ering is CLEAR_END, read comment above CLEAR_END */
|
||||
|
|
Загрузка…
Ссылка в новой задаче