Example #1
0
/**
 * Get zoned block device characteristics
 * (Maximum or optimum number of open zones).
 */
int
zbc_scsi_get_zbd_chars(zbc_device_t *dev)
{
    zbc_sg_cmd_t cmd;
    int ret;

    /* READ CAPACITY 16 */
    ret = zbc_sg_cmd_init(&cmd, ZBC_SG_INQUIRY, NULL, ZBC_SG_INQUIRY_REPLY_LEN_VPD_PAGE_B6);
    if ( ret != 0 ) {
        zbc_error("zbc_sg_cmd_init failed\n");
        return( ret );
    }

    /* Fill command CDB */
    cmd.cdb[0] = ZBC_SG_INQUIRY_CDB_OPCODE;
    cmd.cdb[1] = 0x01;
    cmd.cdb[2] = 0xB6;
    zbc_sg_cmd_set_int16(&cmd.cdb[3], ZBC_SG_INQUIRY_REPLY_LEN_VPD_PAGE_B6);

    /* Send the SG_IO command */
    ret = zbc_sg_cmd_exec(dev, &cmd);
    if ( ret != 0 ) {
        goto out;
    }

    /* URSWRZ (unrestricted read in sequential write required zone) flag */
    dev->zbd_info.zbd_flags |= (cmd.out_buf[4] & 0x01) ? ZBC_UNRESTRICTED_READ : 0;

    /* Resource of handling zones */
    dev->zbd_info.zbd_opt_nr_open_seq_pref = zbc_sg_cmd_get_int32(&cmd.out_buf[8]);
    dev->zbd_info.zbd_opt_nr_non_seq_write_seq_pref = zbc_sg_cmd_get_int32(&cmd.out_buf[12]);
    dev->zbd_info.zbd_max_nr_open_seq_req = zbc_sg_cmd_get_int32(&cmd.out_buf[16]);

    if ( (dev->zbd_info.zbd_model == ZBC_DM_HOST_MANAGED)
	 && (dev->zbd_info.zbd_max_nr_open_seq_req <= 0) ) {
        zbc_error("%s: invalid maximum number of open sequential write required zones for host-managed device\n",
                  dev->zbd_filename);
        ret = -EINVAL;
    }

out:

    zbc_sg_cmd_destroy(&cmd);

    return( ret );

}
Example #2
0
/**
 * Get zoned block device characteristics(Maximum or optimul number of opening zones).
 */
static int
zbc_scsi_get_zbd_chars(zbc_device_t *dev)
{
    zbc_sg_cmd_t cmd;
    int ret;

    /* READ CAPACITY 16 */
    ret = zbc_sg_cmd_init(&cmd, ZBC_SG_INQUIRY, NULL, ZBC_SG_INQUIRY_REPLY_LEN_VPD_PAGE_B6);
    if ( ret != 0 ) {
        zbc_error("zbc_sg_cmd_init failed\n");
        return( ret );
    }

    /* Fill command CDB */
    cmd.cdb[0] = ZBC_SG_INQUIRY_CDB_OPCODE;
    cmd.cdb[1] = 0x01;
    cmd.cdb[2] = 0xB6;
    zbc_sg_cmd_set_int16(&cmd.cdb[3], ZBC_SG_INQUIRY_REPLY_LEN_VPD_PAGE_B6);

    /* Send the SG_IO command */
    ret = zbc_sg_cmd_exec(dev, &cmd);
    if ( ret != 0 ) {
        goto out;
    }

    /* Resource of handling zones */
    dev->zbd_info.zbd_opt_nr_open_seq_pref = zbc_sg_cmd_get_int32(&cmd.out_buf[8]);
    dev->zbd_info.zbd_opt_nr_open_non_seq_write_seq_pref = zbc_sg_cmd_get_int32(&cmd.out_buf[12]);
    dev->zbd_info.zbd_max_nr_open_seq_req = zbc_sg_cmd_get_int32(&cmd.out_buf[16]);

    if ( dev->zbd_info.zbd_max_nr_open_seq_req <= 0 ) {
        zbc_error("%s: invalid maximum number of open sequential write required zones\n",
                  dev->zbd_filename);
        ret = -EINVAL;
    }

out:

    zbc_sg_cmd_destroy(&cmd);

    return( ret );

}
Example #3
0
/**
 * Get a device information (capacity & sector sizes).
 */
