+ struct sg_io_v4 io_v4;
+ uint8_t cdb[12];
+ uint8_t sense[32];
+ int ret;
+
+ /*
+ * INQUIRY, see SPC-4 section 6.4
+ */
+ memset(cdb, 0, sizeof(cdb));
+ cdb[0] = 0x12; /* OPERATION CODE: INQUIRY */
+ cdb[3] = (buf_len >> 8); /* ALLOCATION LENGTH */
+ cdb[4] = (buf_len & 0xff);
+
+ memset(sense, 0, sizeof(sense));
+
+ memset(&io_v4, 0, sizeof(struct sg_io_v4));
+ io_v4.guard = 'Q';
+ io_v4.protocol = BSG_PROTOCOL_SCSI;
+ io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
+ io_v4.request_len = sizeof (cdb);
+ io_v4.request = (uintptr_t) cdb;
+ io_v4.max_response_len = sizeof (sense);
+ io_v4.response = (uintptr_t) sense;
+ io_v4.din_xfer_len = buf_len;
+ io_v4.din_xferp = (uintptr_t) buf;
+ io_v4.timeout = COMMAND_TIMEOUT_MSEC;
+
+ ret = ioctl(fd, SG_IO, &io_v4);
+ if (ret != 0) {
+ /* could be that the driver doesn't do version 4, try version 3 */
+ if (errno == EINVAL) {
+ struct sg_io_hdr io_hdr;
+
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmdp = (unsigned char*) cdb;
+ io_hdr.cmd_len = sizeof (cdb);
+ io_hdr.dxferp = buf;
+ io_hdr.dxfer_len = buf_len;
+ io_hdr.sbp = sense;
+ io_hdr.mx_sb_len = sizeof (sense);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.timeout = COMMAND_TIMEOUT_MSEC;
+
+ ret = ioctl(fd, SG_IO, &io_hdr);
+ if (ret != 0)
+ goto out;
+
+ /* even if the ioctl succeeds, we need to check the return value */
+ if (!(io_hdr.status == 0 &&
+ io_hdr.host_status == 0 &&
+ io_hdr.driver_status == 0)) {
+ errno = EIO;
+ ret = -1;
+ goto out;
+ }
+ } else {
+ goto out;
+ }
+ }
+
+ /* even if the ioctl succeeds, we need to check the return value */
+ if (!(io_v4.device_status == 0 &&
+ io_v4.transport_status == 0 &&
+ io_v4.driver_status == 0)) {
+ errno = EIO;
+ ret = -1;
+ goto out;
+ }