* Re: [PATCH 2/4] Add bio/request flags for using ZBC/ZAC commands
2016-06-06 15:39 ` [PATCH 2/4] Add bio/request flags for using ZBC/ZAC commands Shaun Tancheff
@ 2016-06-06 15:23 ` kbuild test robot
2016-06-06 19:26 ` Shaun Tancheff
1 sibling, 0 replies; 7+ messages in thread
From: kbuild test robot @ 2016-06-06 15:23 UTC (permalink / raw)
Cc: kbuild-all, linux-ide, linux-block, linux-scsi, Shaun Tancheff,
Shaun Tancheff
[-- Attachment #1: Type: text/plain, Size: 2238 bytes --]
Hi,
[auto build test WARNING on scsi/for-next]
[also build test WARNING on v4.7-rc2 next-20160606]
[cannot apply to block/for-next]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Shaun-Tancheff/Block-layer-support-ZAC-ZBC-commands/20160606-234756
base: https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
reproduce: make htmldocs
All warnings (new ones prefixed by >>):
lib/crc32.c:148: warning: No description found for parameter 'tab)[256]'
lib/crc32.c:148: warning: Excess function parameter 'tab' description in 'crc32_le_generic'
lib/crc32.c:293: warning: No description found for parameter 'tab)[256]'
lib/crc32.c:293: warning: Excess function parameter 'tab' description in 'crc32_be_generic'
lib/crc32.c:1: warning: no structured comments found
mm/memory.c:2881: warning: No description found for parameter 'old'
>> block/blk-lib.c:269: warning: No description found for parameter 'opt'
vim +/opt +269 block/blk-lib.c
253
254 /**
255 * blkdev_issue_zone_report - queue a report zones operation
256 * @bdev: target blockdev
257 * @bi_rw: extra bio rw flags. If unsure, use 0.
258 * @sector: starting sector (report will include this sector).
259 * @page: one or more contiguous pages.
260 * @pgsz: up to size of page in bytes, size of report.
261 * @gfp_mask: memory allocation flags (for bio_alloc)
262 *
263 * Description:
264 * Issue a zone report request for the sectors in question.
265 */
266 int blkdev_issue_zone_report(struct block_device *bdev, unsigned int bi_rw,
267 sector_t sector, u8 opt, struct page *page,
268 size_t pgsz, gfp_t gfp_mask)
> 269 {
270 struct bdev_zone_report *conv = page_address(page);
271 struct bio *bio;
272 unsigned int nr_iovecs = 1;
273 int ret = 0;
274
275 if (pgsz < (sizeof(struct bdev_zone_report) +
276 sizeof(struct bdev_zone_descriptor)))
277 return -EINVAL;
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 6366 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 0/4] Block layer support ZAC/ZBC commands
@ 2016-06-06 15:39 Shaun Tancheff
2016-06-06 15:39 ` [PATCH 1/4] Add support for SCT Write Same Shaun Tancheff
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Shaun Tancheff @ 2016-06-06 15:39 UTC (permalink / raw)
To: linux-ide, linux-block, linux-scsi
Cc: Shaun Tancheff, Jens Axboe, James E.J. Bottomley,
Martin K. Petersen, Jeff Layton, J. Bruce Fields
As Host Aware drives are becoming available we would like to be able
to make use of such drives. This series is also intended to be suitable
for use by Host Managed drives.
ZAC/ZBC drives add new commands for discovering and working with Zones.
This extends the ZAC/ZBC support up to the block layer.
Thie first patch in the series is a place-holder for Mike Christi's
separate operations from flags ...
https://lkml.kernel.org/r/1460716802-2294-1-git-send-email-mchristi@redhat.com
Once that work is completed the first patch can be dropped.
Patches for util-linux can be found here:
https://github.com/Seagate/ZDM-Device-Mapper/tree/master/patches/util-linux
Using BIOs to issue ZBC commands allows DM targets (such as ZDM) or
file-systems such as btrfs or nilfs2 to extend their block allocation
schemes and issue discards that are zone aware.
Cc: Jens Axboe <axboe@kernel.dk>
Cc: "James E.J. Bottomley" <jejb@linux.vnet.ibm.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: Jeff Layton <jlayton@poochiereds.net>
Cc: "J. Bruce Fields" <bfields@fieldses.org>
Shaun Tancheff (4):
Losing bits on request.cmd_flags
Add bio/request flags for using ZBC/ZAC commands
dd ioctl to issue ZBC/ZAC commands via block layer
Add ata pass-through path for ZAC commands.
MAINTAINERS | 9 ++
block/blk-core.c | 17 +--
block/blk-lib.c | 96 +++++++++++++++++
block/blk-merge.c | 2 +-
block/blk-mq.c | 2 +-
block/cfq-iosched.c | 2 +-
block/elevator.c | 4 +-
block/ioctl.c | 142 ++++++++++++++++++++++++
drivers/scsi/sd.c | 142 +++++++++++++++++++++++-
drivers/scsi/sd.h | 1 +
include/linux/ata.h | 15 +++
include/linux/blk_types.h | 19 +++-
include/linux/blkzoned_api.h | 25 +++++
include/linux/elevator.h | 4 +-
include/uapi/linux/Kbuild | 1 +
include/uapi/linux/blkzoned_api.h | 221 ++++++++++++++++++++++++++++++++++++++
include/uapi/linux/fs.h | 1 +
17 files changed, 683 insertions(+), 20 deletions(-)
create mode 100644 include/linux/blkzoned_api.h
create mode 100644 include/uapi/linux/blkzoned_api.h
--
2.8.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/4] Add support for SCT Write Same
2016-06-06 15:39 [PATCH 0/4] Block layer support ZAC/ZBC commands Shaun Tancheff
@ 2016-06-06 15:39 ` Shaun Tancheff
2016-06-06 15:39 ` [PATCH 2/4] Add bio/request flags for using ZBC/ZAC commands Shaun Tancheff
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Shaun Tancheff @ 2016-06-06 15:39 UTC (permalink / raw)
To: linux-ide, linux-block, linux-scsi; +Cc: Shaun Tancheff, Shaun Tancheff
SATA drives may support write same via SCT. This is useful
for setting the drive contents to a specific pattern (0's).
Signed-off-by: Shaun Tancheff <shaun.tancheff@seagate.com>
---
block/blk-core.c | 17 ++++++++++-------
block/blk-merge.c | 2 +-
block/blk-mq.c | 2 +-
block/cfq-iosched.c | 2 +-
block/elevator.c | 4 ++--
include/linux/elevator.h | 4 ++--
6 files changed, 17 insertions(+), 14 deletions(-)
diff --git a/block/blk-core.c b/block/blk-core.c
index 2475b1c7..945e564 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -959,7 +959,7 @@ static void __freed_request(struct request_list *rl, int sync)
* A request has just been released. Account for it, update the full and
* congestion status, wake up any waiters. Called under q->queue_lock.
*/
-static void freed_request(struct request_list *rl, unsigned int flags)
+static void freed_request(struct request_list *rl, u64 flags)
{
struct request_queue *q = rl->q;
int sync = rw_is_sync(flags);
@@ -1054,7 +1054,7 @@ static struct io_context *rq_ioc(struct bio *bio)
/**
* __get_request - get a free request
* @rl: request list to allocate from
- * @rw_flags: RW and SYNC flags
+ * @rw: RW and SYNC flags
* @bio: bio to allocate request for (can be %NULL)
* @gfp_mask: allocation mask
*
@@ -1065,7 +1065,7 @@ static struct io_context *rq_ioc(struct bio *bio)
* Returns ERR_PTR on failure, with @q->queue_lock held.
* Returns request pointer on success, with @q->queue_lock *not held*.
*/
-static struct request *__get_request(struct request_list *rl, int rw_flags,
+static struct request *__get_request(struct request_list *rl, unsigned long rw,
struct bio *bio, gfp_t gfp_mask)
{
struct request_queue *q = rl->q;
@@ -1073,6 +1073,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
struct elevator_type *et = q->elevator->type;
struct io_context *ioc = rq_ioc(bio);
struct io_cq *icq = NULL;
+ u64 rw_flags = rw;
const bool is_sync = rw_is_sync(rw_flags) != 0;
int may_queue;
@@ -1237,7 +1238,8 @@ rq_starved:
* Returns ERR_PTR on failure, with @q->queue_lock held.
* Returns request pointer on success, with @q->queue_lock *not held*.
*/
-static struct request *get_request(struct request_queue *q, int rw_flags,
+static struct request *get_request(struct request_queue *q,
+ unsigned long rw_flags,
struct bio *bio, gfp_t gfp_mask)
{
const bool is_sync = rw_is_sync(rw_flags) != 0;
@@ -1490,7 +1492,7 @@ void __blk_put_request(struct request_queue *q, struct request *req)
* it didn't come out of our reserved rq pools
*/
if (req->cmd_flags & REQ_ALLOCED) {
- unsigned int flags = req->cmd_flags;
+ u64 flags = req->cmd_flags;
struct request_list *rl = blk_rq_rl(req);
BUG_ON(!list_empty(&req->queuelist));
@@ -1712,7 +1714,8 @@ static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio)
{
const bool sync = !!(bio->bi_rw & REQ_SYNC);
struct blk_plug *plug;
- int el_ret, rw_flags, where = ELEVATOR_INSERT_SORT;
+ u64 rw_flags;
+ int el_ret, where = ELEVATOR_INSERT_SORT;
struct request *req;
unsigned int request_count = 0;
@@ -2246,7 +2249,7 @@ EXPORT_SYMBOL_GPL(blk_insert_cloned_request);
*/
unsigned int blk_rq_err_bytes(const struct request *rq)
{
- unsigned int ff = rq->cmd_flags & REQ_FAILFAST_MASK;
+ u64 ff = rq->cmd_flags & REQ_FAILFAST_MASK;
unsigned int bytes = 0;
struct bio *bio;
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 2613531..fec37e1 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -604,7 +604,7 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
*/
void blk_rq_set_mixed_merge(struct request *rq)
{
- unsigned int ff = rq->cmd_flags & REQ_FAILFAST_MASK;
+ u64 ff = rq->cmd_flags & REQ_FAILFAST_MASK;
struct bio *bio;
if (rq->cmd_flags & REQ_MIXED_MERGE)
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 29cbc1b..db962bc 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -159,7 +159,7 @@ bool blk_mq_can_queue(struct blk_mq_hw_ctx *hctx)
EXPORT_SYMBOL(blk_mq_can_queue);
static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
- struct request *rq, unsigned int rw_flags)
+ struct request *rq, u64 rw_flags)
{
if (blk_queue_io_stat(q))
rw_flags |= REQ_IO_STAT;
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 4a34978..2722345 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -4285,7 +4285,7 @@ static inline int __cfq_may_queue(struct cfq_queue *cfqq)
return ELV_MQUEUE_MAY;
}
-static int cfq_may_queue(struct request_queue *q, int rw)
+static int cfq_may_queue(struct request_queue *q, u64 rw)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct task_struct *tsk = current;
diff --git a/block/elevator.c b/block/elevator.c
index c3555c9..7c0a59c 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -511,7 +511,7 @@ void elv_merge_requests(struct request_queue *q, struct request *rq,
struct request *next)
{
struct elevator_queue *e = q->elevator;
- const int next_sorted = next->cmd_flags & REQ_SORTED;
+ const int next_sorted = !!(next->cmd_flags & REQ_SORTED);
if (next_sorted && e->type->ops.elevator_merge_req_fn)
e->type->ops.elevator_merge_req_fn(q, rq, next);
@@ -717,7 +717,7 @@ void elv_put_request(struct request_queue *q, struct request *rq)
e->type->ops.elevator_put_req_fn(rq);
}
-int elv_may_queue(struct request_queue *q, int rw)
+int elv_may_queue(struct request_queue *q, u64 rw)
{
struct elevator_queue *e = q->elevator;
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index 638b324..a06cca4 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -26,7 +26,7 @@ typedef int (elevator_dispatch_fn) (struct request_queue *, int);
typedef void (elevator_add_req_fn) (struct request_queue *, struct request *);
typedef struct request *(elevator_request_list_fn) (struct request_queue *, struct request *);
typedef void (elevator_completed_req_fn) (struct request_queue *, struct request *);
-typedef int (elevator_may_queue_fn) (struct request_queue *, int);
+typedef int (elevator_may_queue_fn) (struct request_queue *, u64);
typedef void (elevator_init_icq_fn) (struct io_cq *);
typedef void (elevator_exit_icq_fn) (struct io_cq *);
@@ -134,7 +134,7 @@ extern struct request *elv_former_request(struct request_queue *, struct request
extern struct request *elv_latter_request(struct request_queue *, struct request *);
extern int elv_register_queue(struct request_queue *q);
extern void elv_unregister_queue(struct request_queue *q);
-extern int elv_may_queue(struct request_queue *, int);
+extern int elv_may_queue(struct request_queue *, u64);
extern void elv_completed_request(struct request_queue *, struct request *);
extern int elv_set_request(struct request_queue *q, struct request *rq,
struct bio *bio, gfp_t gfp_mask);
--
2.8.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/4] Add bio/request flags for using ZBC/ZAC commands
2016-06-06 15:39 [PATCH 0/4] Block layer support ZAC/ZBC commands Shaun Tancheff
2016-06-06 15:39 ` [PATCH 1/4] Add support for SCT Write Same Shaun Tancheff
@ 2016-06-06 15:39 ` Shaun Tancheff
2016-06-06 15:23 ` kbuild test robot
2016-06-06 19:26 ` Shaun Tancheff
2016-06-06 15:39 ` [PATCH 3/4] Add ioctl to issue ZBC/ZAC commands via block layer Shaun Tancheff
2016-06-06 15:39 ` [PATCH 4/4] Add ata pass-through path for ZAC commands Shaun Tancheff
3 siblings, 2 replies; 7+ messages in thread
From: Shaun Tancheff @ 2016-06-06 15:39 UTC (permalink / raw)
To: linux-ide, linux-block, linux-scsi; +Cc: Shaun Tancheff, Shaun Tancheff
T10 ZBC and T13 ZAC specify operations for Zoned devices.
To be able to access the zone information and open and close zones
adding flags for the report zones command (REQ_REPORT_ZONES) and for
Open and Close zone (REQ_OPEN_ZONE and REQ_CLOSE_ZONE) can be added
for use by struct bio's bi_rw and by struct request's cmd_flags.
To reduce the number of additional flags needed REQ_RESET_ZONE shares
the same flag as REQ_REPORT_ZONES and is differentiated by direction.
Report zones is a device read that requires a buffer. Reset is a device
command (WRITE) that has no associated data transfer.
The Finish zone command is intentionally not implimented as there is no
current use case for that operation.
Report zones currently defaults to reporting on all zones. It expected
that support for the zone option flag will piggy back on streamid
support. The report option is useful as it can reduce the number of
zones in each report, but not critical.
Signed-off-by: Shaun Tancheff <shaun.tancheff@seagate.com>
---
MAINTAINERS | 9 ++
block/blk-lib.c | 96 +++++++++++++++++
drivers/scsi/sd.c | 99 +++++++++++++++++-
drivers/scsi/sd.h | 1 +
include/linux/blk_types.h | 19 +++-
include/linux/blkzoned_api.h | 25 +++++
include/uapi/linux/Kbuild | 1 +
include/uapi/linux/blkzoned_api.h | 215 ++++++++++++++++++++++++++++++++++++++
include/uapi/linux/fs.h | 1 +
9 files changed, 461 insertions(+), 5 deletions(-)
create mode 100644 include/linux/blkzoned_api.h
create mode 100644 include/uapi/linux/blkzoned_api.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 7304d2e..0b71a3c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12660,6 +12660,15 @@ F: Documentation/networking/z8530drv.txt
F: drivers/net/hamradio/*scc.c
F: drivers/net/hamradio/z8530.h
+ZBC AND ZBC BLOCK DEVICES
+M: Shaun Tancheff <shaun.tancheff@seagate.com>
+W: http://seagate.com
+W: https://github.com/Seagate/ZDM-Device-Mapper
+L: linux-block@vger.kernel.org
+S: Maintained
+F: include/linux/blkzoned_api.h
+F: include/uapi/linux/blkzoned_api.h
+
ZBUD COMPRESSED PAGE ALLOCATOR
M: Seth Jennings <sjenning@redhat.com>
L: linux-mm@kvack.org
diff --git a/block/blk-lib.c b/block/blk-lib.c
index 23d7f30..a7f047c 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -6,6 +6,7 @@
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/scatterlist.h>
+#include <linux/blkzoned_api.h>
#include "blk.h"
@@ -249,3 +250,98 @@ int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
return __blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask);
}
EXPORT_SYMBOL(blkdev_issue_zeroout);
+
+/**
+ * blkdev_issue_zone_report - queue a report zones operation
+ * @bdev: target blockdev
+ * @bi_rw: extra bio rw flags. If unsure, use 0.
+ * @sector: starting sector (report will include this sector).
+ * @page: one or more contiguous pages.
+ * @pgsz: up to size of page in bytes, size of report.
+ * @gfp_mask: memory allocation flags (for bio_alloc)
+ *
+ * Description:
+ * Issue a zone report request for the sectors in question.
+ */
+int blkdev_issue_zone_report(struct block_device *bdev, unsigned int bi_rw,
+ sector_t sector, u8 opt, struct page *page,
+ size_t pgsz, gfp_t gfp_mask)
+{
+ struct bdev_zone_report *conv = page_address(page);
+ struct bio *bio;
+ unsigned int nr_iovecs = 1;
+ int ret = 0;
+
+ if (pgsz < (sizeof(struct bdev_zone_report) +
+ sizeof(struct bdev_zone_descriptor)))
+ return -EINVAL;
+
+ bio = bio_alloc(gfp_mask, nr_iovecs);
+ if (!bio)
+ return -ENOMEM;
+
+ conv->descriptor_count = 0;
+ bio->bi_iter.bi_sector = sector;
+ bio->bi_bdev = bdev;
+ bio->bi_vcnt = 0;
+ bio->bi_iter.bi_size = 0;
+
+ bi_rw |= REQ_REPORT_ZONES;
+
+ /* FUTURE ... when streamid is available: */
+ /* bio_set_streamid(bio, opt); */
+
+ bio_add_page(bio, page, pgsz, 0);
+ ret = submit_bio_wait(READ | bi_rw, bio);
+
+ /*
+ * When our request it nak'd the underlying device maybe conventional
+ * so ... report a single conventional zone the size of the device.
+ */
+ if (ret == -EIO && conv->descriptor_count) {
+ /* Adjust the conventional to the size of the partition ... */
+ __be64 blksz = cpu_to_be64(bdev->bd_part->nr_sects);
+
+ conv->maximum_lba = blksz;
+ conv->descriptors[0].type = ZTYP_CONVENTIONAL;
+ conv->descriptors[0].flags = ZCOND_CONVENTIONAL << 4;
+ conv->descriptors[0].length = blksz;
+ conv->descriptors[0].lba_start = 0;
+ conv->descriptors[0].lba_wptr = blksz;
+ return 0;
+ }
+ bio_put(bio);
+ return ret;
+}
+EXPORT_SYMBOL(blkdev_issue_zone_report);
+
+/**
+ * blkdev_issue_zone_action - queue a report zones operation
+ * @bdev: target blockdev
+ * @bi_rw: REQ_OPEN_ZONE, REQ_CLOSE_ZONE, or REQ_RESET_ZONE.
+ * @sector: starting lba of sector
+ * @gfp_mask: memory allocation flags (for bio_alloc)
+ *
+ * Description:
+ * Issue a zone report request for the sectors in question.
+ */
+int blkdev_issue_zone_action(struct block_device *bdev, unsigned int bi_rw,
+ sector_t sector, gfp_t gfp_mask)
+{
+ int ret;
+ struct bio *bio;
+
+ bio = bio_alloc(gfp_mask, 1);
+ if (!bio)
+ return -ENOMEM;
+
+ bio->bi_iter.bi_sector = sector;
+ bio->bi_bdev = bdev;
+ bio->bi_vcnt = 0;
+ bio->bi_iter.bi_size = 0;
+
+ ret = submit_bio_wait(WRITE | bi_rw, bio);
+ bio_put(bio);
+ return ret;
+}
+EXPORT_SYMBOL(blkdev_issue_zone_action);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 428c03e..372b5e2 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -52,6 +52,7 @@
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/pr.h>
+#include <linux/blkzoned_api.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
@@ -1133,11 +1134,105 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
return ret;
}
+static int sd_setup_zoned_cmnd(struct scsi_cmnd *cmd)
+{
+ struct request *rq = cmd->request;
+ struct scsi_device *sdp = cmd->device;
+ struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
+ struct bio *bio = rq->bio;
+ sector_t sector = blk_rq_pos(rq);
+ struct gendisk *disk = rq->rq_disk;
+ unsigned int nr_bytes = blk_rq_bytes(rq);
+ int ret = BLKPREP_KILL;
+ u8 allbit = 0;
+
+ if (rq->cmd_flags & REQ_REPORT_ZONES && rq_data_dir(rq) == READ) {
+ WARN_ON(nr_bytes == 0);
+
+ /*
+ * For conventional drives generate a report that shows a
+ * large single convetional zone the size of the block device
+ */
+ if (sdkp->zoned != 1 && sdkp->device->type != TYPE_ZBC) {
+ void *src;
+ struct bdev_zone_report *conv;
+
+ if (nr_bytes < sizeof(struct bdev_zone_report))
+ goto out;
+
+ src = kmap_atomic(bio->bi_io_vec->bv_page);
+ conv = src + bio->bi_io_vec->bv_offset;
+ conv->descriptor_count = cpu_to_be32(1);
+ conv->same_field = ZS_ALL_SAME;
+ conv->maximum_lba = cpu_to_be64(disk->part0.nr_sects);
+ kunmap_atomic(src);
+ goto out;
+ }
+
+ ret = scsi_init_io(cmd);
+ if (ret != BLKPREP_OK)
+ goto out;
+
+ cmd = rq->special;
+ if (sdp->changed) {
+ pr_err("SCSI disk has been changed or is not present.");
+ ret = BLKPREP_KILL;
+ goto out;
+ }
+
+ cmd->cmd_len = 16;
+ memset(cmd->cmnd, 0, cmd->cmd_len);
+ cmd->cmnd[0] = ZBC_IN;
+ cmd->cmnd[1] = ZI_REPORT_ZONES;
+ put_unaligned_be64(sector, &cmd->cmnd[2]);
+ put_unaligned_be32(nr_bytes, &cmd->cmnd[10]);
+ /* FUTURE ... when streamid is available */
+ /* cmd->cmnd[14] = bio_get_streamid(bio); */
+ cmd->sc_data_direction = DMA_FROM_DEVICE;
+ cmd->sdb.length = nr_bytes;
+ cmd->transfersize = sdp->sector_size;
+ cmd->underflow = 0;
+ cmd->allowed = SD_MAX_RETRIES;
+ ret = BLKPREP_OK;
+ goto out;
+ }
+
+ if (sdkp->zoned != 1 && sdkp->device->type != TYPE_ZBC)
+ goto out;
+
+ if (sector == ~0ul) {
+ allbit = 1;
+ sector = 0;
+ }
+
+ cmd->cmd_len = 16;
+ memset(cmd->cmnd, 0, cmd->cmd_len);
+ memset(&cmd->sdb, 0, sizeof(cmd->sdb));
+ cmd->cmnd[0] = ZBC_OUT;
+ cmd->cmnd[1] = ZO_OPEN_ZONE;
+ if (rq->cmd_flags & REQ_CLOSE_ZONE)
+ cmd->cmnd[1] = ZO_CLOSE_ZONE;
+ if (rq->cmd_flags & REQ_RESET_ZONE)
+ cmd->cmnd[1] = ZO_RESET_WRITE_POINTER;
+ cmd->cmnd[14] = allbit;
+ put_unaligned_be64(sector, &cmd->cmnd[2]);
+ cmd->transfersize = 0;
+ cmd->underflow = 0;
+ cmd->allowed = SD_MAX_RETRIES;
+ cmd->sc_data_direction = DMA_NONE;
+
+ ret = BLKPREP_OK;
+out:
+ return ret;
+}
+
static int sd_init_command(struct scsi_cmnd *cmd)
{
struct request *rq = cmd->request;
- if (rq->cmd_flags & REQ_DISCARD)
+ if (rq->cmd_flags & REQ_ZONED_CMDS)
+ return sd_setup_zoned_cmnd(cmd);
+ else if (rq->cmd_flags & REQ_DISCARD)
return sd_setup_discard_cmnd(cmd);
else if (rq->cmd_flags & REQ_WRITE_SAME)
return sd_setup_write_same_cmnd(cmd);
@@ -2727,6 +2822,8 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, sdkp->disk->queue);
}
+ sdkp->zoned = (buffer[8] >> 4) & 3;
+
out:
kfree(buffer);
}
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 654630b..e012175 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -94,6 +94,7 @@ struct scsi_disk {
unsigned lbpvpd : 1;
unsigned ws10 : 1;
unsigned ws16 : 1;
+ unsigned zoned: 2;
};
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 77e5d81..d2943e4 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -162,6 +162,10 @@ enum rq_flag_bits {
__REQ_FUA, /* forced unit access */
__REQ_FLUSH, /* request for cache flush */
+ __REQ_REPORT_ZONES, /* Zoned device: Report Zones */
+ __REQ_OPEN_ZONE, /* Zoned device: Open Zone */
+ __REQ_CLOSE_ZONE, /* Zoned device: Close Zone */
+
/* bio only flags */
__REQ_RAHEAD, /* read ahead, can fail anytime */
__REQ_THROTTLED, /* This bio has already been subjected to
@@ -202,20 +206,27 @@ enum rq_flag_bits {
#define REQ_WRITE_SAME (1ULL << __REQ_WRITE_SAME)
#define REQ_NOIDLE (1ULL << __REQ_NOIDLE)
#define REQ_INTEGRITY (1ULL << __REQ_INTEGRITY)
+#define REQ_REPORT_ZONES (1ULL << __REQ_REPORT_ZONES)
+#define REQ_OPEN_ZONE (1ULL << __REQ_OPEN_ZONE)
+#define REQ_CLOSE_ZONE (1ULL << __REQ_CLOSE_ZONE)
+#define REQ_RESET_ZONE (REQ_REPORT_ZONES)
+#define REQ_ZONED_CMDS \
+ (REQ_OPEN_ZONE | REQ_CLOSE_ZONE | REQ_RESET_ZONE | REQ_REPORT_ZONES)
#define REQ_FAILFAST_MASK \
(REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER)
#define REQ_COMMON_MASK \
(REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_PRIO | \
REQ_DISCARD | REQ_WRITE_SAME | REQ_NOIDLE | REQ_FLUSH | REQ_FUA | \
- REQ_SECURE | REQ_INTEGRITY | REQ_NOMERGE)
+ REQ_SECURE | REQ_INTEGRITY | REQ_NOMERGE | REQ_ZONED_CMDS)
#define REQ_CLONE_MASK REQ_COMMON_MASK
-
-#define BIO_NO_ADVANCE_ITER_MASK (REQ_DISCARD|REQ_WRITE_SAME)
+#define BIO_NO_ADVANCE_ITER_MASK \
+ (REQ_DISCARD | REQ_WRITE_SAME | REQ_ZONED_CMDS)
/* This mask is used for both bio and request merge checking */
#define REQ_NOMERGE_FLAGS \
- (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA | REQ_FLUSH_SEQ)
+ (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | \
+ REQ_FLUSH | REQ_FUA | REQ_FLUSH_SEQ | REQ_ZONED_CMDS)
#define REQ_RAHEAD (1ULL << __REQ_RAHEAD)
#define REQ_THROTTLED (1ULL << __REQ_THROTTLED)
diff --git a/include/linux/blkzoned_api.h b/include/linux/blkzoned_api.h
new file mode 100644
index 0000000..6061983
--- /dev/null
+++ b/include/linux/blkzoned_api.h
@@ -0,0 +1,25 @@
+/*
+ * Functions for zone based SMR devices.
+ *
+ * Copyright (C) 2015 Seagate Technology PLC
+ *
+ * Written by:
+ * Shaun Tancheff <shaun.tancheff@seagate.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _BLKZONED_API_H
+#define _BLKZONED_API_H
+
+#include <uapi/linux/blkzoned_api.h>
+
+extern int blkdev_issue_zone_action(struct block_device *, unsigned int bi_rw,
+ sector_t, gfp_t);
+extern int blkdev_issue_zone_report(struct block_device *, unsigned int bi_rw,
+ sector_t, u8 opt, struct page *, size_t,
+ gfp_t);
+
+#endif /* _BLKZONED_API_H */
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 8bdae34..5152fa4 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -70,6 +70,7 @@ header-y += bfs_fs.h
header-y += binfmts.h
header-y += blkpg.h
header-y += blktrace_api.h
+header-y += blkzoned_api.h
header-y += bpf_common.h
header-y += bpf.h
header-y += bpqether.h
diff --git a/include/uapi/linux/blkzoned_api.h b/include/uapi/linux/blkzoned_api.h
new file mode 100644
index 0000000..189e925
--- /dev/null
+++ b/include/uapi/linux/blkzoned_api.h
@@ -0,0 +1,215 @@
+/*
+ * Functions for zone based SMR devices.
+ *
+ * Copyright (C) 2015 Seagate Technology PLC
+ *
+ * Written by:
+ * Shaun Tancheff <shaun.tancheff@seagate.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _UAPI_BLKZONED_API_H
+#define _UAPI_BLKZONED_API_H
+
+#include <linux/types.h>
+
+/**
+ * enum zone_report_option - Report Zones types to be included.
+ *
+ * @ZOPT_NON_SEQ_AND_RESET: Default (all zones).
+ * @ZOPT_ZC1_EMPTY: Zones which are empty.
+ * @ZOPT_ZC2_OPEN_IMPLICIT: Zones open but not explicitly opened
+ * @ZOPT_ZC3_OPEN_EXPLICIT: Zones opened explicitly
+ * @ZOPT_ZC4_CLOSED: Zones closed for writing.
+ * @ZOPT_ZC5_FULL: Zones that are full.
+ * @ZOPT_ZC6_READ_ONLY: Zones that are read-only
+ * @ZOPT_ZC7_OFFLINE: Zones that are offline
+ * @ZOPT_RESET: Zones that are empty
+ * @ZOPT_NON_SEQ: Zones that have HA media-cache writes pending
+ * @ZOPT_NON_WP_ZONES: Zones that do not have Write Pointers (conventional)
+ *
+ * @ZOPT_USE_ATA_PASS: Flag used in kernel to service command I/O
+ *
+ * Used by Report Zones in bdev_zone_get_report: report_option
+ */
+enum zone_report_option {
+ ZOPT_NON_SEQ_AND_RESET = 0x00,
+ ZOPT_ZC1_EMPTY,
+ ZOPT_ZC2_OPEN_IMPLICIT,
+ ZOPT_ZC3_OPEN_EXPLICIT,
+ ZOPT_ZC4_CLOSED,
+ ZOPT_ZC5_FULL,
+ ZOPT_ZC6_READ_ONLY,
+ ZOPT_ZC7_OFFLINE,
+ ZOPT_RESET = 0x10,
+ ZOPT_NON_SEQ = 0x11,
+ ZOPT_NON_WP_ZONES = 0x3f,
+ ZOPT_USE_ATA_PASS = 0x80,
+};
+
+/**
+ * enum bdev_zone_type - Type of zone in descriptor
+ *
+ * @ZTYP_RESERVED: Reserved
+ * @ZTYP_CONVENTIONAL: Conventional random write zone (No Write Pointer)
+ * @ZTYP_SEQ_WRITE_REQUIRED: Non-sequential writes are rejected.
+ * @ZTYP_SEQ_WRITE_PREFERRED: Non-sequential writes allowed but discouraged.
+ *
+ * Returned from Report Zones. See bdev_zone_descriptor* type.
+ */
+enum bdev_zone_type {
+ ZTYP_RESERVED = 0,
+ ZTYP_CONVENTIONAL = 1,
+ ZTYP_SEQ_WRITE_REQUIRED = 2,
+ ZTYP_SEQ_WRITE_PREFERRED = 3,
+};
+
+
+/**
+ * enum bdev_zone_condition - Condition of zone in descriptor
+ *
+ * @ZCOND_CONVENTIONAL: N/A
+ * @ZCOND_ZC1_EMPTY: Empty
+ * @ZCOND_ZC2_OPEN_IMPLICIT: Opened via write to zone.
+ * @ZCOND_ZC3_OPEN_EXPLICIT: Opened via open zone command.
+ * @ZCOND_ZC4_CLOSED: Closed
+ * @ZCOND_ZC6_READ_ONLY:
+ * @ZCOND_ZC5_FULL: No remaining space in zone.
+ * @ZCOND_ZC7_OFFLINE: Offline
+ *
+ * Returned from Report Zones. See bdev_zone_descriptor* flags.
+ */
+enum bdev_zone_condition {
+ ZCOND_CONVENTIONAL = 0,
+ ZCOND_ZC1_EMPTY = 1,
+ ZCOND_ZC2_OPEN_IMPLICIT = 2,
+ ZCOND_ZC3_OPEN_EXPLICIT = 3,
+ ZCOND_ZC4_CLOSED = 4,
+ /* 0x5 to 0xC are reserved */
+ ZCOND_ZC6_READ_ONLY = 0xd,
+ ZCOND_ZC5_FULL = 0xe,
+ ZCOND_ZC7_OFFLINE = 0xf,
+};
+
+
+/**
+ * enum bdev_zone_same - Report Zones same code.
+ *
+ * @ZS_ALL_DIFFERENT: All zones differ in type and size.
+ * @ZS_ALL_SAME: All zones are the same size and type.
+ * @ZS_LAST_DIFFERS: All zones are the same size and type except the last zone.
+ * @ZS_SAME_LEN_DIFF_TYPES: All zones are the same length but types differ.
+ *
+ * Returned from Report Zones. See bdev_zone_report* same_field.
+ */
+enum bdev_zone_same {
+ ZS_ALL_DIFFERENT = 0,
+ ZS_ALL_SAME = 1,
+ ZS_LAST_DIFFERS = 2,
+ ZS_SAME_LEN_DIFF_TYPES = 3,
+};
+
+
+/**
+ * struct bdev_zone_get_report - ioctl: Report Zones request
+ *
+ * @zone_locator_lba: starting lba for first [reported] zone
+ * @return_page_count: number of *bytes* allocated for result
+ * @report_option: see: zone_report_option enum
+ *
+ * Used to issue report zones command to connected device
+ */
+struct bdev_zone_get_report {
+ __u64 zone_locator_lba;
+ __u32 return_page_count;
+ __u8 report_option;
+} __packed;
+
+/**
+ * struct bdev_zone_descriptor_le - See: bdev_zone_descriptor
+ */
+struct bdev_zone_descriptor_le {
+ __u8 type;
+ __u8 flags;
+ __u8 reserved1[6];
+ __le64 length;
+ __le64 lba_start;
+ __le64 lba_wptr;
+ __u8 reserved[32];
+} __packed;
+
+
+/**
+ * struct bdev_zone_report_le - See: bdev_zone_report
+ */
+struct bdev_zone_report_le {
+ __le32 descriptor_count;
+ __u8 same_field;
+ __u8 reserved1[3];
+ __le64 maximum_lba;
+ __u8 reserved2[48];
+ struct bdev_zone_descriptor_le descriptors[0];
+} __packed;
+
+
+/**
+ * struct bdev_zone_descriptor - A Zone descriptor entry from report zones
+ *
+ * @type: see zone_type enum
+ * @flags: Bits 0:reset, 1:non-seq, 2-3: resv, 4-7: see zone_condition enum
+ * @reserved1: padding
+ * @length: length of zone in sectors
+ * @lba_start: lba where the zone starts.
+ * @lba_wptr: lba of the current write pointer.
+ * @reserved: padding
+ *
+ */
+struct bdev_zone_descriptor {
+ __u8 type;
+ __u8 flags;
+ __u8 reserved1[6];
+ __be64 length;
+ __be64 lba_start;
+ __be64 lba_wptr;
+ __u8 reserved[32];
+} __packed;
+
+
+/**
+ * struct bdev_zone_report - Report Zones result
+ *
+ * @descriptor_count: Number of descriptor entries that follow
+ * @same_field: bits 0-3: enum zone_same (MASK: 0x0F)
+ * @reserved1: padding
+ * @maximum_lba: LBA of the last logical sector on the device, inclusive
+ * of all logical sectors in all zones.
+ * @reserved2: padding
+ * @descriptors: array of descriptors follows.
+ */
+struct bdev_zone_report {
+ __be32 descriptor_count;
+ __u8 same_field;
+ __u8 reserved1[3];
+ __be64 maximum_lba;
+ __u8 reserved2[48];
+ struct bdev_zone_descriptor descriptors[0];
+} __packed;
+
+
+/**
+ * struct bdev_zone_report_io - Report Zones ioctl argument.
+ *
+ * @in: Report Zones inputs
+ * @out: Report Zones output
+ */
+struct bdev_zone_report_io {
+ union {
+ struct bdev_zone_get_report in;
+ struct bdev_zone_report out;
+ } data;
+} __packed;
+
+#endif /* _UAPI_BLKZONED_API_H */
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index 3b00f7c..c0b565b 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -222,6 +222,7 @@ struct fsxattr {
#define BLKSECDISCARD _IO(0x12,125)
#define BLKROTATIONAL _IO(0x12,126)
#define BLKZEROOUT _IO(0x12,127)
+/* A jump here: See blkzoned_api.h, Reserving 130 to 133. */
#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
#define FIBMAP _IO(0x00,1) /* bmap access */
--
2.8.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/4] Add ioctl to issue ZBC/ZAC commands via block layer
2016-06-06 15:39 [PATCH 0/4] Block layer support ZAC/ZBC commands Shaun Tancheff
2016-06-06 15:39 ` [PATCH 1/4] Add support for SCT Write Same Shaun Tancheff
2016-06-06 15:39 ` [PATCH 2/4] Add bio/request flags for using ZBC/ZAC commands Shaun Tancheff
@ 2016-06-06 15:39 ` Shaun Tancheff
2016-06-06 15:39 ` [PATCH 4/4] Add ata pass-through path for ZAC commands Shaun Tancheff
3 siblings, 0 replies; 7+ messages in thread
From: Shaun Tancheff @ 2016-06-06 15:39 UTC (permalink / raw)
To: linux-ide, linux-block, linux-scsi; +Cc: Shaun Tancheff, Shaun Tancheff
Add New ioctl types
BLKREPORT - Issue Report Zones to device.
BLKOPENZONE - Issue an Zone Action: Open Zone command.
BLKCLOSEZONE - Issue an Zone Action: Close Zone command.
BLKRESETZONE - Issue an Zone Action: Reset Zone command.
Signed-off-by: Shaun Tancheff <shaun.tancheff@seagate.com>
---
block/ioctl.c | 113 ++++++++++++++++++++++++++++++++++++++
include/uapi/linux/blkzoned_api.h | 6 ++
2 files changed, 119 insertions(+)
diff --git a/block/ioctl.c b/block/ioctl.c
index ed2397f..46a8553 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -7,6 +7,7 @@
#include <linux/backing-dev.h>
#include <linux/fs.h>
#include <linux/blktrace_api.h>
+#include <linux/blkzoned_api.h>
#include <linux/pr.h>
#include <asm/uaccess.h>
@@ -194,6 +195,112 @@ int blkdev_reread_part(struct block_device *bdev)
}
EXPORT_SYMBOL(blkdev_reread_part);
+static int blk_zoned_report_ioctl(struct block_device *bdev, fmode_t mode,
+ void __user *parg)
+{
+ int error = -EFAULT;
+ gfp_t gfp = GFP_KERNEL;
+ struct bdev_zone_report_io *zone_iodata = NULL;
+ int order = 0;
+ struct page *pgs = NULL;
+ u32 alloc_size = PAGE_SIZE;
+ unsigned long bi_rw = 0;
+ u8 opt = 0;
+
+ if (!(mode & FMODE_READ))
+ return -EBADF;
+
+ zone_iodata = (void *)get_zeroed_page(gfp);
+ if (!zone_iodata) {
+ error = -ENOMEM;
+ goto report_zones_out;
+ }
+ if (copy_from_user(zone_iodata, parg, sizeof(*zone_iodata))) {
+ error = -EFAULT;
+ goto report_zones_out;
+ }
+ if (zone_iodata->data.in.return_page_count > alloc_size) {
+ int npages;
+
+ alloc_size = zone_iodata->data.in.return_page_count;
+ npages = (alloc_size + PAGE_SIZE - 1) / PAGE_SIZE;
+ order = ilog2(roundup_pow_of_two(npages));
+ pgs = alloc_pages(gfp, order);
+ if (pgs) {
+ void *mem = page_address(pgs);
+
+ if (!mem) {
+ error = -ENOMEM;
+ goto report_zones_out;
+ }
+ memset(mem, 0, alloc_size);
+ memcpy(mem, zone_iodata, sizeof(*zone_iodata));
+ free_page((unsigned long)zone_iodata);
+ zone_iodata = mem;
+ } else {
+ /* Result requires DMA capable memory */
+ pr_err("Not enough memory available for request.\n");
+ error = -ENOMEM;
+ goto report_zones_out;
+ }
+ }
+ opt = zone_iodata->data.in.report_option & 0x7F;
+ if (zone_iodata->data.in.report_option & ZOPT_USE_ATA_PASS)
+ bi_rw |= REQ_META;
+
+ error = blkdev_issue_zone_report(bdev, bi_rw,
+ zone_iodata->data.in.zone_locator_lba, opt,
+ pgs ? pgs : virt_to_page(zone_iodata),
+ alloc_size, GFP_KERNEL);
+
+ if (error)
+ goto report_zones_out;
+
+ if (copy_to_user(parg, zone_iodata, alloc_size))
+ error = -EFAULT;
+
+report_zones_out:
+ if (pgs)
+ __free_pages(pgs, order);
+ else if (zone_iodata)
+ free_page((unsigned long)zone_iodata);
+ return error;
+}
+
+static int blk_zoned_action_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned long bi_rw = 0;
+
+ if (!(mode & FMODE_WRITE))
+ return -EBADF;
+
+ /*
+ * When acting on zones we explicitly disallow using a partition.
+ */
+ if (bdev != bdev->bd_contains) {
+ pr_err("%s: All zone operations disallowed on this device\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case BLKOPENZONE:
+ bi_rw |= REQ_OPEN_ZONE;
+ break;
+ case BLKCLOSEZONE:
+ bi_rw |= REQ_CLOSE_ZONE;
+ break;
+ case BLKRESETZONE:
+ bi_rw |= REQ_RESET_ZONE;
+ break;
+ default:
+ pr_err("%s: Unknown action: %u\n", __func__, cmd);
+ WARN_ON(1);
+ }
+ return blkdev_issue_zone_action(bdev, bi_rw, arg, GFP_KERNEL);
+}
+
static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
unsigned long arg, unsigned long flags)
{
@@ -568,6 +675,12 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
case BLKTRACESETUP:
case BLKTRACETEARDOWN:
return blk_trace_ioctl(bdev, cmd, argp);
+ case BLKREPORT:
+ return blk_zoned_report_ioctl(bdev, mode, argp);
+ case BLKOPENZONE:
+ case BLKCLOSEZONE:
+ case BLKRESETZONE:
+ return blk_zoned_action_ioctl(bdev, mode, cmd, arg);
case IOC_PR_REGISTER:
return blkdev_pr_register(bdev, argp);
case IOC_PR_RESERVE:
diff --git a/include/uapi/linux/blkzoned_api.h b/include/uapi/linux/blkzoned_api.h
index 189e925..2007b56 100644
--- a/include/uapi/linux/blkzoned_api.h
+++ b/include/uapi/linux/blkzoned_api.h
@@ -212,4 +212,10 @@ struct bdev_zone_report_io {
} data;
} __packed;
+/* continuing from uapi/linux/fs.h: */
+#define BLKREPORT _IOWR(0x12, 130, struct bdev_zone_report_io)
+#define BLKOPENZONE _IO(0x12, 131)
+#define BLKCLOSEZONE _IO(0x12, 132)
+#define BLKRESETZONE _IO(0x12, 133)
+
#endif /* _UAPI_BLKZONED_API_H */
--
2.8.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/4] Add ata pass-through path for ZAC commands.
2016-06-06 15:39 [PATCH 0/4] Block layer support ZAC/ZBC commands Shaun Tancheff
` (2 preceding siblings ...)
2016-06-06 15:39 ` [PATCH 3/4] Add ioctl to issue ZBC/ZAC commands via block layer Shaun Tancheff
@ 2016-06-06 15:39 ` Shaun Tancheff
3 siblings, 0 replies; 7+ messages in thread
From: Shaun Tancheff @ 2016-06-06 15:39 UTC (permalink / raw)
To: linux-ide, linux-block, linux-scsi; +Cc: Shaun Tancheff, Shaun Tancheff
The current generation of HBA SAS adapters support connecting SATA
drives and perform SCSI<->ATA translations in hardware.
Unfortunately the ZBC commands are not being translate (yet).
Currently users of SAS controllers can only send ZAC commands via
ata pass-through.
This method overloads the meaning of REQ_META to direct ZBC commands
to construct ZAC equivalent ATA pass through commands.
Note also that this approach expects the initiator to deal with the
little endian result due to bypassing the normal translation layers.
Signed-off-by: Shaun Tancheff <shaun.tancheff@seagate.com>
---
block/ioctl.c | 29 ++++++++++++++++++++++
drivers/scsi/sd.c | 70 +++++++++++++++++++++++++++++++++++++++++------------
include/linux/ata.h | 15 ++++++++++++
3 files changed, 99 insertions(+), 15 deletions(-)
diff --git a/block/ioctl.c b/block/ioctl.c
index 46a8553..03a5808 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -284,6 +284,35 @@ static int blk_zoned_action_ioctl(struct block_device *bdev, fmode_t mode,
return -EFAULT;
}
+ /*
+ * When the low bit is set force ATA passthrough try to work around
+ * older SAS HBA controllers that don't support ZBC to ZAC translation.
+ *
+ * When the low bit is clear follow the normal path but also correct
+ * for ~0ul LBA means 'for all lbas'.
+ *
+ * NB: We should do extra checking here to see if the user specified
+ * the entire block device as opposed to a partition of the
+ * device....
+ */
+ if (arg & 1) {
+ bi_rw |= REQ_META;
+ if (arg != ~0ul)
+ arg &= ~1ul; /* ~1 :: 0xFF...FE */
+ } else {
+ if (arg == ~1ul)
+ arg = ~0ul;
+ }
+
+ /*
+ * When acting on zones we explicitly disallow using a partition.
+ */
+ if (bdev != bdev->bd_contains) {
+ pr_err("%s: All zone operations disallowed on this device\n",
+ __func__);
+ return -EFAULT;
+ }
+
switch (cmd) {
case BLKOPENZONE:
bi_rw |= REQ_OPEN_ZONE;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 372b5e2..177d5fb 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -53,6 +53,7 @@
#include <linux/pm_runtime.h>
#include <linux/pr.h>
#include <linux/blkzoned_api.h>
+#include <linux/ata.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
@@ -1182,12 +1183,29 @@ static int sd_setup_zoned_cmnd(struct scsi_cmnd *cmd)
cmd->cmd_len = 16;
memset(cmd->cmnd, 0, cmd->cmd_len);
- cmd->cmnd[0] = ZBC_IN;
- cmd->cmnd[1] = ZI_REPORT_ZONES;
- put_unaligned_be64(sector, &cmd->cmnd[2]);
- put_unaligned_be32(nr_bytes, &cmd->cmnd[10]);
- /* FUTURE ... when streamid is available */
- /* cmd->cmnd[14] = bio_get_streamid(bio); */
+ if (rq->cmd_flags & REQ_META) {
+ cmd->cmnd[0] = ATA_16;
+ cmd->cmnd[1] = (0x6 << 1) | 1;
+ cmd->cmnd[2] = 0x0e;
+ /* FUTURE ... when streamid is available */
+ /* cmd->cmnd[3] = bio_get_streamid(bio); */
+ cmd->cmnd[4] = ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES;
+ cmd->cmnd[5] = ((nr_bytes / 512) >> 8) & 0xff;
+ cmd->cmnd[6] = (nr_bytes / 512) & 0xff;
+
+ _lba_to_cmd_ata(&cmd->cmnd[7], sector);
+
+ cmd->cmnd[13] = 1 << 6;
+ cmd->cmnd[14] = ATA_CMD_ZAC_MGMT_IN;
+ } else {
+ cmd->cmnd[0] = ZBC_IN;
+ cmd->cmnd[1] = ZI_REPORT_ZONES;
+ put_unaligned_be64(sector, &cmd->cmnd[2]);
+ put_unaligned_be32(nr_bytes, &cmd->cmnd[10]);
+ /* FUTURE ... when streamid is available */
+ /* cmd->cmnd[14] = bio_get_streamid(bio); */
+ }
+
cmd->sc_data_direction = DMA_FROM_DEVICE;
cmd->sdb.length = nr_bytes;
cmd->transfersize = sdp->sector_size;
@@ -1208,14 +1226,29 @@ static int sd_setup_zoned_cmnd(struct scsi_cmnd *cmd)
cmd->cmd_len = 16;
memset(cmd->cmnd, 0, cmd->cmd_len);
memset(&cmd->sdb, 0, sizeof(cmd->sdb));
- cmd->cmnd[0] = ZBC_OUT;
- cmd->cmnd[1] = ZO_OPEN_ZONE;
- if (rq->cmd_flags & REQ_CLOSE_ZONE)
- cmd->cmnd[1] = ZO_CLOSE_ZONE;
- if (rq->cmd_flags & REQ_RESET_ZONE)
- cmd->cmnd[1] = ZO_RESET_WRITE_POINTER;
- cmd->cmnd[14] = allbit;
- put_unaligned_be64(sector, &cmd->cmnd[2]);
+ if (rq->cmd_flags & REQ_META) {
+ cmd->cmnd[0] = ATA_16;
+ cmd->cmnd[1] = (3 << 1) | 1;
+ cmd->cmnd[3] = allbit;
+ cmd->cmnd[4] = ATA_SUBCMD_ZAC_MGMT_OUT_RESET_WRITE_POINTER;
+ if (rq->cmd_flags & REQ_OPEN_ZONE)
+ cmd->cmnd[4] = ATA_SUBCMD_ZAC_MGMT_OUT_OPEN_ZONE;
+ if (rq->cmd_flags & REQ_CLOSE_ZONE)
+ cmd->cmnd[4] = ATA_SUBCMD_ZAC_MGMT_OUT_CLOSE_ZONE;
+ _lba_to_cmd_ata(&cmd->cmnd[7], sector);
+ cmd->cmnd[13] = 1 << 6;
+ cmd->cmnd[14] = ATA_CMD_ZAC_MGMT_OUT;
+ } else {
+ cmd->cmnd[0] = ZBC_OUT;
+ cmd->cmnd[1] = ZO_OPEN_ZONE;
+ if (rq->cmd_flags & REQ_CLOSE_ZONE)
+ cmd->cmnd[1] = ZO_CLOSE_ZONE;
+ if (rq->cmd_flags & REQ_RESET_ZONE)
+ cmd->cmnd[1] = ZO_RESET_WRITE_POINTER;
+ cmd->cmnd[14] = allbit;
+ put_unaligned_be64(sector, &cmd->cmnd[2]);
+ }
+
cmd->transfersize = 0;
cmd->underflow = 0;
cmd->allowed = SD_MAX_RETRIES;
@@ -2806,7 +2839,7 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
{
unsigned char *buffer;
u16 rot;
- const int vpd_len = 64;
+ const int vpd_len = 512;
buffer = kmalloc(vpd_len, GFP_KERNEL);
@@ -2823,6 +2856,13 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
}
sdkp->zoned = (buffer[8] >> 4) & 3;
+ if (sdkp->zoned != 1) {
+ struct scsi_device *sdev = sdkp->device;
+
+ /* buf size is 512, page is 60 + 512, we need page 206 */
+ if (!scsi_get_vpd_page(sdev, 0x89, buffer, SD_BUF_SIZE))
+ sdkp->zoned = ata_id_zoned_cap((u16 *)&buffer[60]);
+ }
out:
kfree(buffer);
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 99346be..5cc1a85 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -1060,6 +1060,21 @@ static inline void ata_id_to_hd_driveid(u16 *id)
#endif
}
+/**
+ * _lba_to_cmd_ata() - Copy lba48 to ATA command
+ * @cmd: ATA command as an array of bytes
+ * @_lba: lba48 in the low 48 bits
+ */
+static inline void _lba_to_cmd_ata(u8 *cmd, u64 _lba)
+{
+ cmd[1] = _lba & 0xff;
+ cmd[3] = (_lba >> 8) & 0xff;
+ cmd[5] = (_lba >> 16) & 0xff;
+ cmd[0] = (_lba >> 24) & 0xff;
+ cmd[2] = (_lba >> 32) & 0xff;
+ cmd[4] = (_lba >> 40) & 0xff;
+}
+
/*
* Write LBA Range Entries to the buffer that will cover the extent from
* sector to sector + count. This is used for TRIM and for ADD LBA(S)
--
2.8.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/4] Add bio/request flags for using ZBC/ZAC commands
2016-06-06 15:39 ` [PATCH 2/4] Add bio/request flags for using ZBC/ZAC commands Shaun Tancheff
2016-06-06 15:23 ` kbuild test robot
@ 2016-06-06 19:26 ` Shaun Tancheff
1 sibling, 0 replies; 7+ messages in thread
From: Shaun Tancheff @ 2016-06-06 19:26 UTC (permalink / raw)
To: Shaun Tancheff; +Cc: linux-ide, linux-block, linux-scsi
On Mon, Jun 6, 2016 at 10:39 AM, Shaun Tancheff <shaun@tancheff.com> wrote:
>
> T10 ZBC and T13 ZAC specify operations for Zoned devices.
>
> To be able to access the zone information and open and close zones
> adding flags for the report zones command (REQ_REPORT_ZONES) and for
> Open and Close zone (REQ_OPEN_ZONE and REQ_CLOSE_ZONE) can be added
> for use by struct bio's bi_rw and by struct request's cmd_flags.
>
> To reduce the number of additional flags needed REQ_RESET_ZONE shares
> the same flag as REQ_REPORT_ZONES and is differentiated by direction.
> Report zones is a device read that requires a buffer. Reset is a device
> command (WRITE) that has no associated data transfer.
>
> The Finish zone command is intentionally not implimented as there is no
> current use case for that operation.
>
> Report zones currently defaults to reporting on all zones. It expected
> that support for the zone option flag will piggy back on streamid
> support. The report option is useful as it can reduce the number of
> zones in each report, but not critical.
>
> Signed-off-by: Shaun Tancheff <shaun.tancheff@seagate.com>
> ---
> MAINTAINERS | 9 ++
> block/blk-lib.c | 96 +++++++++++++++++
> drivers/scsi/sd.c | 99 +++++++++++++++++-
> drivers/scsi/sd.h | 1 +
> include/linux/blk_types.h | 19 +++-
> include/linux/blkzoned_api.h | 25 +++++
> include/uapi/linux/Kbuild | 1 +
> include/uapi/linux/blkzoned_api.h | 215 ++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/fs.h | 1 +
> 9 files changed, 461 insertions(+), 5 deletions(-)
> create mode 100644 include/linux/blkzoned_api.h
> create mode 100644 include/uapi/linux/blkzoned_api.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7304d2e..0b71a3c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -12660,6 +12660,15 @@ F: Documentation/networking/z8530drv.txt
> F: drivers/net/hamradio/*scc.c
> F: drivers/net/hamradio/z8530.h
>
> +ZBC AND ZBC BLOCK DEVICES
> +M: Shaun Tancheff <shaun.tancheff@seagate.com>
> +W: http://seagate.com
> +W: https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_Seagate_ZDM-2DDevice-2DMapper&d=CwIBAg&c=IGDlg0lD0b-nebmJJ0Kp8A&r=Wg5NqlNlVTT7Ugl8V50qIHLe856QW0qfG3WVYGOrWzA&m=NgIOfWitaBWSqZoCVyVSkoMDm3cP1ofhQL7wPM1Z-xA&s=gEau_a22IpcIHd6A3J6ovk5P_nay7XAov8OoSfJdTXs&e=
> +L: linux-block@vger.kernel.org
> +S: Maintained
> +F: include/linux/blkzoned_api.h
> +F: include/uapi/linux/blkzoned_api.h
> +
> ZBUD COMPRESSED PAGE ALLOCATOR
> M: Seth Jennings <sjenning@redhat.com>
> L: linux-mm@kvack.org
> diff --git a/block/blk-lib.c b/block/blk-lib.c
> index 23d7f30..a7f047c 100644
> --- a/block/blk-lib.c
> +++ b/block/blk-lib.c
> @@ -6,6 +6,7 @@
> #include <linux/bio.h>
> #include <linux/blkdev.h>
> #include <linux/scatterlist.h>
> +#include <linux/blkzoned_api.h>
>
> #include "blk.h"
>
> @@ -249,3 +250,98 @@ int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
> return __blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask);
> }
> EXPORT_SYMBOL(blkdev_issue_zeroout);
> +
> +/**
> + * blkdev_issue_zone_report - queue a report zones operation
> + * @bdev: target blockdev
> + * @bi_rw: extra bio rw flags. If unsure, use 0.
> + * @sector: starting sector (report will include this sector).
Missing:
* @opt: See: zone_report_option, default is 0 (all zones)
> + * @page: one or more contiguous pages.
> + * @pgsz: up to size of page in bytes, size of report.
> + * @gfp_mask: memory allocation flags (for bio_alloc)
> + *
> + * Description:
> + * Issue a zone report request for the sectors in question.
> + */
> +int blkdev_issue_zone_report(struct block_device *bdev, unsigned int bi_rw,
> + sector_t sector, u8 opt, struct page *page,
> + size_t pgsz, gfp_t gfp_mask)
> +{
> + struct bdev_zone_report *conv = page_address(page);
> + struct bio *bio;
> + unsigned int nr_iovecs = 1;
> + int ret = 0;
> +
> + if (pgsz < (sizeof(struct bdev_zone_report) +
> + sizeof(struct bdev_zone_descriptor)))
> + return -EINVAL;
> +
> + bio = bio_alloc(gfp_mask, nr_iovecs);
> + if (!bio)
> + return -ENOMEM;
> +
> + conv->descriptor_count = 0;
> + bio->bi_iter.bi_sector = sector;
> + bio->bi_bdev = bdev;
> + bio->bi_vcnt = 0;
> + bio->bi_iter.bi_size = 0;
> +
> + bi_rw |= REQ_REPORT_ZONES;
> +
> + /* FUTURE ... when streamid is available: */
> + /* bio_set_streamid(bio, opt); */
> +
> + bio_add_page(bio, page, pgsz, 0);
> + ret = submit_bio_wait(READ | bi_rw, bio);
> +
> + /*
> + * When our request it nak'd the underlying device maybe conventional
> + * so ... report a single conventional zone the size of the device.
> + */
> + if (ret == -EIO && conv->descriptor_count) {
> + /* Adjust the conventional to the size of the partition ... */
> + __be64 blksz = cpu_to_be64(bdev->bd_part->nr_sects);
> +
> + conv->maximum_lba = blksz;
> + conv->descriptors[0].type = ZTYP_CONVENTIONAL;
> + conv->descriptors[0].flags = ZCOND_CONVENTIONAL << 4;
> + conv->descriptors[0].length = blksz;
> + conv->descriptors[0].lba_start = 0;
> + conv->descriptors[0].lba_wptr = blksz;
> + return 0;
Memory leak here ... return should be to fall through and put bio.
ret = 0;
>
> + }
> + bio_put(bio);
> + return ret;
> +}
> +EXPORT_SYMBOL(blkdev_issue_zone_report);
> +
> +/**
> + * blkdev_issue_zone_action - queue a report zones operation
> + * @bdev: target blockdev
> + * @bi_rw: REQ_OPEN_ZONE, REQ_CLOSE_ZONE, or REQ_RESET_ZONE.
> + * @sector: starting lba of sector
> + * @gfp_mask: memory allocation flags (for bio_alloc)
> + *
> + * Description:
> + * Issue a zone report request for the sectors in question.
> + */
> +int blkdev_issue_zone_action(struct block_device *bdev, unsigned int bi_rw,
> + sector_t sector, gfp_t gfp_mask)
> +{
> + int ret;
> + struct bio *bio;
> +
> + bio = bio_alloc(gfp_mask, 1);
> + if (!bio)
> + return -ENOMEM;
> +
> + bio->bi_iter.bi_sector = sector;
> + bio->bi_bdev = bdev;
> + bio->bi_vcnt = 0;
> + bio->bi_iter.bi_size = 0;
> +
> + ret = submit_bio_wait(WRITE | bi_rw, bio);
> + bio_put(bio);
> + return ret;
> +}
> +EXPORT_SYMBOL(blkdev_issue_zone_action);
> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
> index 428c03e..372b5e2 100644
> --- a/drivers/scsi/sd.c
> +++ b/drivers/scsi/sd.c
> @@ -52,6 +52,7 @@
> #include <linux/slab.h>
> #include <linux/pm_runtime.h>
> #include <linux/pr.h>
> +#include <linux/blkzoned_api.h>
> #include <asm/uaccess.h>
> #include <asm/unaligned.h>
>
> @@ -1133,11 +1134,105 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
> return ret;
> }
>
> +static int sd_setup_zoned_cmnd(struct scsi_cmnd *cmd)
> +{
> + struct request *rq = cmd->request;
> + struct scsi_device *sdp = cmd->device;
> + struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
> + struct bio *bio = rq->bio;
> + sector_t sector = blk_rq_pos(rq);
> + struct gendisk *disk = rq->rq_disk;
> + unsigned int nr_bytes = blk_rq_bytes(rq);
> + int ret = BLKPREP_KILL;
> + u8 allbit = 0;
> +
> + if (rq->cmd_flags & REQ_REPORT_ZONES && rq_data_dir(rq) == READ) {
> + WARN_ON(nr_bytes == 0);
> +
> + /*
> + * For conventional drives generate a report that shows a
> + * large single convetional zone the size of the block device
> + */
> + if (sdkp->zoned != 1 && sdkp->device->type != TYPE_ZBC) {
> + void *src;
> + struct bdev_zone_report *conv;
> +
> + if (nr_bytes < sizeof(struct bdev_zone_report))
> + goto out;
> +
> + src = kmap_atomic(bio->bi_io_vec->bv_page);
> + conv = src + bio->bi_io_vec->bv_offset;
> + conv->descriptor_count = cpu_to_be32(1);
> + conv->same_field = ZS_ALL_SAME;
> + conv->maximum_lba = cpu_to_be64(disk->part0.nr_sects);
> + kunmap_atomic(src);
> + goto out;
> + }
> +
> + ret = scsi_init_io(cmd);
> + if (ret != BLKPREP_OK)
> + goto out;
> +
> + cmd = rq->special;
> + if (sdp->changed) {
> + pr_err("SCSI disk has been changed or is not present.");
> + ret = BLKPREP_KILL;
> + goto out;
> + }
> +
> + cmd->cmd_len = 16;
> + memset(cmd->cmnd, 0, cmd->cmd_len);
> + cmd->cmnd[0] = ZBC_IN;
> + cmd->cmnd[1] = ZI_REPORT_ZONES;
> + put_unaligned_be64(sector, &cmd->cmnd[2]);
> + put_unaligned_be32(nr_bytes, &cmd->cmnd[10]);
> + /* FUTURE ... when streamid is available */
> + /* cmd->cmnd[14] = bio_get_streamid(bio); */
> + cmd->sc_data_direction = DMA_FROM_DEVICE;
> + cmd->sdb.length = nr_bytes;
> + cmd->transfersize = sdp->sector_size;
> + cmd->underflow = 0;
> + cmd->allowed = SD_MAX_RETRIES;
> + ret = BLKPREP_OK;
> + goto out;
> + }
> +
> + if (sdkp->zoned != 1 && sdkp->device->type != TYPE_ZBC)
> + goto out;
> +
> + if (sector == ~0ul) {
> + allbit = 1;
> + sector = 0;
> + }
> +
> + cmd->cmd_len = 16;
> + memset(cmd->cmnd, 0, cmd->cmd_len);
> + memset(&cmd->sdb, 0, sizeof(cmd->sdb));
> + cmd->cmnd[0] = ZBC_OUT;
> + cmd->cmnd[1] = ZO_OPEN_ZONE;
> + if (rq->cmd_flags & REQ_CLOSE_ZONE)
> + cmd->cmnd[1] = ZO_CLOSE_ZONE;
> + if (rq->cmd_flags & REQ_RESET_ZONE)
> + cmd->cmnd[1] = ZO_RESET_WRITE_POINTER;
> + cmd->cmnd[14] = allbit;
> + put_unaligned_be64(sector, &cmd->cmnd[2]);
> + cmd->transfersize = 0;
> + cmd->underflow = 0;
> + cmd->allowed = SD_MAX_RETRIES;
> + cmd->sc_data_direction = DMA_NONE;
> +
> + ret = BLKPREP_OK;
> +out:
> + return ret;
> +}
> +
> static int sd_init_command(struct scsi_cmnd *cmd)
> {
> struct request *rq = cmd->request;
>
> - if (rq->cmd_flags & REQ_DISCARD)
> + if (rq->cmd_flags & REQ_ZONED_CMDS)
> + return sd_setup_zoned_cmnd(cmd);
> + else if (rq->cmd_flags & REQ_DISCARD)
> return sd_setup_discard_cmnd(cmd);
> else if (rq->cmd_flags & REQ_WRITE_SAME)
> return sd_setup_write_same_cmnd(cmd);
> @@ -2727,6 +2822,8 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
> queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, sdkp->disk->queue);
> }
>
> + sdkp->zoned = (buffer[8] >> 4) & 3;
> +
> out:
> kfree(buffer);
> }
> diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
> index 654630b..e012175 100644
> --- a/drivers/scsi/sd.h
> +++ b/drivers/scsi/sd.h
> @@ -94,6 +94,7 @@ struct scsi_disk {
> unsigned lbpvpd : 1;
> unsigned ws10 : 1;
> unsigned ws16 : 1;
> + unsigned zoned: 2;
> };
> #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
>
> diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
> index 77e5d81..d2943e4 100644
> --- a/include/linux/blk_types.h
> +++ b/include/linux/blk_types.h
> @@ -162,6 +162,10 @@ enum rq_flag_bits {
> __REQ_FUA, /* forced unit access */
> __REQ_FLUSH, /* request for cache flush */
>
> + __REQ_REPORT_ZONES, /* Zoned device: Report Zones */
> + __REQ_OPEN_ZONE, /* Zoned device: Open Zone */
> + __REQ_CLOSE_ZONE, /* Zoned device: Close Zone */
> +
> /* bio only flags */
> __REQ_RAHEAD, /* read ahead, can fail anytime */
> __REQ_THROTTLED, /* This bio has already been subjected to
> @@ -202,20 +206,27 @@ enum rq_flag_bits {
> #define REQ_WRITE_SAME (1ULL << __REQ_WRITE_SAME)
> #define REQ_NOIDLE (1ULL << __REQ_NOIDLE)
> #define REQ_INTEGRITY (1ULL << __REQ_INTEGRITY)
> +#define REQ_REPORT_ZONES (1ULL << __REQ_REPORT_ZONES)
> +#define REQ_OPEN_ZONE (1ULL << __REQ_OPEN_ZONE)
> +#define REQ_CLOSE_ZONE (1ULL << __REQ_CLOSE_ZONE)
> +#define REQ_RESET_ZONE (REQ_REPORT_ZONES)
> +#define REQ_ZONED_CMDS \
> + (REQ_OPEN_ZONE | REQ_CLOSE_ZONE | REQ_RESET_ZONE | REQ_REPORT_ZONES)
>
> #define REQ_FAILFAST_MASK \
> (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER)
> #define REQ_COMMON_MASK \
> (REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_PRIO | \
> REQ_DISCARD | REQ_WRITE_SAME | REQ_NOIDLE | REQ_FLUSH | REQ_FUA | \
> - REQ_SECURE | REQ_INTEGRITY | REQ_NOMERGE)
> + REQ_SECURE | REQ_INTEGRITY | REQ_NOMERGE | REQ_ZONED_CMDS)
> #define REQ_CLONE_MASK REQ_COMMON_MASK
> -
> -#define BIO_NO_ADVANCE_ITER_MASK (REQ_DISCARD|REQ_WRITE_SAME)
> +#define BIO_NO_ADVANCE_ITER_MASK \
> + (REQ_DISCARD | REQ_WRITE_SAME | REQ_ZONED_CMDS)
>
> /* This mask is used for both bio and request merge checking */
> #define REQ_NOMERGE_FLAGS \
> - (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA | REQ_FLUSH_SEQ)
> + (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | \
> + REQ_FLUSH | REQ_FUA | REQ_FLUSH_SEQ | REQ_ZONED_CMDS)
>
> #define REQ_RAHEAD (1ULL << __REQ_RAHEAD)
> #define REQ_THROTTLED (1ULL << __REQ_THROTTLED)
> diff --git a/include/linux/blkzoned_api.h b/include/linux/blkzoned_api.h
> new file mode 100644
> index 0000000..6061983
> --- /dev/null
> +++ b/include/linux/blkzoned_api.h
> @@ -0,0 +1,25 @@
> +/*
> + * Functions for zone based SMR devices.
> + *
> + * Copyright (C) 2015 Seagate Technology PLC
> + *
> + * Written by:
> + * Shaun Tancheff <shaun.tancheff@seagate.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _BLKZONED_API_H
> +#define _BLKZONED_API_H
> +
> +#include <uapi/linux/blkzoned_api.h>
> +
> +extern int blkdev_issue_zone_action(struct block_device *, unsigned int bi_rw,
> + sector_t, gfp_t);
> +extern int blkdev_issue_zone_report(struct block_device *, unsigned int bi_rw,
> + sector_t, u8 opt, struct page *, size_t,
> + gfp_t);
> +
> +#endif /* _BLKZONED_API_H */
> diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
> index 8bdae34..5152fa4 100644
> --- a/include/uapi/linux/Kbuild
> +++ b/include/uapi/linux/Kbuild
> @@ -70,6 +70,7 @@ header-y += bfs_fs.h
> header-y += binfmts.h
> header-y += blkpg.h
> header-y += blktrace_api.h
> +header-y += blkzoned_api.h
> header-y += bpf_common.h
> header-y += bpf.h
> header-y += bpqether.h
> diff --git a/include/uapi/linux/blkzoned_api.h b/include/uapi/linux/blkzoned_api.h
> new file mode 100644
> index 0000000..189e925
> --- /dev/null
> +++ b/include/uapi/linux/blkzoned_api.h
> @@ -0,0 +1,215 @@
> +/*
> + * Functions for zone based SMR devices.
> + *
> + * Copyright (C) 2015 Seagate Technology PLC
> + *
> + * Written by:
> + * Shaun Tancheff <shaun.tancheff@seagate.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _UAPI_BLKZONED_API_H
> +#define _UAPI_BLKZONED_API_H
> +
> +#include <linux/types.h>
> +
> +/**
> + * enum zone_report_option - Report Zones types to be included.
> + *
> + * @ZOPT_NON_SEQ_AND_RESET: Default (all zones).
> + * @ZOPT_ZC1_EMPTY: Zones which are empty.
> + * @ZOPT_ZC2_OPEN_IMPLICIT: Zones open but not explicitly opened
> + * @ZOPT_ZC3_OPEN_EXPLICIT: Zones opened explicitly
> + * @ZOPT_ZC4_CLOSED: Zones closed for writing.
> + * @ZOPT_ZC5_FULL: Zones that are full.
> + * @ZOPT_ZC6_READ_ONLY: Zones that are read-only
> + * @ZOPT_ZC7_OFFLINE: Zones that are offline
> + * @ZOPT_RESET: Zones that are empty
> + * @ZOPT_NON_SEQ: Zones that have HA media-cache writes pending
> + * @ZOPT_NON_WP_ZONES: Zones that do not have Write Pointers (conventional)
> + *
> + * @ZOPT_USE_ATA_PASS: Flag used in kernel to service command I/O
> + *
> + * Used by Report Zones in bdev_zone_get_report: report_option
> + */
> +enum zone_report_option {
> + ZOPT_NON_SEQ_AND_RESET = 0x00,
> + ZOPT_ZC1_EMPTY,
> + ZOPT_ZC2_OPEN_IMPLICIT,
> + ZOPT_ZC3_OPEN_EXPLICIT,
> + ZOPT_ZC4_CLOSED,
> + ZOPT_ZC5_FULL,
> + ZOPT_ZC6_READ_ONLY,
> + ZOPT_ZC7_OFFLINE,
> + ZOPT_RESET = 0x10,
> + ZOPT_NON_SEQ = 0x11,
> + ZOPT_NON_WP_ZONES = 0x3f,
> + ZOPT_USE_ATA_PASS = 0x80,
> +};
> +
> +/**
> + * enum bdev_zone_type - Type of zone in descriptor
> + *
> + * @ZTYP_RESERVED: Reserved
> + * @ZTYP_CONVENTIONAL: Conventional random write zone (No Write Pointer)
> + * @ZTYP_SEQ_WRITE_REQUIRED: Non-sequential writes are rejected.
> + * @ZTYP_SEQ_WRITE_PREFERRED: Non-sequential writes allowed but discouraged.
> + *
> + * Returned from Report Zones. See bdev_zone_descriptor* type.
> + */
> +enum bdev_zone_type {
> + ZTYP_RESERVED = 0,
> + ZTYP_CONVENTIONAL = 1,
> + ZTYP_SEQ_WRITE_REQUIRED = 2,
> + ZTYP_SEQ_WRITE_PREFERRED = 3,
> +};
> +
> +
> +/**
> + * enum bdev_zone_condition - Condition of zone in descriptor
> + *
> + * @ZCOND_CONVENTIONAL: N/A
> + * @ZCOND_ZC1_EMPTY: Empty
> + * @ZCOND_ZC2_OPEN_IMPLICIT: Opened via write to zone.
> + * @ZCOND_ZC3_OPEN_EXPLICIT: Opened via open zone command.
> + * @ZCOND_ZC4_CLOSED: Closed
> + * @ZCOND_ZC6_READ_ONLY:
> + * @ZCOND_ZC5_FULL: No remaining space in zone.
> + * @ZCOND_ZC7_OFFLINE: Offline
> + *
> + * Returned from Report Zones. See bdev_zone_descriptor* flags.
> + */
> +enum bdev_zone_condition {
> + ZCOND_CONVENTIONAL = 0,
> + ZCOND_ZC1_EMPTY = 1,
> + ZCOND_ZC2_OPEN_IMPLICIT = 2,
> + ZCOND_ZC3_OPEN_EXPLICIT = 3,
> + ZCOND_ZC4_CLOSED = 4,
> + /* 0x5 to 0xC are reserved */
> + ZCOND_ZC6_READ_ONLY = 0xd,
> + ZCOND_ZC5_FULL = 0xe,
> + ZCOND_ZC7_OFFLINE = 0xf,
> +};
> +
> +
> +/**
> + * enum bdev_zone_same - Report Zones same code.
> + *
> + * @ZS_ALL_DIFFERENT: All zones differ in type and size.
> + * @ZS_ALL_SAME: All zones are the same size and type.
> + * @ZS_LAST_DIFFERS: All zones are the same size and type except the last zone.
> + * @ZS_SAME_LEN_DIFF_TYPES: All zones are the same length but types differ.
> + *
> + * Returned from Report Zones. See bdev_zone_report* same_field.
> + */
> +enum bdev_zone_same {
> + ZS_ALL_DIFFERENT = 0,
> + ZS_ALL_SAME = 1,
> + ZS_LAST_DIFFERS = 2,
> + ZS_SAME_LEN_DIFF_TYPES = 3,
> +};
> +
> +
> +/**
> + * struct bdev_zone_get_report - ioctl: Report Zones request
> + *
> + * @zone_locator_lba: starting lba for first [reported] zone
> + * @return_page_count: number of *bytes* allocated for result
> + * @report_option: see: zone_report_option enum
> + *
> + * Used to issue report zones command to connected device
> + */
> +struct bdev_zone_get_report {
> + __u64 zone_locator_lba;
> + __u32 return_page_count;
> + __u8 report_option;
> +} __packed;
> +
> +/**
> + * struct bdev_zone_descriptor_le - See: bdev_zone_descriptor
> + */
> +struct bdev_zone_descriptor_le {
> + __u8 type;
> + __u8 flags;
> + __u8 reserved1[6];
> + __le64 length;
> + __le64 lba_start;
> + __le64 lba_wptr;
> + __u8 reserved[32];
> +} __packed;
> +
> +
> +/**
> + * struct bdev_zone_report_le - See: bdev_zone_report
> + */
> +struct bdev_zone_report_le {
> + __le32 descriptor_count;
> + __u8 same_field;
> + __u8 reserved1[3];
> + __le64 maximum_lba;
> + __u8 reserved2[48];
> + struct bdev_zone_descriptor_le descriptors[0];
> +} __packed;
> +
> +
> +/**
> + * struct bdev_zone_descriptor - A Zone descriptor entry from report zones
> + *
> + * @type: see zone_type enum
> + * @flags: Bits 0:reset, 1:non-seq, 2-3: resv, 4-7: see zone_condition enum
> + * @reserved1: padding
> + * @length: length of zone in sectors
> + * @lba_start: lba where the zone starts.
> + * @lba_wptr: lba of the current write pointer.
> + * @reserved: padding
> + *
> + */
> +struct bdev_zone_descriptor {
> + __u8 type;
> + __u8 flags;
> + __u8 reserved1[6];
> + __be64 length;
> + __be64 lba_start;
> + __be64 lba_wptr;
> + __u8 reserved[32];
> +} __packed;
> +
> +
> +/**
> + * struct bdev_zone_report - Report Zones result
> + *
> + * @descriptor_count: Number of descriptor entries that follow
> + * @same_field: bits 0-3: enum zone_same (MASK: 0x0F)
> + * @reserved1: padding
> + * @maximum_lba: LBA of the last logical sector on the device, inclusive
> + * of all logical sectors in all zones.
> + * @reserved2: padding
> + * @descriptors: array of descriptors follows.
> + */
> +struct bdev_zone_report {
> + __be32 descriptor_count;
> + __u8 same_field;
> + __u8 reserved1[3];
> + __be64 maximum_lba;
> + __u8 reserved2[48];
> + struct bdev_zone_descriptor descriptors[0];
> +} __packed;
> +
> +
> +/**
> + * struct bdev_zone_report_io - Report Zones ioctl argument.
> + *
> + * @in: Report Zones inputs
> + * @out: Report Zones output
> + */
> +struct bdev_zone_report_io {
> + union {
> + struct bdev_zone_get_report in;
> + struct bdev_zone_report out;
> + } data;
> +} __packed;
> +
> +#endif /* _UAPI_BLKZONED_API_H */
> diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
> index 3b00f7c..c0b565b 100644
> --- a/include/uapi/linux/fs.h
> +++ b/include/uapi/linux/fs.h
> @@ -222,6 +222,7 @@ struct fsxattr {
> #define BLKSECDISCARD _IO(0x12,125)
> #define BLKROTATIONAL _IO(0x12,126)
> #define BLKZEROOUT _IO(0x12,127)
> +/* A jump here: See blkzoned_api.h, Reserving 130 to 133. */
>
> #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
> #define FIBMAP _IO(0x00,1) /* bmap access */
> --
> 2.8.1
>
--
Shaun Tancheff
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2016-06-06 19:26 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-06-06 15:39 [PATCH 0/4] Block layer support ZAC/ZBC commands Shaun Tancheff
2016-06-06 15:39 ` [PATCH 1/4] Add support for SCT Write Same Shaun Tancheff
2016-06-06 15:39 ` [PATCH 2/4] Add bio/request flags for using ZBC/ZAC commands Shaun Tancheff
2016-06-06 15:23 ` kbuild test robot
2016-06-06 19:26 ` Shaun Tancheff
2016-06-06 15:39 ` [PATCH 3/4] Add ioctl to issue ZBC/ZAC commands via block layer Shaun Tancheff
2016-06-06 15:39 ` [PATCH 4/4] Add ata pass-through path for ZAC commands Shaun Tancheff
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).