static int
zbc_scsi_get_capacity(zbc_device_t *dev)
{
    zbc_sg_cmd_t cmd;
    zbc_zone_t *zones = NULL;
    int logical_per_physical;
    unsigned int nr_zones = 0;
    uint64_t max_lba;
    int ret;

    /* READ CAPACITY 16 */
    ret = zbc_sg_cmd_init(&cmd, ZBC_SG_READ_CAPACITY, NULL, ZBC_SG_READ_CAPACITY_REPLY_LEN);
    if ( ret != 0 ) {
        zbc_error("zbc_sg_cmd_init failed\n");
        return( ret );
    }

    /* Fill command CDB */
    cmd.cdb[0] = ZBC_SG_READ_CAPACITY_CDB_OPCODE;
    cmd.cdb[1] = ZBC_SG_READ_CAPACITY_CDB_SA;
    zbc_sg_cmd_set_int32(&cmd.cdb[10], ZBC_SG_READ_CAPACITY_REPLY_LEN);

    /* Send the SG_IO command */
    ret = zbc_sg_cmd_exec(dev, &cmd);
    if ( ret != 0 ) {
        goto out;
    }

    /* Logical block size */
    dev->zbd_info.zbd_logical_block_size = zbc_sg_cmd_get_int32(&cmd.out_buf[8]);
    if ( dev->zbd_info.zbd_logical_block_size <= 0 ) {
        zbc_error("%s: invalid logical sector size\n",
                  dev->zbd_filename);
        ret = -EINVAL;
        goto out;
    }

    logical_per_physical = 1 << cmd.out_buf[13] & 0x0f;

    /* Check RC_BASIS field */
    switch( (cmd.out_buf[12] & 0x30) >> 4 ) {

    case 0x00:

        /* The logical block address indicates the last LBA of the */
        /* conventional zones at the beginning of the disk. To get */
        /* the entire disk capacity, we need to get last LBA of    */
        /* the last zone of the disk.                              */
        ret = zbc_scsi_report_zones(dev, 0, ZBC_RO_ALL, &max_lba, NULL, &nr_zones);
        if ( ret != 0 ) {
            zbc_error("zbc_report_zones failed\n");
            goto out;
        }

        /* Set the drive capacity to the reported max LBA */
        dev->zbd_info.zbd_logical_blocks = max_lba + 1;

        break;

    case 0x01:

        /* The disk last LBA was reproted */
        dev->zbd_info.zbd_logical_blocks = zbc_sg_cmd_get_int64(&cmd.out_buf[0]) + 1;

        break;

    default:

        zbc_error("%s: invalid RC_BASIS field encountered in READ CAPACITY result\n",
                  dev->zbd_filename);
        ret = -EIO;

        goto out;

    }

    if ( ! dev->zbd_info.zbd_logical_blocks ) {
        zbc_error("%s: invalid capacity (logical blocks)\n",
                  dev->zbd_filename);
        ret = -EINVAL;
        goto out;
    }

    dev->zbd_info.zbd_physical_block_size = dev->zbd_info.zbd_logical_block_size * logical_per_physical;
    dev->zbd_info.zbd_physical_blocks = dev->zbd_info.zbd_logical_blocks / logical_per_physical;

out:

    zbc_sg_cmd_destroy(&cmd);

    if ( zones ) {
        free(zones);
    }

    return( ret );

}
Example #4
0
/**
 * Get a SCSI device zone information.
 */
