With the upcoming sglist support, HBAs will not see any transfer_data call and will not have a way to detect short transfers. So pass the residual amount of data upon command completion.
Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- hw/esp.c | 3 ++- hw/lsi53c895a.c | 2 +- hw/scsi-bus.c | 6 +++++- hw/scsi.h | 3 ++- hw/spapr_vscsi.c | 2 +- hw/usb-msd.c | 2 +- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index be3a35d..5d29071 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -395,7 +395,8 @@ static void esp_do_dma(ESPState *s) esp_dma_done(s); } -static void esp_command_complete(SCSIRequest *req, uint32_t status) +static void esp_command_complete(SCSIRequest *req, uint32_t status, + int32_t resid) { ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index dac176a..a0c2419 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -706,7 +706,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len) } /* Callback to indicate that the SCSI layer has completed a command. */ -static void lsi_command_complete(SCSIRequest *req, uint32_t status) +static void lsi_command_complete(SCSIRequest *req, uint32_t status, int32_t resid) { LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); int out; diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 648b1f9..b49d02d 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -394,6 +394,8 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, } req->cmd = cmd; + req->resid = req->cmd.xfer; + switch (buf[0]) { case INQUIRY: trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]); @@ -1043,6 +1045,8 @@ void scsi_req_continue(SCSIRequest *req) void scsi_req_data(SCSIRequest *req, int len) { trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); + assert(req->cmd.mode != SCSI_XFER_NONE); + req->resid -= len; req->bus->ops->transfer_data(req, len); } @@ -1091,7 +1095,7 @@ void scsi_req_complete(SCSIRequest *req, int status) scsi_req_ref(req); scsi_req_dequeue(req); - req->bus->ops->complete(req, req->status); + req->bus->ops->complete(req, req->status, req->resid); scsi_req_unref(req); } diff --git a/hw/scsi.h b/hw/scsi.h index 98fd689..76d4df2 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -47,6 +47,7 @@ struct SCSIRequest { uint32_t tag; uint32_t lun; uint32_t status; + size_t resid; SCSICommand cmd; BlockDriverAIOCB *aiocb; uint8_t sense[SCSI_SENSE_BUF_SIZE]; @@ -98,7 +99,7 @@ struct SCSIDeviceInfo { struct SCSIBusOps { void (*transfer_data)(SCSIRequest *req, uint32_t arg); - void (*complete)(SCSIRequest *req, uint32_t arg); + void (*complete)(SCSIRequest *req, uint32_t arg, int32_t len); void (*cancel)(SCSIRequest *req); }; diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 1f4de11..128b5a6 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -467,7 +467,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) } /* Callback to indicate that the SCSI layer has completed a transfer. */ -static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status) +static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, int32_t resid) { VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); vscsi_req *req = sreq->hba_private; diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 63305b8..8cddf80 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -232,7 +232,7 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) } } -static void usb_msd_command_complete(SCSIRequest *req, uint32_t status) +static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, int32_t resid) { MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); USBPacket *p = s->packet; -- 1.7.6