On Thu, Jun 27, 2019 at 2:01 AM Paolo Bonzini <pbonz...@redhat.com> wrote: > > On 27/06/19 00:46, Alistair Francis wrote: > > From: Shin'ichiro Kawasaki <shinichiro.kawas...@wdc.com> > > > > When host block devices are bridged to a guest system through > > virtio-scsi-pci and scsi-block driver, scsi_handle_rw_error() in > > hw/scsi/scsi-disk.c checks the error number to judge which error to > > report to the guests. EIO and EINVAL are not reported and ignored. Once > > EIO or EINVAL happen, eternal wait of guest system happens. This problem > > was observed with zoned block devices on the host system attached to the > > guest via virtio-scsi-pci. To avoid the eternal wait, add EIO and EINVAL > > to the list of error numbers to report to the guest. > > This is certainly correct for EINVAL, I am not sure about EIO. Did you > run the VM with "-drive ...,rerror=report,werror=report"?
This is from Shin'ichiro Kawasaki: I tried to run my VM with option "-drive ...,rerror=report,werror=report" as he noted, but the eternal loop symptom still happens when host block-scsi device returns EIO. Then I believe EIO should be added to the report target error list. > > The update_sense part is okay too. Cool! Alistair > > Paolo > > > On top of this, it is required to report SCSI sense data to the guest > > so that the guest can handle the error correctly. However, > > scsi_handle_rw_error() does not passthrough sense data that host > > scsi-block device reported. Instead, it newly generates fixed sense > > data only for certain error numbers. This is inflexible to support new > > error codes to report to guest. To avoid this inflexiblity, pass the SCSI > > sense data that the host scsi-block device reported as is. To be more > > precise, set valid sense_len in the SCSIDiskReq referring sb_len_wr that > > host SCSI device SG_IO ioctl reported. Add update_sense callback to > > SCSIDiskClass to refer the SG_IO ioctl result only when scsi-block device > > is targeted. > > > > Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawas...@wdc.com> > > Signed-off-by: Alistair Francis <alistair.fran...@wdc.com> > > --- > > hw/scsi/scsi-disk.c | 15 ++++++++++++++- > > 1 file changed, 14 insertions(+), 1 deletion(-) > > > > diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c > > index ed7295bfd7..6801e3a0d0 100644 > > --- a/hw/scsi/scsi-disk.c > > +++ b/hw/scsi/scsi-disk.c > > @@ -62,6 +62,7 @@ typedef struct SCSIDiskClass { > > DMAIOFunc *dma_readv; > > DMAIOFunc *dma_writev; > > bool (*need_fua_emulation)(SCSICommand *cmd); > > + void (*update_sense)(SCSIRequest *r); > > } SCSIDiskClass; > > > > typedef struct SCSIDiskReq { > > @@ -438,6 +439,7 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int > > error, bool acct_failed) > > { > > bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV); > > SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); > > + SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); > > BlockErrorAction action = blk_get_error_action(s->qdev.conf.blk, > > is_read, error); > > > > @@ -452,9 +454,12 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int > > error, bool acct_failed) > > * pause the host. > > */ > > assert(r->status && *r->status); > > + if (sdc->update_sense) { > > + sdc->update_sense(&r->req); > > + } > > error = scsi_sense_buf_to_errno(r->req.sense, > > sizeof(r->req.sense)); > > if (error == ECANCELED || error == EAGAIN || error == ENOTCONN > > || > > - error == 0) { > > + error == EIO || error == EINVAL || error == 0) { > > /* These errors are handled by guest. */ > > scsi_req_complete(&r->req, *r->status); > > return true; > > @@ -2894,6 +2899,13 @@ static int scsi_block_parse_cdb(SCSIDevice *d, > > SCSICommand *cmd, > > } > > } > > > > +static void scsi_block_update_sense(SCSIRequest *req) > > +{ > > + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); > > + SCSIBlockReq *br = DO_UPCAST(SCSIBlockReq, req, r); > > + r->req.sense_len = MIN(br->io_header.sb_len_wr, sizeof(r->req.sense)); > > +} > > + > > #endif > > > > static > > @@ -3059,6 +3071,7 @@ static void scsi_block_class_initfn(ObjectClass > > *klass, void *data) > > sc->parse_cdb = scsi_block_parse_cdb; > > sdc->dma_readv = scsi_block_dma_readv; > > sdc->dma_writev = scsi_block_dma_writev; > > + sdc->update_sense = scsi_block_update_sense; > > sdc->need_fua_emulation = scsi_block_no_fua; > > dc->desc = "SCSI block device passthrough"; > > dc->props = scsi_block_properties; > > >