linux-scsi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] libata: ZAC SATL implementation
@ 2015-03-31  8:52 Hannes Reinecke
  2015-03-31  8:52 ` [PATCH 1/3] libata: implement ZBC IN translation Hannes Reinecke
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Hannes Reinecke @ 2015-03-31  8:52 UTC (permalink / raw)
  To: Tejun Heo; +Cc: linux-ide, linux-scsi, Hannes Reinecke

Hi Tejun,

this patchset implements support for the new ZAC commands
'ZBC IN' and 'ZBC OUT', aka 'REPORT ZONES' and 'RESET WRITE POINTER'.
And some additional support bits for host-aware ZAC drives.

Hannes Reinecke (3):
  libata: implement ZBC IN translation
  libata: Implement ZBC OUT translation
  libata: support host-aware ZAC devices

 drivers/ata/libata-core.c     |  17 +++
 drivers/ata/libata-eh.c       |   2 +
 drivers/ata/libata-scsi.c     | 252 +++++++++++++++++++++++++++++++++++++++++-
 include/linux/ata.h           |  16 +++
 include/linux/libata.h        |   1 +
 include/scsi/scsi.h           |   9 ++
 include/trace/events/libata.h |   2 +
 7 files changed, 293 insertions(+), 6 deletions(-)

-- 
1.8.5.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/3] libata: implement ZBC IN translation
  2015-03-31  8:52 [PATCH 0/3] libata: ZAC SATL implementation Hannes Reinecke
@ 2015-03-31  8:52 ` Hannes Reinecke
  2015-03-31  8:52 ` [PATCH 2/3] libata: Implement ZBC OUT translation Hannes Reinecke
  2015-03-31  8:52 ` [PATCH 3/3] libata: support host-aware ZAC devices Hannes Reinecke
  2 siblings, 0 replies; 5+ messages in thread
From: Hannes Reinecke @ 2015-03-31  8:52 UTC (permalink / raw)
  To: Tejun Heo; +Cc: linux-ide, linux-scsi, Hannes Reinecke

ZAC drives implement 'zac management in' command template,
which maps onto the ZBC IN command.

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 drivers/ata/libata-eh.c       |   1 +
 drivers/ata/libata-scsi.c     | 144 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/ata.h           |   4 ++
 include/scsi/scsi.h           |   3 +
 include/trace/events/libata.h |   1 +
 5 files changed, 153 insertions(+)

diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 07f41be..adf306e 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2479,6 +2479,7 @@ const char *ata_get_cmd_descript(u8 command)
 		{ ATA_CMD_CFA_WRITE_MULT_NE,	"CFA WRITE MULTIPLE WITHOUT ERASE" },
 		{ ATA_CMD_REQ_SENSE_DATA,	"REQUEST SENSE DATA EXT" },
 		{ ATA_CMD_SANITIZE_DEVICE,	"SANITIZE DEVICE" },
+		{ ATA_CMD_ZAC_MGMT_IN,		"ZAC MANAGEMENT IN" },
 		{ ATA_CMD_READ_LONG,		"READ LONG (with retries)" },
 		{ ATA_CMD_READ_LONG_ONCE,	"READ LONG (without retries)" },
 		{ ATA_CMD_WRITE_LONG,		"WRITE LONG (with retries)" },
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 35fec70..fa480de 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3202,6 +3202,147 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
 	return 1;
 }
 
