/** * Fill the buffer with the result of INQUIRY command. * buf must be at least ZBC_SG_INQUIRY_REPLY_LEN bytes long. */ int zbc_sg_cmd_inquiry(zbc_device_t *dev, void *buf) { zbc_sg_cmd_t cmd; int ret; /* Allocate and intialize inquiry command */ ret = zbc_sg_cmd_init(&cmd, ZBC_SG_INQUIRY, NULL, ZBC_SG_INQUIRY_REPLY_LEN); if ( ret != 0 ) { zbc_error("%s: zbc_sg_cmd_init INQUIRY failed\n", dev->zbd_filename); return( ret ); } /* Fill command CDB: * +=============================================================================+ * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | * |Byte | | | | | | | | | * |=====+=======================================================================| * | 0 | Operation Code (12h) | * |-----+-----------------------------------------------------------------------| * | 1 | Logical Unit Number | Reserved | EVPD | * |-----+-----------------------------------------------------------------------| * | 2 | Page Code | * |-----+-----------------------------------------------------------------------| * | 3 | (MSB) | * |- - -+--- Allocation Length ---| * | 4 | (LSB) | * |-----+-----------------------------------------------------------------------| * | 5 | Control | * +=============================================================================+ */ cmd.cdb[0] = ZBC_SG_INQUIRY_CDB_OPCODE; zbc_sg_cmd_set_int16(&cmd.cdb[3], ZBC_SG_INQUIRY_REPLY_LEN); /* Execute the SG_IO command */ ret = zbc_sg_cmd_exec(dev, &cmd); if ( ret == 0 ) { memcpy(buf, cmd.out_buf, ZBC_SG_INQUIRY_REPLY_LEN); } zbc_sg_cmd_destroy(&cmd); return( ret ); }
/** * 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 ); }
/** * 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 ); }
/** * Get information (model, vendor, ...) from a SCSI device. */ static int zbc_scsi_classify(zbc_device_t *dev) { zbc_sg_cmd_t cmd; int dev_type; int n, ret; /* Allocate and intialize inquiry command */ ret = zbc_sg_cmd_init(&cmd, ZBC_SG_INQUIRY, NULL, ZBC_SG_INQUIRY_REPLY_LEN); 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 (12h) | * |-----+-----------------------------------------------------------------------| * | 1 | Logical Unit Number | Reserved | EVPD | * |-----+-----------------------------------------------------------------------| * | 2 | Page Code | * |-----+-----------------------------------------------------------------------| * | 3 | (MSB) | * |- - -+--- Allocation Length ---| * | 4 | (LSB) | * |-----+-----------------------------------------------------------------------| * | 5 | Control | * +=============================================================================+ */ cmd.cdb[0] = ZBC_SG_INQUIRY_CDB_OPCODE; zbc_sg_cmd_set_int16(&cmd.cdb[3], ZBC_SG_INQUIRY_REPLY_LEN); /* Execute the SG_IO command */ ret = zbc_sg_cmd_exec(dev, &cmd); if ( ret != 0 ) { goto out; } /* Make sure we are not dealing with an ATA device */ if ( strncmp((char *)&cmd.out_buf[8], "ATA", 3) == 0 ) { ret = -ENXIO; goto out; } /* This is a SCSI device */ dev->zbd_info.zbd_type = ZBC_DT_SCSI; /* Vendor identification */ n = zbc_sg_cmd_strcpy(&dev->zbd_info.zbd_vendor_id[0], (char *)&cmd.out_buf[8], 8); /* Product identification */ n += zbc_sg_cmd_strcpy(&dev->zbd_info.zbd_vendor_id[n], (char *)&cmd.out_buf[16], 16); /* Product revision */ n += zbc_sg_cmd_strcpy(&dev->zbd_info.zbd_vendor_id[n], (char *)&cmd.out_buf[32], 4); /* Now check the device type */ dev_type = (int)(cmd.out_buf[0] & 0x1f); if ( dev_type == ZBC_DEV_TYPE_HOST_MANAGED ) { /* Host-managed device */ zbc_debug("Host-managed ZBC disk signature detected\n"); dev->zbd_info.zbd_model = ZBC_DM_HOST_MANAGED; goto out; } if ( dev_type != ZBC_DEV_TYPE_STANDARD ) { /* Unsupported device */ ret = -ENXIO; goto out; } zbc_debug("Standard SCSI disk signature detected\n"); /* This may be a host-aware device: look at VPD */ /* page B1h (block device characteristics) */ memset(cmd.cdb, 0, sizeof(cmd.cdb)); memset(cmd.out_buf, 0, ZBC_SG_INQUIRY_REPLY_LEN_VPD_PAGE_B1); cmd.cdb[0] = ZBC_SG_INQUIRY_CDB_OPCODE; cmd.cdb[1] = 0x01; cmd.cdb[2] = 0xB1; zbc_sg_cmd_set_int16(&cmd.cdb[3], ZBC_SG_INQUIRY_REPLY_LEN_VPD_PAGE_B1); /* Execute the SG_IO command */ ret = zbc_sg_cmd_exec(dev, &cmd); if ( ret == 0 ) { if ( (cmd.out_buf[1] == 0xB1) && (cmd.out_buf[2] == 0x00) && (cmd.out_buf[3] == 0x3C) ) { switch( (cmd.out_buf[8] & 0x30) >> 4 ) { case 0x01: /* Host aware device */ zbc_debug("Host aware ZBC disk detected\n"); dev->zbd_info.zbd_model = ZBC_DM_HOST_AWARE; break; case 0x00: case 0x10: /* Standard or drive-managed device */ zbc_debug("Standard or drive managed SCSI disk detected\n"); dev->zbd_info.zbd_model = ZBC_DM_DRIVE_MANAGED; ret = -ENXIO; break; default: zbc_debug("Unknown device type\n"); dev->zbd_info.zbd_model = ZBC_DM_DRIVE_UNKNOWN; ret = -ENXIO; break; } } } out: zbc_sg_cmd_destroy(&cmd); return( ret ); }