diff options
author | Damien Le Moal <damien.lemoal@wdc.com> | 2016-10-28 16:57:00 +0900 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2016-11-01 17:27:34 -0700 |
commit | 9691420a990b81895c47b08be14b74d5ce8f8da4 (patch) | |
tree | d975ec28451dc70fc15badb1be5b5a58e04cf0c6 /lib | |
parent | 81c62e2537caaacfd0937b93535006edda73e1b5 (diff) | |
download | android_external_f2fs-tools-9691420a990b81895c47b08be14b74d5ce8f8da4.tar.gz android_external_f2fs-tools-9691420a990b81895c47b08be14b74d5ce8f8da4.tar.bz2 android_external_f2fs-tools-9691420a990b81895c47b08be14b74d5ce8f8da4.zip |
f2fs-tools: introduce support for zoned block devices
With the availability of the BLKREPORTZONE and BLKRESETZONE
ioctls, there is no need for using SG_IO to discover zoned
block devices characteristics. This simplifies the code.
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/libf2fs.c | 36 | ||||
-rw-r--r-- | lib/libf2fs_zoned.c | 294 | ||||
-rw-r--r-- | lib/zbc.c | 647 | ||||
-rw-r--r-- | lib/zbc.h | 361 |
5 files changed, 322 insertions, 1018 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 91e4b4c..b26b404 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -2,7 +2,7 @@ lib_LTLIBRARIES = libf2fs.la -libf2fs_la_SOURCES = libf2fs.c libf2fs_io.c zbc.c +libf2fs_la_SOURCES = libf2fs.c libf2fs_io.c libf2fs_zoned.c libf2fs_la_CFLAGS = -Wall libf2fs_la_CPPFLAGS = -I$(top_srcdir)/include libf2fs_la_LDFLAGS = -version-info $(LIBF2FS_CURRENT):$(LIBF2FS_REVISION):$(LIBF2FS_AGE) diff --git a/lib/libf2fs.c b/lib/libf2fs.c index 5407ff5..0485448 100644 --- a/lib/libf2fs.c +++ b/lib/libf2fs.c @@ -546,6 +546,8 @@ void f2fs_init_configuration(void) c.sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK; c.blks_per_seg = DEFAULT_BLOCKS_PER_SEGMENT; c.rootdev_name = get_rootdev(); + c.zoned_mode = 0; + c.zoned_model = F2FS_ZONED_NONE; /* calculated by overprovision ratio */ c.reserved_segments = 0; @@ -746,17 +748,33 @@ int f2fs_get_device_info(void) } #ifndef WITH_ANDROID - if (c.zoned_mode) { - if (zbc_scsi_report_zones()) { - MSG(0, "\tError: Not proper zoned block device\n"); + if (S_ISBLK(stat_buf.st_mode)) + f2fs_get_zoned_model(); + if (c.zoned_model == F2FS_ZONED_NONE) { + c.zoned_mode = 0; + } else { + if (f2fs_get_zone_blocks()) { + MSG(0, "\tError: Failed to get number of blocks per zone\n"); + return -1; + } + + if (f2fs_check_zones()) { + MSG(0, "\tError: Failed to check zone configuration\n"); return -1; } - MSG(0, "Info: Zoned block device - ZONES = %u, CONV = %u, ZONE_SECTS = %lu\n", - c.nr_zones, c.nr_conventional, - c.zone_sectors); - if (c.segs_per_sec == 1) - c.segs_per_sec = c.zone_sectors / - c.sectors_per_blk / DEFAULT_BLOCKS_PER_SEGMENT; + MSG(0, "Info: Host-%s zoned block device:\n", + (c.zoned_model == F2FS_ZONED_HA) ? + "aware" : "managed"); + MSG(0, " %u zones, %u randomly writeable zones\n", + c.nr_zones, c.nr_rnd_zones); + MSG(0, " %lu blocks per zone\n", + c.zone_blocks); + /* + * Align sections to the device zone size + * and align F2FS zones to the device zones. + */ + c.segs_per_sec = c.zone_blocks / DEFAULT_BLOCKS_PER_SEGMENT; + c.secs_per_zone = 1; } #endif c.segs_per_zone = c.segs_per_sec * c.secs_per_zone; diff --git a/lib/libf2fs_zoned.c b/lib/libf2fs_zoned.c new file mode 100644 index 0000000..4ef4f1d --- /dev/null +++ b/lib/libf2fs_zoned.c @@ -0,0 +1,294 @@ +/** + * libf2fs_zoned.c + * + * Copyright (c) 2016 Western Digital Corporation. + * Written by: Damien Le Moal <damien.lemoal@wdc.com> + * + * Dual licensed under the GPL or LGPL version 2 licenses. + */ +#define _LARGEFILE64_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <libgen.h> + +#include <f2fs_fs.h> + +#ifdef HAVE_LINUX_BLKZONED_H + +void f2fs_get_zoned_model() +{ + char str[128]; + FILE *file; + + /* Check that this is a zoned block device */ + snprintf(str, sizeof(str), + "/sys/block/%s/queue/zoned", + basename(c.device_name)); + file = fopen(str, "r"); + if (!file) + goto not_zoned; + + memset(str, 0, sizeof(str)); + fscanf(file, "%s", str); + fclose(file); + + if (strcmp(str, "host-aware") == 0) { + c.zoned_model = F2FS_ZONED_HA; + return; + } + if (strcmp(str, "host-managed") == 0) { + c.zoned_model = F2FS_ZONED_HM; + return; + } + +not_zoned: + c.zoned_model = F2FS_ZONED_NONE; +} + +int f2fs_get_zone_blocks() +{ + uint64_t sectors; + char str[128]; + FILE *file; + + /* Get zone size */ + c.zone_blocks = 0; + + snprintf(str, sizeof(str), + "/sys/block/%s/queue/chunk_sectors", + basename(c.device_name)); + file = fopen(str, "r"); + if (!file) + return -1; + + memset(str, 0, sizeof(str)); + fscanf(file, "%s", str); + fclose(file); + + sectors = atol(str); + if (!sectors) + return -1; + + c.zone_blocks = sectors >> (F2FS_BLKSIZE_BITS - 9); + sectors = (sectors << 9) / c.sector_size; + + /* + * Total number of zones: there may + * be a last smaller runt zone. + */ + c.nr_zones = c.total_sectors / sectors; + if (c.total_sectors % sectors) + c.nr_zones++; + + return 0; +} + +#define F2FS_REPORT_ZONES_BUFSZ 524288 + +int f2fs_check_zones() +{ + struct blk_zone_report *rep; + struct blk_zone *blkz; + unsigned int i, n = 0; + u_int64_t total_sectors; + u_int64_t sector; + int last_is_conv = 1; + int ret = -1; + + rep = malloc(F2FS_REPORT_ZONES_BUFSZ); + if (!rep) { + ERR_MSG("No memory for report zones\n"); + return -ENOMEM; + } + + c.nr_rnd_zones = 0; + sector = 0; + total_sectors = (c.total_sectors * c.sector_size) >> 9; + + while (sector < total_sectors) { + + /* Get zone info */ + memset(rep, 0, F2FS_REPORT_ZONES_BUFSZ); + rep->sector = sector; + rep->nr_zones = (F2FS_REPORT_ZONES_BUFSZ - sizeof(struct blk_zone_report)) + / sizeof(struct blk_zone); + + ret = ioctl(c.fd, BLKREPORTZONE, rep); + if (ret != 0) { + ret = -errno; + ERR_MSG("ioctl BLKREPORTZONE failed\n"); + goto out; + } + + if (!rep->nr_zones) + break; + + blkz = (struct blk_zone *)(rep + 1); + for (i = 0; i < rep->nr_zones && sector < total_sectors; i++) { + + if (blk_zone_cond(blkz) == BLK_ZONE_COND_READONLY || + blk_zone_cond(blkz) == BLK_ZONE_COND_OFFLINE) + last_is_conv = 0; + if (blk_zone_conv(blkz) || + blk_zone_seq_pref(blkz)) { + if (last_is_conv) + c.nr_rnd_zones++; + } else { + last_is_conv = 0; + } + + if (blk_zone_conv(blkz)) { + DBG(2, + "Zone %05u: Conventional, cond 0x%x (%s), sector %llu, %llu sectors\n", + n, + blk_zone_cond(blkz), + blk_zone_cond_str(blkz), + blk_zone_sector(blkz), + blk_zone_length(blkz)); + } else { + DBG(2, + "Zone %05u: type 0x%x (%s), cond 0x%x (%s), need_reset %d, " + "non_seq %d, sector %llu, %llu sectors, wp sector %llu\n", + n, + blk_zone_type(blkz), + blk_zone_type_str(blkz), + blk_zone_cond(blkz), + blk_zone_cond_str(blkz), + blk_zone_need_reset(blkz), + blk_zone_non_seq(blkz), + blk_zone_sector(blkz), + blk_zone_length(blkz), + blk_zone_wp_sector(blkz)); + } + + sector = blk_zone_sector(blkz) + blk_zone_length(blkz); + n++; + blkz++; + } + + } + + if (sector != total_sectors) { + ERR_MSG("Invalid zones: last sector reported is %llu, expected %llu\n", + (unsigned long long)(sector << 9) / c.sector_size, + (unsigned long long)c.total_sectors); + ret = -1; + goto out; + } + + if (n != c.nr_zones) { + ERR_MSG("Inconsistent number of zones: expected %u zones, got %u\n", + c.nr_zones, n); + ret = -1; + goto out; + } + + if (c.zoned_model == F2FS_ZONED_HM && + !c.nr_rnd_zones) { + ERR_MSG("No conventional zone for super block\n"); + ret = -1; + } +out: + free(rep); + return ret; +} + +int f2fs_reset_zones() +{ + struct blk_zone_report *rep; + struct blk_zone *blkz; + struct blk_zone_range range; + u_int64_t total_sectors; + u_int64_t sector; + unsigned int i; + int ret = -1; + + rep = malloc(F2FS_REPORT_ZONES_BUFSZ); + if (!rep) { + ERR_MSG("No memory for report zones\n"); + return -1; + } + + sector = 0; + total_sectors = (c.total_sectors * c.sector_size) >> 9; + while (sector < total_sectors) { + + /* Get zone info */ + memset(rep, 0, F2FS_REPORT_ZONES_BUFSZ); + rep->sector = sector; + rep->nr_zones = (F2FS_REPORT_ZONES_BUFSZ - sizeof(struct blk_zone_report)) + / sizeof(struct blk_zone); + + ret = ioctl(c.fd, BLKREPORTZONE, rep); + if (ret != 0) { + ret = -errno; + ERR_MSG("ioctl BLKREPORTZONES failed\n"); + goto out; + } + + if (!rep->nr_zones) + break; + + blkz = (struct blk_zone *)(rep + 1); + for (i = 0; i < rep->nr_zones && sector < total_sectors; i++) { + if (blk_zone_seq(blkz) && + !blk_zone_empty(blkz)) { + /* Non empty sequential zone: reset */ + range.sector = blk_zone_sector(blkz); + range.nr_sectors = blk_zone_length(blkz); + ret = ioctl(c.fd, BLKRESETZONE, &range); + if (ret != 0) { + ERR_MSG("ioctl BLKRESETZONE failed\n"); + goto out; + } + } + sector = blk_zone_sector(blkz) + blk_zone_length(blkz); + blkz++; + } + + } + +out: + free(rep); + return 0; +} + +#else + +void f2fs_get_zoned_model() +{ + c.zoned_mode = 0; + c.zoned_model = F2FS_ZONED_NONE; +} + +int f2fs_get_zone_blocks() +{ + c.zoned_mode = 0; + c.nr_zones = 0; + c.zone_blocks = 0; + c.zoned_model = F2FS_ZONED_NONE; + + return 0; +} + +int f2fs_check_zones() +{ + ERR_MSG("Zoned block devices are not supported\n"); + return -1; +} + +int f2fs_reset_zones() +{ + ERR_MSG("Zoned block devices are not supported\n"); + return -1; +} + +#endif + diff --git a/lib/zbc.c b/lib/zbc.c deleted file mode 100644 index 1783bd5..0000000 --- a/lib/zbc.c +++ /dev/null @@ -1,647 +0,0 @@ -/* - * This file is mostly copied from libzbc. - * - * Copyright (C) 2009-2014, HGST, Inc. All rights reserved. - * - * This software is distributed under the terms of the BSD 2-clause license, - * "as is," without technical support, and WITHOUT ANY WARRANTY, without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. You should have received a copy of the BSD 2-clause license along - * with libzbc. If not, see <http://opensource.org/licenses/BSD-2-Clause>. - * - * Authors: Damien Le Moal (damien.lemoal@hgst.com) - * Christophe Louargant (christophe.louargant@hgst.com) - * - * Integrated into f2fs-tools by: - * Jaegeuk Kim (jaegeuk@kernel.org) - */ - -#include <f2fs_fs.h> - -#include "zbc.h" - -static struct zbc_sg_cmd_s -{ - - char *cdb_cmd_name; - int cdb_opcode; - int cdb_sa; - size_t cdb_length; - int dir; - -} zbc_sg_cmd_list[ZBC_SG_CMD_NUM] = { - - /* ZBC_SG_TEST_UNIT_READY */ - { - "TEST UNIT READY", - ZBC_SG_TEST_UNIT_READY_CDB_OPCODE, - 0, - ZBC_SG_TEST_UNIT_READY_CDB_LENGTH, - SG_DXFER_NONE - }, - - /* ZBC_SG_INQUIRY */ - { - "INQUIRY", - ZBC_SG_INQUIRY_CDB_OPCODE, - 0, - ZBC_SG_INQUIRY_CDB_LENGTH, - SG_DXFER_FROM_DEV - }, - - /* ZBC_SG_READ_CAPACITY */ - { - "READ CAPACITY 16", - ZBC_SG_READ_CAPACITY_CDB_OPCODE, - ZBC_SG_READ_CAPACITY_CDB_SA, - ZBC_SG_READ_CAPACITY_CDB_LENGTH, - SG_DXFER_FROM_DEV - }, - - /* ZBC_SG_READ */ - { - "READ 16", - ZBC_SG_READ_CDB_OPCODE, - 0, - ZBC_SG_READ_CDB_LENGTH, - SG_DXFER_FROM_DEV - }, - - /* ZBC_SG_WRITE */ - { - "WRITE 16", - ZBC_SG_WRITE_CDB_OPCODE, - 0, - ZBC_SG_WRITE_CDB_LENGTH, - SG_DXFER_TO_DEV - }, - - /* ZBC_SG_SYNC_CACHE */ - { - "SYNCHRONIZE CACHE 16", - ZBC_SG_SYNC_CACHE_CDB_OPCODE, - 0, - ZBC_SG_SYNC_CACHE_CDB_LENGTH, - SG_DXFER_NONE - }, - - /* ZBC_SG_REPORT_ZONES */ - { - "REPORT ZONES", - ZBC_SG_REPORT_ZONES_CDB_OPCODE, - ZBC_SG_REPORT_ZONES_CDB_SA, - ZBC_SG_REPORT_ZONES_CDB_LENGTH, - SG_DXFER_FROM_DEV - }, - - /* ZBC_SG_OPEN_ZONE */ - { - "OPEN ZONE", - ZBC_SG_OPEN_ZONE_CDB_OPCODE, - ZBC_SG_OPEN_ZONE_CDB_SA, - ZBC_SG_OPEN_ZONE_CDB_LENGTH, - SG_DXFER_NONE - }, - - /* ZBC_SG_CLOSE_ZONE */ - { - "CLOSE ZONE", - ZBC_SG_CLOSE_ZONE_CDB_OPCODE, - ZBC_SG_CLOSE_ZONE_CDB_SA, - ZBC_SG_CLOSE_ZONE_CDB_LENGTH, - SG_DXFER_NONE - }, - - /* ZBC_SG_FINISH_ZONE */ - { - "FINISH ZONE", - ZBC_SG_FINISH_ZONE_CDB_OPCODE, - ZBC_SG_FINISH_ZONE_CDB_SA, - ZBC_SG_FINISH_ZONE_CDB_LENGTH, - SG_DXFER_NONE - }, - - /* ZBC_SG_RESET_WRITE_POINTER */ - { - "RESET WRITE POINTER", - ZBC_SG_RESET_WRITE_POINTER_CDB_OPCODE, - ZBC_SG_RESET_WRITE_POINTER_CDB_SA, - ZBC_SG_RESET_WRITE_POINTER_CDB_LENGTH, - SG_DXFER_NONE - }, - - /* ZBC_SG_SET_ZONES */ - { - "SET ZONES", - ZBC_SG_SET_ZONES_CDB_OPCODE, - ZBC_SG_SET_ZONES_CDB_SA, - ZBC_SG_SET_ZONES_CDB_LENGTH, - SG_DXFER_NONE - }, - - /* ZBC_SG_SET_WRITE_POINTER */ - { - "SET WRITE POINTER", - ZBC_SG_SET_WRITE_POINTER_CDB_OPCODE, - ZBC_SG_SET_WRITE_POINTER_CDB_SA, - ZBC_SG_SET_WRITE_POINTER_CDB_LENGTH, - SG_DXFER_NONE - }, - - /* ZBC_SG_ATA12 */ - { - "ATA 12", - ZBC_SG_ATA12_CDB_OPCODE, - 0, - ZBC_SG_ATA12_CDB_LENGTH, - 0 - }, - - /* ZBC_SG_ATA16 */ - { - "ATA 16", - ZBC_SG_ATA16_CDB_OPCODE, - 0, - ZBC_SG_ATA16_CDB_LENGTH, - 0 - } -}; - -static void zbc_sg_cmd_set_bytes(uint8_t *cmd, void *buf, int bytes) -{ - uint8_t *v = (uint8_t *) buf; - int i; - - for (i = 0; i < bytes; i++) { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - /* The least significant byte is stored last */ - cmd[bytes - i - 1] = v[i]; -#else - /* The most significant byte is stored first */ - cmd[i] = v[i]; -#endif - } - return; -} - -static void zbc_sg_cmd_get_bytes(uint8_t *val, union converter *conv, int bytes) -{ - uint8_t *v = (uint8_t *) val; - int i; - - memset(conv, 0, sizeof(union converter)); - - for(i = 0; i < bytes; i++) { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - conv->val_buf[bytes - i - 1] = v[i]; -#else - conv->val_buf[i] = v[i]; -#endif - } - return; -} - -static inline void zbc_sg_cmd_set_int64(uint8_t *buf, uint64_t val) -{ - zbc_sg_cmd_set_bytes(buf, &val, 8); - return; -} - -static inline void zbc_sg_cmd_set_int32(uint8_t *buf, uint32_t val) -{ - zbc_sg_cmd_set_bytes(buf, &val, 4); - return; -} - -static inline uint32_t zbc_sg_cmd_get_int32(uint8_t *buf) -{ - union converter conv; - - zbc_sg_cmd_get_bytes(buf, &conv, 4); - return conv.val32; -} - -static inline uint64_t zbc_sg_cmd_get_int64(uint8_t *buf) -{ - union converter conv; - - zbc_sg_cmd_get_bytes(buf, &conv, 8); - return( conv.val64 ); - -} - -static void zbc_sg_cmd_destroy(zbc_sg_cmd_t *cmd) -{ - /* Free the command */ - if (!cmd) - return; - - if (cmd->out_buf && cmd->out_buf_needfree) { - free(cmd->out_buf); - cmd->out_buf = NULL; - cmd->out_bufsz = 0; - } - memset(cmd, 0, sizeof(*cmd)); - return; -} - -static int zbc_sg_cmd_init(zbc_sg_cmd_t *cmd, int cmd_code, - uint8_t *out_buf, size_t out_bufsz) -{ - int ret = 0; - - if ((!cmd) || (cmd_code < 0) || (cmd_code >= ZBC_SG_CMD_NUM) ) { - ERR_MSG("Invalid command specified\n"); - return -EINVAL; - } - - /* Set command */ - memset(cmd, 0, sizeof(zbc_sg_cmd_t)); - cmd->code = cmd_code; - cmd->cdb_sz = zbc_sg_cmd_list[cmd_code].cdb_length; - cmd->cdb_opcode = zbc_sg_cmd_list[cmd_code].cdb_opcode; - cmd->cdb_sa = zbc_sg_cmd_list[cmd_code].cdb_sa; - - /* Set output buffer */ - if (out_buf) { - /* Set specified buffer */ - if (!out_bufsz) { - ERR_MSG("Invalid 0 output buffer size\n"); - ret = -EINVAL; - goto out; - } - cmd->out_buf = out_buf; - cmd->out_bufsz = out_bufsz; - } else if (out_bufsz) { - /* Allocate a buffer */ - ret = posix_memalign((void **)&cmd->out_buf, - sysconf(_SC_PAGESIZE), out_bufsz); - if ( ret != 0 ) { - ERR_MSG("No memory for output buffer (%zu B)\n", - out_bufsz); - ret = -ENOMEM; - goto out; - } - memset(cmd->out_buf, 0, out_bufsz); - cmd->out_bufsz = out_bufsz; - cmd->out_buf_needfree = 1; - } - - /* OK: setup SGIO header */ - memset(&cmd->io_hdr, 0, sizeof(sg_io_hdr_t)); - - cmd->io_hdr.interface_id = 'S'; - cmd->io_hdr.timeout = 20000; - cmd->io_hdr.flags = 0; //SG_FLAG_DIRECT_IO; - - cmd->io_hdr.cmd_len = cmd->cdb_sz; - cmd->io_hdr.cmdp = &cmd->cdb[0]; - - cmd->io_hdr.dxfer_direction = zbc_sg_cmd_list[cmd_code].dir; - cmd->io_hdr.dxfer_len = cmd->out_bufsz; - cmd->io_hdr.dxferp = cmd->out_buf; - - cmd->io_hdr.mx_sb_len = ZBC_SG_SENSE_MAX_LENGTH; - cmd->io_hdr.sbp = cmd->sense_buf; -out: - if (ret != 0) - zbc_sg_cmd_destroy(cmd); - - return ret; -} - -static char *zbc_sg_cmd_name(zbc_sg_cmd_t *cmd) -{ - char *name; - - if ((cmd->code >= 0) - && (cmd->code < ZBC_SG_CMD_NUM)) { - name = zbc_sg_cmd_list[cmd->code].cdb_cmd_name; - } else { - name = "(UNKNOWN COMMAND)"; - } - - return name; -} - -static void zbc_sg_set_sense(uint8_t *sense_buf) -{ - if (sense_buf == NULL) { - c.zbd_errno.sk = 0x00; - c.zbd_errno.asc_ascq = 0x0000; - } else { - if ((sense_buf[0] & 0x7F) == 0x72 - || (sense_buf[0] & 0x7F) == 0x73) { - /* store sense key, ASC/ASCQ */ - c.zbd_errno.sk = sense_buf[1] & 0x0F; - c.zbd_errno.asc_ascq = ((int)sense_buf[2] << 8) | - (int)sense_buf[3]; - } else if ((sense_buf[0] & 0x7F) == 0x70 - || (sense_buf[0] & 0x7F) == 0x71) { - /* store sense key, ASC/ASCQ */ - c.zbd_errno.sk = sense_buf[2] & 0x0F; - c.zbd_errno.asc_ascq = ((int)sense_buf[12] << 8) | - (int)sense_buf[13]; - } - } - return; -} - -static int zbc_sg_cmd_exec(zbc_sg_cmd_t *cmd) -{ - int ret; - - /* Send the SG_IO command */ - ret = ioctl(c.fd, SG_IO, &cmd->io_hdr); - if (ret) { - ERR_MSG("SG_IO ioctl failed (%s)\n", strerror(errno)); - goto out; - } - - /* Reset errno */ - zbc_sg_set_sense(NULL); - - DBG(1, "Command %s done: status 0x%02x (0x%02x), host status 0x%04x, driver status 0x%04x (flags 0x%04x)\n", - zbc_sg_cmd_name(cmd), - (unsigned int)cmd->io_hdr.status, - (unsigned int)cmd->io_hdr.masked_status, - (unsigned int)cmd->io_hdr.host_status, - (unsigned int)zbc_sg_cmd_driver_status(cmd), - (unsigned int)zbc_sg_cmd_driver_flags(cmd)); - - /* Check status */ - if (((cmd->code == ZBC_SG_ATA12) || (cmd->code == ZBC_SG_ATA16)) - && (cmd->cdb[2] & (1 << 5)) ) { - - /* ATA command status */ - if (cmd->io_hdr.status != ZBC_SG_CHECK_CONDITION) { - zbc_sg_set_sense(cmd->sense_buf); - ret = -EIO; - goto out; - } - - if ((zbc_sg_cmd_driver_status(cmd) == ZBC_SG_DRIVER_SENSE) - && (cmd->io_hdr.sb_len_wr > 21) - && (cmd->sense_buf[21] != 0x50) ) { - zbc_sg_set_sense(cmd->sense_buf); - ret = -EIO; - goto out; - } - cmd->io_hdr.status = 0; - } - - if (cmd->io_hdr.status - || (cmd->io_hdr.host_status != ZBC_SG_DID_OK) - || (zbc_sg_cmd_driver_status(cmd) && - (zbc_sg_cmd_driver_status(cmd) != ZBC_SG_DRIVER_SENSE)) ) { - - ERR_MSG("Command %s failed with status 0x%02x (0x%02x), host status 0x%04x, driver status 0x%04x (flags 0x%04x)\n", - zbc_sg_cmd_name(cmd), - (unsigned int)cmd->io_hdr.status, - (unsigned int)cmd->io_hdr.masked_status, - (unsigned int)cmd->io_hdr.host_status, - (unsigned int)zbc_sg_cmd_driver_status(cmd), - (unsigned int)zbc_sg_cmd_driver_flags(cmd)); - zbc_sg_set_sense(cmd->sense_buf); - ret = -EIO; - goto out; - } - - if (cmd->io_hdr.resid) { - ERR_MSG("Transfer missing %d B of data\n", - cmd->io_hdr.resid); - cmd->out_bufsz -= cmd->io_hdr.resid; - } -out: - return ret; -} - -#define ZBC_SCSI_REPORT_ZONES_BUFSZ 524288 - -int zbc_scsi_report_zones(void) -{ - zbc_sg_cmd_t cmd; - uint8_t *buf; - zbc_zone_t *z, *zones = NULL; - int i, buf_nz, ret; - size_t bufsz; - uint32_t idx = 0, nr_zones = 0; - uint64_t next_lba = 0; - int phase = 0; -next: - bufsz = ZBC_ZONE_DESCRIPTOR_OFFSET; - if (phase) { - if (c.nr_zones - idx == 0) - return 0; - - bufsz += (size_t)(c.nr_zones - idx) * - ZBC_ZONE_DESCRIPTOR_LENGTH; - if (bufsz > ZBC_SCSI_REPORT_ZONES_BUFSZ) - bufsz = ZBC_SCSI_REPORT_ZONES_BUFSZ; - } - - /* For in kernel ATA translation: align to 512 B */ - bufsz = (bufsz + 511) & ~511; - - /* Allocate and intialize report zones command */ - ret = zbc_sg_cmd_init(&cmd, ZBC_SG_REPORT_ZONES, NULL, bufsz); - if (ret) { - ERR_MSG("zbc_sg_cmd_init failed\n"); - return ret; - } - - /* Fill command CDB: - * +=============================================================================+ - * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | - * |Byte | | | | | | | | | - * |=====+==========================+============================================| - * | 0 | Operation Code (95h) | - * |-----+-----------------------------------------------------------------------| - * | 1 | Reserved | Service Action (00h) | - * |-----+-----------------------------------------------------------------------| - * | 2 | (MSB) | - * |- - -+--- Zone Start LBA ---| - * | 9 | (LSB) | - * |-----+-----------------------------------------------------------------------| - * | 10 | (MSB) | - * |- - -+--- Allocation Length ---| - * | 13 | (LSB) | - * |-----+-----------------------------------------------------------------------| - * | 14 |Partial |Reserved| Reporting Options | - * |-----+-----------------------------------------------------------------------| - * | 15 | Control | - * +=============================================================================+ - */ - cmd.cdb[0] = ZBC_SG_REPORT_ZONES_CDB_OPCODE; - cmd.cdb[1] = ZBC_SG_REPORT_ZONES_CDB_SA; - zbc_sg_cmd_set_int64(&cmd.cdb[2], next_lba); - zbc_sg_cmd_set_int32(&cmd.cdb[10], (unsigned int) bufsz); - cmd.cdb[14] = 0; - - /* Send the SG_IO command */ - ret = zbc_sg_cmd_exec(&cmd); - if (ret != 0) - goto out; - - if (cmd.out_bufsz < ZBC_ZONE_DESCRIPTOR_OFFSET) { - ERR_MSG("Not enough data received (need at least %d B, got %zu B)\n", - ZBC_ZONE_DESCRIPTOR_OFFSET, - cmd.out_bufsz); - ret = -EIO; - goto out; - } - - /* Process output: - * +=============================================================================+ - * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | - * |Byte | | | | | | | | | - * |=====+=======================================================================| - * | 0 | (MSB) | - * |- - -+--- Zone List Length (n - 64) ---| - * | 3 | (LSB) | - * |-----+-----------------------------------------------------------------------| - * | 4 | Reserved | Same | - * |-----+-----------------------------------------------------------------------| - * | 5 | | - * |- - -+--- Reserved ---| - * | 7 | | - * |-----+-----------------------------------------------------------------------| - * | 8 | (MSB) | - * |- - -+--- Maximum LBA ---| - * | 15 | (LSB) | - * |-----+-----------------------------------------------------------------------| - * | 16 | (MSB) | - * |- - -+--- Reserved ---| - * | 63 | (LSB) | - * |=====+=======================================================================| - * | | Vendor-Specific Parameters | - * |=====+=======================================================================| - * | 64 | (MSB) | - * |- - -+--- Zone Descriptor [first] ---| - * | 127 | (LSB) | - * |-----+-----------------------------------------------------------------------| - * | . | - * | . | - * | . | - * |-----+-----------------------------------------------------------------------| - * |n-63 | | - * |- - -+--- Zone Descriptor [last] ---| - * | n | | - * +=============================================================================+ - */ - - /* Get number of zones in result */ - buf = (uint8_t *)cmd.out_buf; - nr_zones = zbc_sg_cmd_get_int32(buf) / ZBC_ZONE_DESCRIPTOR_LENGTH; - - /* read # of zones and then get all the zone info */ - if (phase == 0) { - c.nr_zones = nr_zones; - c.nr_conventional = 0; - zbc_sg_cmd_destroy(&cmd); - phase++; - goto next; - } - - if (nr_zones > c.nr_zones - idx) - nr_zones = c.nr_zones - idx; - - buf_nz = (cmd.out_bufsz - ZBC_ZONE_DESCRIPTOR_OFFSET) / - ZBC_ZONE_DESCRIPTOR_LENGTH; - if (nr_zones > buf_nz) - nr_zones = buf_nz; - - if (!nr_zones) { - ERR_MSG("No more zones\n"); - goto out; - } - - /* Allocate zone array */ - zones = (zbc_zone_t *)malloc(sizeof(zbc_zone_t) * nr_zones); - if (!zones) { - ERR_MSG("No memory\n"); - goto out; - } - memset(zones, 0, sizeof(zbc_zone_t) * nr_zones); - - /* Get zone descriptors: - * +=============================================================================+ - * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | - * |Byte | | | | | | | | | - * |=====+=======================================================================| - * | 0 | Reserved | Zone type | - * |-----+-----------------------------------------------------------------------| - * | 1 | Zone condition | Reserved |non-seq | Reset | - * |-----+-----------------------------------------------------------------------| - * | 2 | | - * |- - -+--- Reserved ---| - * | 7 | | - * |-----+-----------------------------------------------------------------------| - * | 8 | (MSB) | - * |- - -+--- Zone Length ---| - * | 15 | (LSB) | - * |-----+-----------------------------------------------------------------------| - * | 16 | (MSB) | - * |- - -+--- Zone Start LBA ---| - * | 23 | (LSB) | - * |-----+-----------------------------------------------------------------------| - * | 24 | (MSB) | - * |- - -+--- Write Pointer LBA ---| - * | 31 | (LSB) | - * |-----+-----------------------------------------------------------------------| - * | 32 | | - * |- - -+--- Reserved ---| - * | 63 | | - * +=============================================================================+ - */ - buf += ZBC_ZONE_DESCRIPTOR_OFFSET; - - for(i = 0; i < nr_zones; i++) { - zones[i].zbz_type = buf[0] & 0x0f; - zones[i].zbz_condition = (buf[1] >> 4) & 0x0f; - zones[i].zbz_length = zbc_sg_cmd_get_int64(&buf[8]); - zones[i].zbz_start = zbc_sg_cmd_get_int64(&buf[16]); - zones[i].zbz_write_pointer = zbc_sg_cmd_get_int64(&buf[24]); - zones[i].zbz_flags = buf[1] & 0x03; - - buf += ZBC_ZONE_DESCRIPTOR_LENGTH; - } - - for (i = 0; i < nr_zones; i++) { - z = &zones[i]; - if ( zbc_zone_conventional(z) ) { - c.nr_conventional++; - DBG(1, "Zone %05d: type 0x%x (%s), cond 0x%x (%s), LBA %llu, %llu sectors, wp N/A\n", - i + idx, - zbc_zone_type(z), - zbc_zone_type_str(zbc_zone_type(z)), - zbc_zone_condition(z), - zbc_zone_condition_str(zbc_zone_condition(z)), - zbc_zone_start_lba(z), - zbc_zone_length(z)); - } else { - DBG(1, "Zone %05d: type 0x%x (%s), cond 0x%x (%s), need_reset %d, non_seq %d, LBA %llu, %llu sectors, wp %llu\n", - i + idx, - zbc_zone_type(z), - zbc_zone_type_str(zbc_zone_type(z)), - zbc_zone_condition(z), - zbc_zone_condition_str(zbc_zone_condition(z)), - zbc_zone_need_reset(z), - zbc_zone_non_seq(z), - zbc_zone_start_lba(z), - zbc_zone_length(z), - zbc_zone_wp_lba(z)); - } - } - - idx += nr_zones; - next_lba = zones[nr_zones - 1].zbz_start + zones[nr_zones - 1].zbz_length; - c.zone_sectors = zones[nr_zones - 1].zbz_length; - phase++; - zbc_sg_cmd_destroy(&cmd); - free(zones); - goto next; -out: - zbc_sg_cmd_destroy(&cmd); - return ret; -} diff --git a/lib/zbc.h b/lib/zbc.h deleted file mode 100644 index 15692c1..0000000 --- a/lib/zbc.h +++ /dev/null @@ -1,361 +0,0 @@ -/* - * This file is copied from libzbc. - * - * Copyright (C) 2009-2014, HGST, Inc. All rights reserved. - * - * This software is distributed under the terms of the BSD 2-clause license, - * "as is," without technical support, and WITHOUT ANY WARRANTY, without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. You should have received a copy of the BSD 2-clause license along - * with libzbc. If not, see <http://opensource.org/licenses/BSD-2-Clause>. - * - * Author: Damien Le Moal (damien.lemoal@hgst.com) - * Christophe Louargant (christophe.louargant@hgst.com) - */ - -#ifndef __LIBZBC_SG_H__ -#define __LIBZBC_SG_H__ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <linux/types.h> -#include <sys/types.h> -#include <sys/ioctl.h> -#include <scsi/scsi.h> -#include <scsi/sg.h> - -#define zbc_error(format, args...) \ - fprintf(stderr, "[ERROR] " format, ##args) - -/** - * SG SCSI command names. - */ -enum { - - ZBC_SG_TEST_UNIT_READY = 0, - ZBC_SG_INQUIRY, - ZBC_SG_READ_CAPACITY, - ZBC_SG_READ, - ZBC_SG_WRITE, - ZBC_SG_SYNC_CACHE, - ZBC_SG_REPORT_ZONES, - ZBC_SG_OPEN_ZONE, - ZBC_SG_CLOSE_ZONE, - ZBC_SG_FINISH_ZONE, - ZBC_SG_RESET_WRITE_POINTER, - ZBC_SG_SET_ZONES, - ZBC_SG_SET_WRITE_POINTER, - ZBC_SG_ATA12, - ZBC_SG_ATA16, - - ZBC_SG_CMD_NUM, -}; - -/** - * Test unit ready command definition. - */ -#define ZBC_SG_TEST_UNIT_READY_CDB_OPCODE 0x00 -#define ZBC_SG_TEST_UNIT_READY_CDB_LENGTH 6 -#define ZBC_ZONE_DESCRIPTOR_LENGTH 64 - -/** - * Number of bytes in the buffer before the first Zone Descriptor. - */ -#define ZBC_ZONE_DESCRIPTOR_OFFSET 64 - -/** - * Inquiry command definition. - */ -#define ZBC_SG_INQUIRY_CDB_OPCODE 0x12 -#define ZBC_SG_INQUIRY_CDB_LENGTH 6 -#define ZBC_SG_INQUIRY_REPLY_LEN 96 -#define ZBC_SG_INQUIRY_REPLY_LEN_VPD_PAGE_B1 64 -#define ZBC_SG_INQUIRY_REPLY_LEN_VPD_PAGE_B6 64 - -/** - * Read capacity command definition. - */ -#define ZBC_SG_READ_CAPACITY_CDB_OPCODE 0x9E -#define ZBC_SG_READ_CAPACITY_CDB_SA 0x10 -#define ZBC_SG_READ_CAPACITY_CDB_LENGTH 16 -#define ZBC_SG_READ_CAPACITY_REPLY_LEN 32 - -/** - * Read command definition. - */ -#define ZBC_SG_READ_CDB_OPCODE 0x88 -#define ZBC_SG_READ_CDB_LENGTH 16 - -/** - * Write command definition. - */ -#define ZBC_SG_WRITE_CDB_OPCODE 0x8A -#define ZBC_SG_WRITE_CDB_LENGTH 16 - -/** - * Sync cache command definition. - */ -#define ZBC_SG_SYNC_CACHE_CDB_OPCODE 0x91 -#define ZBC_SG_SYNC_CACHE_CDB_LENGTH 16 - -/** - * Report zones command definition. - */ -#define ZBC_SG_REPORT_ZONES_CDB_OPCODE 0x95 -#define ZBC_SG_REPORT_ZONES_CDB_SA 0x00 -#define ZBC_SG_REPORT_ZONES_CDB_LENGTH 16 - -/** - * Open zone command definition. - */ -#define ZBC_SG_OPEN_ZONE_CDB_OPCODE 0x94 -#define ZBC_SG_OPEN_ZONE_CDB_SA 0x03 -#define ZBC_SG_OPEN_ZONE_CDB_LENGTH 16 - -/** - * Close zone command definition. - */ -#define ZBC_SG_CLOSE_ZONE_CDB_OPCODE 0x94 -#define ZBC_SG_CLOSE_ZONE_CDB_SA 0x01 -#define ZBC_SG_CLOSE_ZONE_CDB_LENGTH 16 - -/** - * Finish zone command definition. - */ -#define ZBC_SG_FINISH_ZONE_CDB_OPCODE 0x94 -#define ZBC_SG_FINISH_ZONE_CDB_SA 0x02 -#define ZBC_SG_FINISH_ZONE_CDB_LENGTH 16 - -/** - * Reset write pointer command definition. - */ -#define ZBC_SG_RESET_WRITE_POINTER_CDB_OPCODE 0x94 -#define ZBC_SG_RESET_WRITE_POINTER_CDB_SA 0x04 -#define ZBC_SG_RESET_WRITE_POINTER_CDB_LENGTH 16 - -/** - * Set zones command definition. - */ -#define ZBC_SG_SET_ZONES_CDB_OPCODE 0x9F -#define ZBC_SG_SET_ZONES_CDB_SA 0x15 -#define ZBC_SG_SET_ZONES_CDB_LENGTH 16 - -/** - * Set write pointer command definition. - */ -#define ZBC_SG_SET_WRITE_POINTER_CDB_OPCODE 0x9F -#define ZBC_SG_SET_WRITE_POINTER_CDB_SA 0x16 -#define ZBC_SG_SET_WRITE_POINTER_CDB_LENGTH 16 - -/** - * ATA pass through 12. - */ -#define ZBC_SG_ATA12_CDB_OPCODE 0xA1 -#define ZBC_SG_ATA12_CDB_LENGTH 12 - -/** - * ATA pass through 16. - */ -#define ZBC_SG_ATA16_CDB_OPCODE 0x85 -#define ZBC_SG_ATA16_CDB_LENGTH 16 - -/** - * Command sense buffer maximum length. - */ -#define ZBC_SG_SENSE_MAX_LENGTH 64 - -/** - * Maximum command CDB length. - */ -#define ZBC_SG_CDB_MAX_LENGTH 16 - -/** - * Status codes. - */ -#define ZBC_SG_CHECK_CONDITION 0x02 - -/** - * Host status codes. - */ -#define ZBC_SG_DID_OK 0x00 /* No error */ -#define ZBC_SG_DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ -#define ZBC_SG_DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ -#define ZBC_SG_DID_TIME_OUT 0x03 /* Timed out for other reason */ -#define ZBC_SG_DID_BAD_TARGET 0x04 /* Bad target, device not responding? */ -#define ZBC_SG_DID_ABORT 0x05 /* Told to abort for some other reason. */ -#define ZBC_SG_DID_PARITY 0x06 /* Parity error. */ -#define ZBC_SG_DID_ERROR 0x07 /* Internal error detected in the host adapter. */ -#define ZBC_SG_DID_RESET 0x08 /* The SCSI bus (or this device) has been reset. */ -#define ZBC_SG_DID_BAD_INTR 0x09 /* Got an unexpected interrupt */ -#define ZBC_SG_DID_PASSTHROUGH 0x0a /* Forced command past mid-layer. */ -#define ZBC_SG_DID_SOFT_ERROR 0x0b /* The low level driver wants a retry. */ - -/** - * Driver status codes. - */ -#define ZBC_SG_DRIVER_OK 0x00 -#define ZBC_SG_DRIVER_BUSY 0x01 -#define ZBC_SG_DRIVER_SOFT 0x02 -#define ZBC_SG_DRIVER_MEDIA 0x03 -#define ZBC_SG_DRIVER_ERROR 0x04 -#define ZBC_SG_DRIVER_INVALID 0x05 -#define ZBC_SG_DRIVER_TIMEOUT 0x06 -#define ZBC_SG_DRIVER_HARD 0x07 -#define ZBC_SG_DRIVER_SENSE 0x08 -#define ZBC_SG_DRIVER_STATUS_MASK 0x0f - -/** - * Driver status code flags ('or'ed with code) - */ -#define ZBC_SG_DRIVER_SUGGEST_RETRY 0x10 -#define ZBC_SG_DRIVER_SUGGEST_ABORT 0x20 -#define ZBC_SG_DRIVER_SUGGEST_REMAP 0x30 -#define ZBC_SG_DRIVER_SUGGEST_DIE 0x40 -#define ZBC_SG_DRIVER_SUGGEST_SENSE 0x80 -#define ZBC_SG_DRIVER_FLAGS_MASK 0xf0 - -/***** Type definitions *****/ - -/** - * SG command descriptor. Used to process SCSI commands. - */ -typedef struct zbc_sg_cmd { - - int code; - - int cdb_opcode; - int cdb_sa; - size_t cdb_sz; - uint8_t cdb[ZBC_SG_CDB_MAX_LENGTH]; - - size_t sense_bufsz; - uint8_t sense_buf[ZBC_SG_SENSE_MAX_LENGTH]; - - int out_buf_needfree; - size_t out_bufsz; - uint8_t *out_buf; - - sg_io_hdr_t io_hdr; - -} zbc_sg_cmd_t; - -/** - * Zone descriptor. - */ -struct zbc_zone { - - uint64_t zbz_length; - uint64_t zbz_start; - uint64_t zbz_write_pointer; - - uint8_t zbz_type; - uint8_t zbz_condition; - uint8_t zbz_flags; - - uint8_t __pad[5]; - -}; -typedef struct zbc_zone zbc_zone_t; - -#define ZBC_FORCE_ATA_RW 0x40000000 -#define zbc_open_flags(f) ((f) & ~ZBC_FORCE_ATA_RW) - -/** - * Zone type. - */ -enum zbc_zone_type { - ZBC_ZT_CONVENTIONAL = 0x01, - ZBC_ZT_SEQUENTIAL_REQ = 0x02, - ZBC_ZT_SEQUENTIAL_PREF = 0x03, -}; -#define zbc_zone_type(z) ((int)(z)->zbz_type) - -#define zbc_zone_conventional(z) ((z)->zbz_type == ZBC_ZT_CONVENTIONAL) -static inline const char *zbc_zone_type_str(enum zbc_zone_type type) -{ - switch( type ) { - case ZBC_ZT_CONVENTIONAL: - return( "Conventional" ); - case ZBC_ZT_SEQUENTIAL_REQ: - return( "Sequential-write-required" ); - case ZBC_ZT_SEQUENTIAL_PREF: - return( "Sequential-write-preferred" ); - } - return( "Unknown-type" ); -} - -/** - * Zone condition. - */ -enum zbc_zone_condition { - ZBC_ZC_NOT_WP = 0x00, - ZBC_ZC_EMPTY = 0x01, - ZBC_ZC_IMP_OPEN = 0x02, - ZBC_ZC_EXP_OPEN = 0x03, - ZBC_ZC_CLOSED = 0x04, - ZBC_ZC_RDONLY = 0x0d, - ZBC_ZC_FULL = 0x0e, - ZBC_ZC_OFFLINE = 0x0f, -}; - -/** - * zbc_zone_cond_str - returns a string describing a zone condition. - * @zone: (IN) ZBC_ZC_NOT_WP, ZBC_ZC_EMPTY, ZBC_ZC_IMP_OPEN, ZBC_ZC_EXP_OPEN, - * ZBC_ZC_CLOSED, ZBC_ZC_RDONLY, ZBC_ZC_FULL or ZBC_ZC_OFFLINE - * - * Returns a string describing a zone condition. - */ -static inline const char *zbc_zone_condition_str(enum zbc_zone_condition cond) -{ - switch( cond ) { - case ZBC_ZC_NOT_WP: - return "Not-write-pointer"; - case ZBC_ZC_EMPTY: - return "Empty"; - case ZBC_ZC_IMP_OPEN: - return "Implicit-open"; - case ZBC_ZC_EXP_OPEN: - return "Explicit-open"; - case ZBC_ZC_CLOSED: - return "Closed"; - case ZBC_ZC_RDONLY: - return "Read-only"; - case ZBC_ZC_FULL: - return "Full"; - case ZBC_ZC_OFFLINE: - return "Offline"; - } - return "Unknown-cond"; -} - -#define zbc_zone_condition(z) ((int)(z)->zbz_condition) -#define zbc_zone_start_lba(z) ((unsigned long long)((z)->zbz_start)) -#define zbc_zone_length(z) ((unsigned long long)((z)->zbz_length)) -#define zbc_zone_wp_lba(z) ((unsigned long long)((z)->zbz_write_pointer)) - -/** - * Zone flags: need reset, and non-seq write. - */ -enum zbc_zone_flags { - ZBC_ZF_NEED_RESET = 0x0001, - ZBC_ZF_NON_SEQ = 0x0002, -}; -#define zbc_zone_need_reset(z) (((z)->zbz_flags & ZBC_ZF_NEED_RESET) != 0) -#define zbc_zone_non_seq(z) (((z)->zbz_flags & ZBC_ZF_NON_SEQ) != 0) - -#define zbc_sg_cmd_driver_status(cmd) ((cmd)->io_hdr.driver_status & ZBC_SG_DRIVER_STATUS_MASK) -#define zbc_sg_cmd_driver_flags(cmd) ((cmd)->io_hdr.driver_status & ZBC_SG_DRIVER_FLAGS_MASK) - -union converter { - uint8_t val_buf[8]; - uint16_t val16; - uint32_t val32; - uint64_t val64; -}; - -#endif /* __LIBZBC_SG_H__ */ |