+/*
+ * ata_scsi_report_zones_complete
+ *
+ * Convert T-13 little-endian field representation into
+ * T-10 big-endian field representation.
+ */
+static void ata_scsi_report_zones_complete(struct ata_queued_cmd *qc)
+{
+	struct scsi_cmnd *scmd = qc->scsicmd;
+	struct sg_mapping_iter miter;
+	unsigned long flags;
+	unsigned int bytes = 0;
+
+	sg_miter_start(&miter, scsi_sglist(scmd), scsi_sg_count(scmd),
+		       SG_MITER_TO_SG | SG_MITER_ATOMIC);
+
+	local_irq_save(flags);
+	while (sg_miter_next(&miter)) {
+		unsigned int offset = 0;
+
+		if (bytes == 0) {
+			char *hdr;
+			u32 list_length;
+			u64 max_lba, opt_lba;
+			u16 same;
+
+			/* Swizzle header */
+			hdr = miter.addr;
+			list_length = get_unaligned_le32(&hdr[0]);
+			same = get_unaligned_le16(&hdr[4]);
+			max_lba = get_unaligned_le64(&hdr[8]);
+			opt_lba = get_unaligned_le64(&hdr[16]);
+			put_unaligned_be32(list_length, &hdr[0]);
+			hdr[4] = same & 0xf;
+			put_unaligned_be64(max_lba, &hdr[8]);
+			put_unaligned_be64(opt_lba, &hdr[16]);
+			offset += 64;
+			bytes += 64;
+		}
+		while (offset < miter.length) {
+			char *rec;
+			u16 option;
+			u8 cond, type, reset;
+			u64 size, start, wp, checkpoint;
+
+			/* Swizzle zone descriptor */
+			rec = miter.addr + offset;
+			option = get_unaligned_le16(&rec[0]);
+			cond = (option >> 4) & 0xf;
+			type = (option >> 8) & 0xf;
+			reset = (option & 1);
+			size = get_unaligned_le64(&rec[8]);
+			start = get_unaligned_le64(&rec[16]);
+			wp = get_unaligned_le64(&rec[24]);
+			checkpoint = get_unaligned_le64(&rec[32]);
+			rec[0] = type;
+			rec[1] = (cond << 4) | reset;
+			put_unaligned_be64(size, &rec[8]);
+			put_unaligned_be64(start, &rec[16]);
+			put_unaligned_be64(wp, &rec[24]);
+			put_unaligned_be64(checkpoint, &rec[32]);
+			WARN_ON(offset + 64 > miter.length);
+			offset += 64;
+			bytes += 64;
+		}
+	}
+	sg_miter_stop(&miter);
+	local_irq_restore(flags);
+
+	ata_scsi_qc_complete(qc);
+}
+
+static unsigned int ata_scsi_zbc_in_xlat(struct ata_queued_cmd *qc)
+{
+	struct ata_taskfile *tf = &qc->tf;
+	struct scsi_cmnd *scmd = qc->scsicmd;
+	const u8 *cdb = scmd->cmnd;
+	u16 sect;
+	u8 sa, options;
+	u64 block;
+	u32 n_block;
+
+	if (unlikely(scmd->cmd_len < 16)) {
+		ata_dev_warn(qc->dev, "invalid cdb length %d\n",
+			     scmd->cmd_len);
+		goto invalid_fld;
+	}
+	scsi_16_lba_len(cdb, &block, &n_block);
+	if (n_block != scsi_bufflen(scmd)) {
+		ata_dev_warn(qc->dev, "non-matching transfer count (%d/%d)\n",
+			     n_block, scsi_bufflen(scmd));
+		goto invalid_fld;
+	}
+	sa = cdb[1] & 0x1f;
+	if (sa != ZI_REPORT_ZONES) {
+		ata_dev_warn(qc->dev, "invalid service action %d\n", sa);
+		goto invalid_fld;
+	}
+	/*
+	 * ZAC allows only for transfers in 512 byte blocks,
+	 * and uses a 16 bit value for the transfer count.
+	 */
+	if ((n_block / 512) > 0xffff || n_block < 512 || (n_block % 512)) {
+		ata_dev_warn(qc->dev, "invalid transfer count %d\n", n_block);
+		goto invalid_fld;
+	}
+	sect = n_block / 512;
+	options = cdb[14];
+
+	tf->command = ATA_CMD_ZAC_MGMT_IN;
+	tf->feature = ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES;
+	if (qc->dev->dma_mode)
+		tf->protocol = ATA_PROT_DMA;
+	else
+		tf->protocol = ATA_PROT_PIO;
+	tf->hob_feature = options & 0x3f;
+	tf->hob_nsect = (sect >> 8) & 0xff;
+	tf->nsect = sect & 0xff;
+	tf->device |= (1 << 6);
+	tf->lbah = (block >> 16) & 0xff;
+	tf->lbam = (block >> 8) & 0xff;
+	tf->lbal = block & 0xff;
+	tf->hob_lbah = (block >> 40) & 0xff;
+	tf->hob_lbam = (block >> 32) & 0xff;
+	tf->hob_lbal = (block >> 24) & 0xff;
+
+	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48;
+	qc->flags |= ATA_QCFLAG_RESULT_TF;
+
+	ata_qc_set_pc_nbytes(qc);
+
+	qc->complete_fn = ata_scsi_report_zones_complete;
+
+	return 0;
+
+ invalid_fld:
+	ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x00);
+	/* "Invalid field in cdb" */
+	return 1;
+}
+
 /**
  *	ata_mselect_caching - Simulate MODE SELECT for caching info page
  *	@qc: Storage for translated ATA taskfile
@@ -3429,6 +3570,9 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
 		return ata_scsi_mode_select_xlat;
 		break;
 
+	case ZBC_IN:
+		return ata_scsi_zbc_in_xlat;
+
 	case START_STOP:
 		return ata_scsi_start_stop_xlat;
 	}
diff --git a/include/linux/ata.h b/include/linux/ata.h
index b666b77..63427b1 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -300,6 +300,7 @@ enum {
 	ATA_CMD_CFA_WRITE_MULT_NE = 0xCD,
 	ATA_CMD_REQ_SENSE_DATA  = 0x0B,
 	ATA_CMD_SANITIZE_DEVICE = 0xB4,
+	ATA_CMD_ZAC_MGMT_IN	= 0x4A,
 
 	/* marked obsolete in the ATA/ATAPI-7 spec */
 	ATA_CMD_RESTORE		= 0x10,
