/** * Set a device info. */ static int zbc_fake_set_info(struct zbc_device *dev) { unsigned long long size64; struct stat st; int size32; int ret; /* Get device stats */ if ( fstat(dev->zbd_fd, &st) < 0 ) { ret = -errno; zbc_error("%s: stat failed %d (%s)\n", dev->zbd_filename, errno, strerror(errno)); return ret; } if ( S_ISBLK(st.st_mode) ) { /* Get logical block size */ ret = ioctl(dev->zbd_fd, BLKSSZGET, &size32); if ( ret != 0 ) { ret = -errno; zbc_error("%s: ioctl BLKSSZGET failed %d (%s)\n", dev->zbd_filename, errno, strerror(errno)); return ret; } dev->zbd_info.zbd_logical_block_size = size32; /* Get physical block size */ ret = ioctl(dev->zbd_fd, BLKPBSZGET, &size32); if ( ret != 0 ) { ret = -errno; zbc_error("%s: ioctl BLKPBSZGET failed %d (%s)\n", dev->zbd_filename, errno, strerror(errno)); return ret; } dev->zbd_info.zbd_physical_block_size = size32; /* Get capacity (B) */ ret = ioctl(dev->zbd_fd, BLKGETSIZE64, &size64); if ( ret != 0 ) { ret = -errno; zbc_error("%s: ioctl BLKGETSIZE64 failed %d (%s)\n", dev->zbd_filename, errno, strerror(errno)); return ret; } if ( dev->zbd_info.zbd_logical_block_size <= 0 ) { zbc_error("%s: invalid logical sector size %d\n", dev->zbd_filename, size32); return -EINVAL; } dev->zbd_info.zbd_logical_blocks = size64 / dev->zbd_info.zbd_logical_block_size; if ( dev->zbd_info.zbd_physical_block_size <= 0 ) { zbc_error("%s: invalid physical sector size %d\n", dev->zbd_filename, size32); return -EINVAL; } dev->zbd_info.zbd_physical_blocks = size64 / dev->zbd_info.zbd_physical_block_size; } else if ( S_ISREG(st.st_mode) ) { /* Default value for files */ dev->zbd_info.zbd_logical_block_size = ZBC_FAKE_FILE_SECTOR_SIZE; dev->zbd_info.zbd_logical_blocks = st.st_size / ZBC_FAKE_FILE_SECTOR_SIZE; dev->zbd_info.zbd_physical_block_size = dev->zbd_info.zbd_logical_block_size; dev->zbd_info.zbd_physical_blocks = dev->zbd_info.zbd_logical_blocks; } else { return -ENXIO; } /* Check */ if ( ! dev->zbd_info.zbd_logical_blocks ) { zbc_error("%s: invalid capacity (logical blocks)\n", dev->zbd_filename); return -EINVAL; } if ( ! dev->zbd_info.zbd_physical_blocks ) { zbc_error("%s: invalid capacity (physical blocks)\n", dev->zbd_filename); return -EINVAL; } /* Finish setting */ dev->zbd_info.zbd_type = ZBC_DT_FAKE; dev->zbd_info.zbd_model = ZBC_DM_HOST_MANAGED; strncpy(dev->zbd_info.zbd_vendor_id, "FAKE HGST HM libzbc", ZBC_DEVICE_INFO_LENGTH - 1); dev->zbd_info.zbd_opt_nr_open_seq_pref = 0; dev->zbd_info.zbd_opt_nr_non_seq_write_seq_pref = 0; dev->zbd_info.zbd_max_nr_open_seq_req = ZBC_FAKE_MAX_OPEN_NR_ZONES; /* Get maximum command size */ zbc_sg_get_max_cmd_blocks(dev); return 0; }
/** * Get a device capacity information (total sectors & sector sizes). */ int zbc_sg_get_capacity(zbc_device_t *dev, int (*report_zones)(struct zbc_device *, uint64_t, enum zbc_reporting_options, uint64_t *, zbc_zone_t *, unsigned int *)) { 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; /* Get maximum command size */ zbc_sg_get_max_cmd_blocks(dev); /* 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 = report_zones(dev, 0, ZBC_RO_ALL, &max_lba, NULL, &nr_zones); if ( ret != 0 ) { 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 reported */ 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 ); }