Now that we can use SCSI command emulation without using the SCSI
disk abstraction we can easily add it to the megasas HBA.
Signed-off-by: Hannes Reinecke <hare at suse.de>
---
hw/megasas.c | 88 +++++++++++++++++++++++++++++++++++-----------------------
1 files changed, 53 insertions(+), 35 deletions(-)
diff --git a/hw/megasas.c b/hw/megasas.c
index a57e8e0..f32b313 100644
--- a/hw/megasas.c
+++ b/hw/megasas.c
@@ -661,40 +661,55 @@ static int megasas_handle_scsi(MPTState *s, uint8_t fcmd,
}
}
- memset(&cmd->hdr, 0, sizeof(struct sg_io_hdr));
- cmd->hdr.interface_id = 'S';
- cmd->hdr.cmd_len = cdb_len;
- cmd->hdr.cmdp = cdb;
- cmd->hdr.iovec_count = cmd->sge_count;
- cmd->hdr.dxferp = cmd->iov;
- for (n = 0; n < cmd->sge_count; n++)
- cmd->hdr.dxfer_len += cmd->iov[n].iov_len;
- if (cmd->sge_count) {
- if (dir)
- cmd->hdr.dxfer_direction = SG_DXFER_TO_DEV;
- else
- cmd->hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- } else {
- cmd->hdr.dxfer_direction = SG_DXFER_NONE;
- }
- cmd->hdr.sbp = cmd->sense;
- cmd->hdr.mx_sb_len = cmd->sense_len;
+ if (bdrv_is_sg(cmd->lun->bdrv)) {
+ memset(&cmd->hdr, 0, sizeof(struct sg_io_hdr));
+ cmd->hdr.interface_id = 'S';
+ cmd->hdr.cmd_len = cdb_len;
+ cmd->hdr.cmdp = cdb;
+ cmd->hdr.iovec_count = cmd->sge_count;
+ cmd->hdr.dxferp = cmd->iov;
+ for (n = 0; n < cmd->sge_count; n++)
+ cmd->hdr.dxfer_len += cmd->iov[n].iov_len;
+ if (cmd->sge_count) {
+ if (dir)
+ cmd->hdr.dxfer_direction = SG_DXFER_TO_DEV;
+ else
+ cmd->hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ } else {
+ cmd->hdr.dxfer_direction = SG_DXFER_NONE;
+ }
+ cmd->hdr.sbp = cmd->sense;
+ cmd->hdr.mx_sb_len = cmd->sense_len;
- ret = bdrv_ioctl(cmd->lun->bdrv, SG_IO, &cmd->hdr);
- if (ret) {
- DPRINTF("SCSI pthru dev %x lun %x failed with %d\n",
- target, lun, errno);
- sense_len = scsi_build_sense(cmd->sense, SENSE_IO_ERROR);
- cmd->sge_size = 0;
- scsi_status = SAM_STAT_CHECK_CONDITION;
- } else if (cmd->hdr.status) {
- sense_len = cmd->hdr.sb_len_wr;
- scsi_status = cmd->hdr.status;
- cmd->sge_size = cmd->hdr.dxfer_len;
- scsi_status = SAM_STAT_CHECK_CONDITION;
+ ret = bdrv_ioctl(cmd->lun->bdrv, SG_IO, &cmd->hdr);
+ if (ret) {
+ DPRINTF("SCSI pthru dev %x lun %x failed with %d\n",
+ target, lun, errno);
+ sense_len = scsi_build_sense(cmd->sense, SENSE_IO_ERROR);
+ cmd->sge_size = 0;
+ scsi_status = SAM_STAT_CHECK_CONDITION;
+ } else if (cmd->hdr.status) {
+ sense_len = cmd->hdr.sb_len_wr;
+ scsi_status = cmd->hdr.status;
+ cmd->sge_size = cmd->hdr.dxfer_len;
+ scsi_status = SAM_STAT_CHECK_CONDITION;
+ } else {
+ sense_len = 0;
+ cmd->sge_size = cmd->hdr.dxfer_len;
+ }
} else {
- sense_len = 0;
- cmd->sge_size = cmd->hdr.dxfer_len;
+ uint32_t sense;
+
+ DPRINTF("Emulate SCSI pthru cmd %x\n", cdb[0]);
+ sense = scsi_emulate_command(cmd->lun->bdrv, 0, cdb,
+ cmd->iov[0].iov_len,
+ cmd->iov[0].iov_base,
+ &cmd->sge_size);
+ sense_len = scsi_build_sense(cmd->sense, sense);
+ if (sense_len)
+ scsi_status = SAM_STAT_CHECK_CONDITION;
+ else
+ scsi_status = SAM_STAT_GOOD;
}
out:
megasas_unmap_sense(cmd, sense_len);
@@ -1105,13 +1120,16 @@ static int megasas_scsi_init(PCIDevice *dev)
lun->bdrv = NULL;
continue;
}
+ bdrv_set_tcq(lun->bdrv, 1);
/* check if we can use SG_IO */
ret = bdrv_ioctl(lun->bdrv, SG_IO, &hdr);
if (ret) {
- DPRINTF("SCSI cmd passthrough not available on dev %d (error
%d)\n",
+ DPRINTF("Using SCSI cmd emulation on dev %d (error %d)\n",
unit, ret);
- lun->sdev = NULL;
- lun->bdrv = NULL;
+ bdrv_set_sg(lun->bdrv, 0);
+ } else {
+ DPRINTF("Using SCSI cmd passthrough on dev %d\n", unit);
+ bdrv_set_sg(lun->bdrv, 1);
}
}
register_savevm("megasas", -1, 0, megasas_scsi_save,
megasas_scsi_load, s);
--
1.6.0.2