@@ -308,6 +309,9 @@ enum {
 	ATA_SUBCMD_FPDMA_SEND_DSM            = 0x00,
 	ATA_SUBCMD_FPDMA_SEND_WR_LOG_DMA_EXT = 0x02,
 
+	/* Subcmds for ATA_CMD_ZAC_MGMT_IN */
+	ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES = 0x00,
+
 	/* READ_LOG_EXT pages */
 	ATA_LOG_SATA_NCQ	= 0x10,
 	ATA_LOG_NCQ_SEND_RECV	  = 0x13,
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index d0a66aa..607c25a 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -153,6 +153,7 @@ enum scsi_timeouts {
 #define VERIFY_16	      0x8f
 #define SYNCHRONIZE_CACHE_16  0x91
 #define WRITE_SAME_16	      0x93
+#define ZBC_IN		      0x95
 #define SERVICE_ACTION_BIDIRECTIONAL 0x9d
 #define SERVICE_ACTION_IN_16  0x9e
 #define SERVICE_ACTION_OUT_16 0x9f
@@ -181,6 +182,8 @@ enum scsi_timeouts {
 #define MO_SET_PRIORITY       0x0e
 #define MO_SET_TIMESTAMP      0x0f
 #define MO_MANAGEMENT_PROTOCOL_OUT 0x10
+/* values for ZBC_IN */
+#define ZI_REPORT_ZONES	      0x00
 /* values for variable length command */
 #define XDREAD_32	      0x03
 #define XDWRITE_32	      0x04
diff --git a/include/trace/events/libata.h b/include/trace/events/libata.h
index 8b0fbd9..02ec4e5 100644
--- a/include/trace/events/libata.h
+++ b/include/trace/events/libata.h
@@ -97,6 +97,7 @@
 		 ata_opcode_name(ATA_CMD_CFA_WRITE_MULT_NE),	\
 		 ata_opcode_name(ATA_CMD_REQ_SENSE_DATA),	\
 		 ata_opcode_name(ATA_CMD_SANITIZE_DEVICE),	\
+		 ata_opcode_name(ATA_CMD_ZAC_MGMT_IN),		\
 		 ata_opcode_name(ATA_CMD_RESTORE),		\
 		 ata_opcode_name(ATA_CMD_READ_LONG),		\
 		 ata_opcode_name(ATA_CMD_READ_LONG_ONCE),	\
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] libata: Implement ZBC OUT translation
  2015-03-31  8:52 [PATCH 0/3] libata: ZAC SATL implementation Hannes Reinecke
  2015-03-31  8:52 ` [PATCH 1/3] libata: implement ZBC IN translation Hannes Reinecke
@ 2015-03-31  8:52 ` Hannes Reinecke
  2015-03-31  8:52 ` [PATCH 3/3] libata: support host-aware ZAC devices Hannes Reinecke
  2 siblings, 0 replies; 5+ messages in thread
From: Hannes Reinecke @ 2015-03-31  8:52 UTC (permalink / raw)
  To: Tejun Heo; +Cc: linux-ide, linux-scsi, Hannes Reinecke

ZAC drives implement 'zac management out' command template,
which maps onto the ZBC OUT command.

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 drivers/ata/libata-eh.c       |  1 +
 drivers/ata/libata-scsi.c     | 65 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/ata.h           |  7 +++++
 include/scsi/scsi.h           |  6 ++++
 include/trace/events/libata.h |  1 +
 5 files changed, 80 insertions(+)

diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index adf306e..f12b6e3 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2480,6 +2480,7 @@ const char *ata_get_cmd_descript(u8 command)
 		{ ATA_CMD_REQ_SENSE_DATA,	"REQUEST SENSE DATA EXT" },
 		{ ATA_CMD_SANITIZE_DEVICE,	"SANITIZE DEVICE" },
 		{ ATA_CMD_ZAC_MGMT_IN,		"ZAC MANAGEMENT IN" },
+		{ ATA_CMD_ZAC_MGMT_OUT,		"ZAC MANAGEMENT OUT" },
 		{ ATA_CMD_READ_LONG,		"READ LONG (with retries)" },
 		{ ATA_CMD_READ_LONG_ONCE,	"READ LONG (without retries)" },
 		{ ATA_CMD_WRITE_LONG,		"WRITE LONG (with retries)" },
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index fa480de..fb81343 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3343,6 +3343,68 @@ static unsigned int ata_scsi_zbc_in_xlat(struct ata_queued_cmd *qc)
 	return 1;
 }
 
+static unsigned int ata_scsi_zbc_out_xlat(struct ata_queued_cmd *qc)
+{
+	struct ata_taskfile *tf = &qc->tf;
+	struct scsi_cmnd *scmd = qc->scsicmd;
+	struct ata_device *dev = qc->dev;
+	const u8 *cdb = scmd->cmnd;
+	u8 reset_all, sa;
+	u64 block;
+	u32 n_block;
+
+	if (unlikely(scmd->cmd_len < 16))
+		goto invalid_fld;
+
+	/*
+	 * The service action definition got moved from
+	 * 0x00 to 0x04 with zbc-r02, so accept both.
+	 */
+	sa = cdb[1] & 0x1f;
+	/* Compatibility with ZBC r01 */
+	if (!sa)
+		sa = ZO_RESET_WRITE_POINTER;
+	if (sa != ZO_RESET_WRITE_POINTER)
+		goto invalid_fld;
+
+	scsi_16_lba_len(cdb, &block, &n_block);
+	if (n_block) {
+		/*
+		 * ZAC MANAGEMENT OUT doesn't define any length
+		 */
+		goto invalid_fld;
+	}
+	if (block > dev->n_sectors)
+		goto out_of_range;
+
+	reset_all = cdb[14] & 0x1;
+
+	tf->protocol = ATA_PROT_NODATA;
+	tf->command = ATA_CMD_ZAC_MGMT_OUT;
+	tf->feature = sa;
+	tf->hob_feature = reset_all & 0x1;
+
+	tf->lbah = (block >> 16) & 0xff;
+	tf->lbam = (block >> 8) & 0xff;
+	tf->lbal = block & 0xff;
+	tf->hob_lbah = (block >> 40) & 0xff;
+	tf->hob_lbam = (block >> 32) & 0xff;
+	tf->hob_lbal = (block >> 24) & 0xff;
+	tf->device |= ATA_LBA;
+	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48;
+
+	return 0;
+
+ invalid_fld:
+	ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x00);
+	/* "Invalid field in cdb" */
+	return 1;
+ out_of_range:
+	ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x21, 0x00);
+	/* "Logical Block Address out of range" */
+	return 1;
+}
+
 /**
  *	ata_mselect_caching - Simulate MODE SELECT for caching info page
  *	@qc: Storage for translated ATA taskfile
@@ -3573,6 +3635,9 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
 	case ZBC_IN:
 		return ata_scsi_zbc_in_xlat;
 
+	case ZBC_OUT:
+		return ata_scsi_zbc_out_xlat;
+
 	case START_STOP:
 		return ata_scsi_start_stop_xlat;
 	}
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 63427b1..6b2d2b5 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -301,6 +301,7 @@ enum {
 	ATA_CMD_REQ_SENSE_DATA  = 0x0B,
 	ATA_CMD_SANITIZE_DEVICE = 0xB4,
 	ATA_CMD_ZAC_MGMT_IN	= 0x4A,
+	ATA_CMD_ZAC_MGMT_OUT	= 0x94,
 
 	/* marked obsolete in the ATA/ATAPI-7 spec */
 	ATA_CMD_RESTORE		= 0x10,
@@ -312,6 +313,12 @@ enum {
 	/* Subcmds for ATA_CMD_ZAC_MGMT_IN */
 	ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES = 0x00,
 
+	/* Subcmds for ATA_CMD_ZAC_MGMT_OUT */
+	ATA_SUBCMD_ZAC_MGMT_OUT_CLOSE_ZONE = 0x01,
+	ATA_SUBCMD_ZAC_MGMT_OUT_FINISH_ZONE = 0x02,
+	ATA_SUBCMD_ZAC_MGMT_OUT_OPEN_ZONE = 0x03,
+	ATA_SUBCMD_ZAC_MGMT_OUT_RESET_WRITE_POINTER = 0x04,
+
 	/* READ_LOG_EXT pages */
 	ATA_LOG_SATA_NCQ	= 0x10,
 	ATA_LOG_NCQ_SEND_RECV	  = 0x13,
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 607c25a..ed1c108 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -153,6 +153,7 @@ enum scsi_timeouts {
 #define VERIFY_16	      0x8f
 #define SYNCHRONIZE_CACHE_16  0x91
 #define WRITE_SAME_16	      0x93
+#define ZBC_OUT		      0x94
 #define ZBC_IN		      0x95
 #define SERVICE_ACTION_BIDIRECTIONAL 0x9d
 #define SERVICE_ACTION_IN_16  0x9e
@@ -184,6 +185,11 @@ enum scsi_timeouts {
 #define MO_MANAGEMENT_PROTOCOL_OUT 0x10
 /* values for ZBC_IN */
 #define ZI_REPORT_ZONES	      0x00
+/* values for ZBC_OUT */
+#define ZO_CLOSE_ZONE	      0x01
+#define ZO_OPEN_ZONE	      0x02
+#define ZO_FINISH_ZONE	      0x03
+#define ZO_RESET_WRITE_POINTER 0x04
 /* values for variable length command */
 #define XDREAD_32	      0x03
 #define XDWRITE_32	      0x04
diff --git a/include/trace/events/libata.h b/include/trace/events/libata.h
index 02ec4e5..24dcd43 100644
--- a/include/trace/events/libata.h
+++ b/include/trace/events/libata.h
@@ -98,6 +98,7 @@
 		 ata_opcode_name(ATA_CMD_REQ_SENSE_DATA),	\
 		 ata_opcode_name(ATA_CMD_SANITIZE_DEVICE),	\
 		 ata_opcode_name(ATA_CMD_ZAC_MGMT_IN),		\
+		 ata_opcode_name(ATA_CMD_ZAC_MGMT_OUT),		\
 		 ata_opcode_name(ATA_CMD_RESTORE),		\
 		 ata_opcode_name(ATA_CMD_READ_LONG),		\
 		 ata_opcode_name(ATA_CMD_READ_LONG_ONCE),	\
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] libata: support host-aware ZAC devices
  2015-03-31  8:52 [PATCH 0/3] libata: ZAC SATL implementation Hannes Reinecke
  2015-03-31  8:52 ` [PATCH 1/3] libata: implement ZBC IN translation Hannes Reinecke
  2015-03-31  8:52 ` [PATCH 2/3] libata: Implement ZBC OUT translation Hannes Reinecke
@ 2015-03-31  8:52 ` Hannes Reinecke
  2015-03-31 12:56   ` One Thousand Gnomes
  2 siblings, 1 reply; 5+ messages in thread
From: Hannes Reinecke @ 2015-03-31  8:52 UTC (permalink / raw)
  To: Tejun Heo; +Cc: linux-ide, linux-scsi, Hannes Reinecke

Byte 69 bits 0:1 in the IDENTIFY DEVICE data are proposed
to indicate a host-aware ZAC device.
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>
---
 drivers/ata/libata-core.c | 17 +++++++++++++++++
 drivers/ata/libata-scsi.c | 43 +++++++++++++++++++++++++++++++++++++------
 include/linux/ata.h       |  5 +++++
 include/linux/libata.h    |  1 +
 4 files changed, 60 insertions(+), 6 deletions(-)

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 1882fd2..a3cad3c 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2165,6 +2165,22 @@ static void ata_dev_config_sense_reporting(struct ata_device *dev)
 	}
 }
 
+static void ata_dev_config_zac(struct ata_device *dev)
+{
+	/*
+	 * Always set the 'ZAC' flag for Host-managed devices.
+	 */
+	if (dev->class == ATA_DEV_ZAC) {
+		dev->flags |= ATA_DFLAG_ZAC;
+		return;
+	}
+	/*
+	 * Check for host-aware devices.
+	 */
+	if (ata_id_is_zac_host_aware(dev->id))
+		dev->flags |= ATA_DFLAG_ZAC;
+}
+
 /**
  *	ata_dev_configure - Configure the specified ATA/ATAPI device
  *	@dev: Target device to configure
@@ -2388,6 +2404,7 @@ int ata_dev_configure(struct ata_device *dev)
 				}
 		}
 		ata_dev_config_sense_reporting(dev);
+		ata_dev_config_zac(dev);
 		dev->cdb_len = 16;
 	}
 
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index fb81343..1bedbfc 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -2019,7 +2019,7 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
 		0x60,	/* SPC-4 (no version claimed) */
 
 		0x60,
-		0x20,   /* ZBC (no version claimed) */
+		0x22,   /* ZBC r02 */
 	};
 
 	u8 hdr[] = {
@@ -2036,9 +2036,10 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
 	if (ata_id_removable(args->id))
 		hdr[1] |= (1 << 7);
 
-	if (args->dev->class == ATA_DEV_ZAC) {
-		hdr[0] = TYPE_ZBC;
+	if (args->dev->flags & ATA_DFLAG_ZAC) {
 		hdr[2] = 0x6; /* ZBC is defined in SPC-4 */
+		if (args->dev->class == ATA_DEV_ZAC)
+			hdr[0] = TYPE_ZBC;
 	}
 
 	memcpy(rbuf, hdr, sizeof(hdr));
@@ -2053,7 +2054,7 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
 	if (rbuf[32] == 0 || rbuf[32] == ' ')
 		memcpy(&rbuf[32], "n/a ", 4);
 
-	if (args->dev->class == ATA_DEV_ZAC)
+	if (args->dev->flags & ATA_DFLAG_ZAC)
 		memcpy(rbuf + 58, versions_zbc, sizeof(versions_zbc));
 	else
 		memcpy(rbuf + 58, versions, sizeof(versions));
@@ -2073,6 +2074,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 */
@@ -2081,10 +2083,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;
 }
 
@@ -2255,6 +2261,9 @@ static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf)
 	rbuf[4] = media_rotation_rate >> 8;
 	rbuf[5] = media_rotation_rate;
 	rbuf[7] = form_factor;
+	/* Set the 'ZONED' bit for ZAC drives */
+	if (args->dev->flags & ATA_DFLAG_ZAC)
+		rbuf[8] = 1 << 4;
 
 	return 0;
 }
@@ -2269,6 +2278,22 @@ 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)
+{
+	/*
+	 * SCSI Zoned Block device characteristics VPD page:
+	 * ZBC rev 02 or later.
+	 */
+	rbuf[1] = 0xb6;
+	rbuf[3] = 0x3C;
+
+	put_unaligned_be32((u32)-1, &rbuf[8]);
+	put_unaligned_be32((u32)-1, &rbuf[12]);
+	put_unaligned_be32((u32)-1, &rbuf[16]);
+
+	return 0;
+}
+
 /**
  *	ata_scsiop_noop - Command handler that simply returns success.
  *	@args: device IDENTIFY data / SCSI command of interest.
@@ -3819,6 +3844,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(cmd);
 			break;
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 6b2d2b5..f8cab27 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -889,6 +889,11 @@ static inline bool ata_id_is_ssd(const u16 *id)
 	return id[ATA_ID_ROT_SPEED] == 0x01;
 }
 
+static inline bool ata_id_is_zac_host_aware(const u16 *id)
+{
+	return (id[ATA_ID_ADDITIONAL_SUPP] & 0x3) == 0x1;
+}
+
 static inline bool ata_id_pio_need_iordy(const u16 *id, const u8 pio)
 {
 	/* CF spec. r4.1 Table 22 says no IORDY on PIO5 and PIO6. */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 6b08cc1..ffef372 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -181,6 +181,7 @@ enum {
 	ATA_DFLAG_DA		= (1 << 26), /* device supports Device Attention */
 	ATA_DFLAG_DEVSLP	= (1 << 27), /* device supports Device Sleep */
 	ATA_DFLAG_ACPI_DISABLED = (1 << 28), /* ACPI for the device is disabled */
+	ATA_DFLAG_ZAC		= (1 << 29), /* ZAC device */
 
 	ATA_DEV_UNKNOWN		= 0,	/* unknown device */
 	ATA_DEV_ATA		= 1,	/* ATA device */
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 3/3] libata: support host-aware ZAC devices
  2015-03-31  8:52 ` [PATCH 3/3] libata: support host-aware ZAC devices Hannes Reinecke
@ 2015-03-31 12:56   ` One Thousand Gnomes
  0 siblings, 0 replies; 5+ messages in thread
From: One Thousand Gnomes @ 2015-03-31 12:56 UTC (permalink / raw)
  To: Hannes Reinecke; +Cc: Tejun Heo, linux-ide, linux-scsi

On Tue, 31 Mar 2015 10:52:43 +0200
Hannes Reinecke <hare@suse.de> wrote:

> Byte 69 bits 0:1 in the IDENTIFY DEVICE data are proposed
> to indicate a host-aware ZAC device.
> And whenever we detect a ZAC-compatible device we should
> be displaying the zoned block characteristics VPD page.

I don't think this belongs upstream as is - because this is a "proposed"
- it might change and then we have Linux boxes in the field randomly
misinterpreting bits if instead other bits are used or the definition
changes.

Until it's officially in the spec there ought IMHO to be a boot option to
enable the test.

Alan

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2015-03-31 12:56 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-03-31  8:52 [PATCH 0/3] libata: ZAC SATL implementation Hannes Reinecke
2015-03-31  8:52 ` [PATCH 1/3] libata: implement ZBC IN translation Hannes Reinecke
2015-03-31  8:52 ` [PATCH 2/3] libata: Implement ZBC OUT translation Hannes Reinecke
2015-03-31  8:52 ` [PATCH 3/3] libata: support host-aware ZAC devices Hannes Reinecke
2015-03-31 12:56   ` One Thousand Gnomes

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).