int
zbc_scsi_report_zones(zbc_device_t *dev,
                      uint64_t start_lba,
                      enum zbc_reporting_options ro,
		      uint64_t *max_lba,
                      zbc_zone_t *zones,
                      unsigned int *nr_zones)
{
    size_t bufsz = ZBC_ZONE_DESCRIPTOR_OFFSET;
    unsigned int i, nz, buf_nz;
    zbc_sg_cmd_t cmd;
    uint8_t *buf;
    int ret;

    if ( *nr_zones ) {
        bufsz += (size_t)*nr_zones * 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 != 0 ) {
        zbc_error("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], start_lba);
    zbc_sg_cmd_set_int32(&cmd.cdb[10], (unsigned int) bufsz);
    cmd.cdb[14] = ro & 0xbf;

    /* Send the SG_IO command */
    ret = zbc_sg_cmd_exec(dev, &cmd);
    if ( ret != 0 ) {
        goto out;
    }

    if ( cmd.out_bufsz < ZBC_ZONE_DESCRIPTOR_OFFSET ) {
        zbc_error("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;
    nz = zbc_sg_cmd_get_int32(buf) / ZBC_ZONE_DESCRIPTOR_LENGTH;
    if ( max_lba ) {
	*max_lba = zbc_sg_cmd_get_int64(&buf[8]);
    }

    if ( zones && nz ) {

        /* Get zone info */
        if ( nz > *nr_zones ) {
            nz = *nr_zones;
        }

	buf_nz = (cmd.out_bufsz - ZBC_ZONE_DESCRIPTOR_OFFSET) / ZBC_ZONE_DESCRIPTOR_LENGTH;
        if ( nz > buf_nz ) {
            nz = buf_nz;
        }

        /* 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 < nz; 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;

        }

    }

    /* Return number of zones */
    *nr_zones = nz;

out:

    /* Cleanup */
    zbc_sg_cmd_destroy(&cmd);

    return( ret );

}
Example #5
0
/**
 * Get a device information (capacity & sector sizes).
 */
static int
zbc_scsi_get_capacity(zbc_device_t *dev)
{
    zbc_sg_cmd_t cmd;
    zbc_zone_t *zones = NULL;
    int logical_per_physical;
    unsigned int nr_zones = 0;
    uint64_t slba = 0;
    int ret;

    /* READ CAPACITY 16 */
    ret = zbc_sg_cmd_init(&cmd, ZBC_SG_READ_CAPACITY, NULL, ZBC_SG_READ_CAPACITY_REPLY_LEN);
    if ( ret != 0 ) {
        zbc_error("zbc_sg_cmd_init failed\n");
        return( ret );
    }

    /* Fill command CDB */
    cmd.cdb[0] = ZBC_SG_READ_CAPACITY_CDB_OPCODE;
    cmd.cdb[1] = ZBC_SG_READ_CAPACITY_CDB_SA;
    zbc_sg_cmd_set_int32(&cmd.cdb[10], ZBC_SG_READ_CAPACITY_REPLY_LEN);

    /* Send the SG_IO command */
    ret = zbc_sg_cmd_exec(dev, &cmd);
    if ( ret != 0 ) {
        goto out;
    }

    /* Logical block size */
    dev->zbd_info.zbd_logical_block_size = zbc_sg_cmd_get_int32(&cmd.out_buf[8]);
    if ( dev->zbd_info.zbd_logical_block_size <= 0 ) {
        zbc_error("%s: invalid logical sector size\n",
                  dev->zbd_filename);
        ret = -EINVAL;
        goto out;
    }

    logical_per_physical = 1 << cmd.out_buf[13] & 0x0f;

    /* Check RC_BASIS field */
    switch( (cmd.out_buf[12] & 0x30) >> 4 ) {

    case 0x00:

        /* The logical block address indicates the last LBA of the */
        /* conventional zones at the beginning of the disk. To get */
        /* the entire disk capacity, we need to get last LBA of    */
        /* the last zone of the disk.                              */
        ret = zbc_scsi_report_zones(dev, 0, 0, NULL, &nr_zones);
        if ( ret != 0 ) {
            zbc_error("zbc_report_zones failed\n");
            goto out;
        }
        if ( ! nr_zones ) {
            ret = -EIO;
            goto out;
        }

        /* Allocate zone array */
        zones = (zbc_zone_t *) malloc(sizeof(zbc_zone_t) * nr_zones);
        if ( ! zones ) {
            zbc_error("No memory\n");
            ret = -ENOMEM;
            goto out;
        }
        memset(zones, 0, sizeof(zbc_zone_t) * nr_zones);

        /* Get all zone information */
        unsigned int n, z = 0, nz = 0;

        while ( nz < nr_zones ) {

            n= nr_zones - nz;
            ret = zbc_scsi_report_zones(dev, slba, 0, &zones[z], &n);
            if ( ret != 0 ) {
                zbc_error("zbc_report_zones failed\n");
                goto out;
            }

            if ( n == 0 ) {
                ret = -EIO;
                break;
            }

            nz += n;
            z  += n;
            slba = zones[z - 1].zbz_start + zones[z - 1].zbz_length;

        }

        /* Get the drive capacity from the last zone last LBA */
        dev->zbd_info.zbd_logical_blocks = zbc_zone_next_lba(&zones[nr_zones - 1]);

        break;

    case 0x01:

        /* The disk last LBA was reproted */
        dev->zbd_info.zbd_logical_blocks = zbc_sg_cmd_get_int64(&cmd.out_buf[0]) + 1;

        break;

    default:

        zbc_error("%s: invalid RC_BASIS field encountered in READ CAPACITY result\n",
                  dev->zbd_filename);
        ret = -EIO;

        goto out;

    }

    if ( ! dev->zbd_info.zbd_logical_blocks ) {
        zbc_error("%s: invalid capacity (logical blocks)\n",
                  dev->zbd_filename);
        ret = -EINVAL;
        goto out;
    }

    dev->zbd_info.zbd_physical_block_size = dev->zbd_info.zbd_logical_block_size * logical_per_physical;
    dev->zbd_info.zbd_physical_blocks = dev->zbd_info.zbd_logical_blocks / logical_per_physical;

out:

    zbc_sg_cmd_destroy(&cmd);

    if ( zones ) {
        free(zones);
    }

    return( ret );

}