647 lines
20 KiB
C
647 lines
20 KiB
C
/*
|
|
* 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(struct f2fs_configuration *c, 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(struct f2fs_configuration *c, 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(c, 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(c, 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(c, 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(c, 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(struct f2fs_configuration *c)
|
|
{
|
|
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(c, &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;
|
|
}
|