mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-08 18:23:57 -06:00
scsi-disk: Add native FUA write support
Simply propagate the FUA flag on write requests to the driver. The block layer will emulate it if necessary. Signed-off-by: Alberto Faria <afaria@redhat.com> Message-ID: <20250502121115.3613717-2-afaria@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
f0737158b4
commit
e460991883
1 changed files with 15 additions and 38 deletions
|
@ -74,7 +74,7 @@ struct SCSIDiskClass {
|
||||||
*/
|
*/
|
||||||
DMAIOFunc *dma_readv;
|
DMAIOFunc *dma_readv;
|
||||||
DMAIOFunc *dma_writev;
|
DMAIOFunc *dma_writev;
|
||||||
bool (*need_fua_emulation)(SCSICommand *cmd);
|
bool (*need_fua)(SCSICommand *cmd);
|
||||||
void (*update_sense)(SCSIRequest *r);
|
void (*update_sense)(SCSIRequest *r);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ typedef struct SCSIDiskReq {
|
||||||
uint32_t sector_count;
|
uint32_t sector_count;
|
||||||
uint32_t buflen;
|
uint32_t buflen;
|
||||||
bool started;
|
bool started;
|
||||||
bool need_fua_emulation;
|
bool need_fua;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
QEMUIOVector qiov;
|
QEMUIOVector qiov;
|
||||||
BlockAcctCookie acct;
|
BlockAcctCookie acct;
|
||||||
|
@ -389,24 +389,6 @@ static bool scsi_is_cmd_fua(SCSICommand *cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scsi_write_do_fua(SCSIDiskReq *r)
|
|
||||||
{
|
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
|
||||||
|
|
||||||
assert(r->req.aiocb == NULL);
|
|
||||||
assert(!r->req.io_canceled);
|
|
||||||
|
|
||||||
if (r->need_fua_emulation) {
|
|
||||||
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
|
|
||||||
BLOCK_ACCT_FLUSH);
|
|
||||||
r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
scsi_req_complete(&r->req, GOOD);
|
|
||||||
scsi_req_unref(&r->req);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret)
|
static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret)
|
||||||
{
|
{
|
||||||
assert(r->req.aiocb == NULL);
|
assert(r->req.aiocb == NULL);
|
||||||
|
@ -416,12 +398,7 @@ static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret)
|
||||||
|
|
||||||
r->sector += r->sector_count;
|
r->sector += r->sector_count;
|
||||||
r->sector_count = 0;
|
r->sector_count = 0;
|
||||||
if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
|
|
||||||
scsi_write_do_fua(r);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
scsi_req_complete(&r->req, GOOD);
|
scsi_req_complete(&r->req, GOOD);
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
scsi_req_unref(&r->req);
|
scsi_req_unref(&r->req);
|
||||||
|
@ -564,7 +541,7 @@ static void scsi_read_data(SCSIRequest *req)
|
||||||
|
|
||||||
first = !r->started;
|
first = !r->started;
|
||||||
r->started = true;
|
r->started = true;
|
||||||
if (first && r->need_fua_emulation) {
|
if (first && r->need_fua) {
|
||||||
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
|
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
|
||||||
BLOCK_ACCT_FLUSH);
|
BLOCK_ACCT_FLUSH);
|
||||||
r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_do_read_cb, r);
|
r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_do_read_cb, r);
|
||||||
|
@ -589,8 +566,7 @@ static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
|
||||||
r->sector += n;
|
r->sector += n;
|
||||||
r->sector_count -= n;
|
r->sector_count -= n;
|
||||||
if (r->sector_count == 0) {
|
if (r->sector_count == 0) {
|
||||||
scsi_write_do_fua(r);
|
scsi_req_complete(&r->req, GOOD);
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
|
scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
|
||||||
trace_scsi_disk_write_complete_noio(r->req.tag, r->qiov.size);
|
trace_scsi_disk_write_complete_noio(r->req.tag, r->qiov.size);
|
||||||
|
@ -623,6 +599,7 @@ static void scsi_write_data(SCSIRequest *req)
|
||||||
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
|
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||||
SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
|
SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
|
||||||
|
BlockCompletionFunc *cb;
|
||||||
|
|
||||||
/* No data transfer may already be in progress */
|
/* No data transfer may already be in progress */
|
||||||
assert(r->req.aiocb == NULL);
|
assert(r->req.aiocb == NULL);
|
||||||
|
@ -648,11 +625,10 @@ static void scsi_write_data(SCSIRequest *req)
|
||||||
|
|
||||||
if (r->req.cmd.buf[0] == VERIFY_10 || r->req.cmd.buf[0] == VERIFY_12 ||
|
if (r->req.cmd.buf[0] == VERIFY_10 || r->req.cmd.buf[0] == VERIFY_12 ||
|
||||||
r->req.cmd.buf[0] == VERIFY_16) {
|
r->req.cmd.buf[0] == VERIFY_16) {
|
||||||
if (r->req.sg) {
|
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
|
||||||
scsi_dma_complete_noio(r, 0);
|
BLOCK_ACCT_FLUSH);
|
||||||
} else {
|
cb = r->req.sg ? scsi_dma_complete : scsi_write_complete;
|
||||||
scsi_write_complete_noio(r, 0);
|
r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, cb, r);
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2391,7 +2367,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
|
||||||
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
|
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
r->need_fua_emulation = sdc->need_fua_emulation(&r->req.cmd);
|
r->need_fua = sdc->need_fua(&r->req.cmd);
|
||||||
if (r->sector_count == 0) {
|
if (r->sector_count == 0) {
|
||||||
scsi_req_complete(&r->req, GOOD);
|
scsi_req_complete(&r->req, GOOD);
|
||||||
}
|
}
|
||||||
|
@ -3137,7 +3113,8 @@ BlockAIOCB *scsi_dma_writev(int64_t offset, QEMUIOVector *iov,
|
||||||
{
|
{
|
||||||
SCSIDiskReq *r = opaque;
|
SCSIDiskReq *r = opaque;
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||||
return blk_aio_pwritev(s->qdev.conf.blk, offset, iov, 0, cb, cb_opaque);
|
int flags = r->need_fua ? BDRV_REQ_FUA : 0;
|
||||||
|
return blk_aio_pwritev(s->qdev.conf.blk, offset, iov, flags, cb, cb_opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *scsi_property_get_loadparm(Object *obj, Error **errp)
|
static char *scsi_property_get_loadparm(Object *obj, Error **errp)
|
||||||
|
@ -3186,7 +3163,7 @@ static void scsi_disk_base_class_initfn(ObjectClass *klass, const void *data)
|
||||||
device_class_set_legacy_reset(dc, scsi_disk_reset);
|
device_class_set_legacy_reset(dc, scsi_disk_reset);
|
||||||
sdc->dma_readv = scsi_dma_readv;
|
sdc->dma_readv = scsi_dma_readv;
|
||||||
sdc->dma_writev = scsi_dma_writev;
|
sdc->dma_writev = scsi_dma_writev;
|
||||||
sdc->need_fua_emulation = scsi_is_cmd_fua;
|
sdc->need_fua = scsi_is_cmd_fua;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo scsi_disk_base_info = {
|
static const TypeInfo scsi_disk_base_info = {
|
||||||
|
@ -3338,7 +3315,7 @@ static void scsi_block_class_initfn(ObjectClass *klass, const void *data)
|
||||||
sdc->dma_readv = scsi_block_dma_readv;
|
sdc->dma_readv = scsi_block_dma_readv;
|
||||||
sdc->dma_writev = scsi_block_dma_writev;
|
sdc->dma_writev = scsi_block_dma_writev;
|
||||||
sdc->update_sense = scsi_block_update_sense;
|
sdc->update_sense = scsi_block_update_sense;
|
||||||
sdc->need_fua_emulation = scsi_block_no_fua;
|
sdc->need_fua = scsi_block_no_fua;
|
||||||
dc->desc = "SCSI block device passthrough";
|
dc->desc = "SCSI block device passthrough";
|
||||||
device_class_set_props(dc, scsi_block_properties);
|
device_class_set_props(dc, scsi_block_properties);
|
||||||
dc->vmsd = &vmstate_scsi_disk_state;
|
dc->vmsd = &vmstate_scsi_disk_state;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue