1a4ab4792SPeter Maydell #include "qemu/osdep.h"
2da34e65cSMarkus Armbruster #include "qapi/error.h"
349ab747fSPaolo Bonzini #include "qemu/error-report.h"
40b8fa32fSMarkus Armbruster #include "qemu/module.h"
5922a01a0SMarkus Armbruster #include "qemu/option.h"
615e09912SPeter Maydell #include "qemu/hw-version.h"
7a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
849ab747fSPaolo Bonzini #include "hw/scsi/scsi.h"
9ca77ee28SMarkus Armbruster #include "migration/qemu-file-types.h"
10d6454270SMarkus Armbruster #include "migration/vmstate.h"
1108e2c9f1SPaolo Bonzini #include "scsi/constants.h"
12fa1d36dfSMarkus Armbruster #include "sysemu/block-backend.h"
1349ab747fSPaolo Bonzini #include "sysemu/blockdev.h"
142f780b6aSMarkus Armbruster #include "sysemu/sysemu.h"
1554d31236SMarkus Armbruster #include "sysemu/runstate.h"
1649ab747fSPaolo Bonzini #include "trace.h"
1749ab747fSPaolo Bonzini #include "sysemu/dma.h"
18f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
1949ab747fSPaolo Bonzini
2049ab747fSPaolo Bonzini static char *scsibus_get_dev_path(DeviceState *dev);
2149ab747fSPaolo Bonzini static char *scsibus_get_fw_dev_path(DeviceState *dev);
2249ab747fSPaolo Bonzini static void scsi_req_dequeue(SCSIRequest *req);
2384642435SAsias He static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len);
2484642435SAsias He static void scsi_target_free_buf(SCSIRequest *req);
252eb5599eSStefano Garzarella static void scsi_clear_reported_luns_changed(SCSIRequest *req);
2649ab747fSPaolo Bonzini
2749ab747fSPaolo Bonzini static int next_scsi_bus;
2849ab747fSPaolo Bonzini
do_scsi_device_find(SCSIBus * bus,int channel,int id,int lun,bool include_unrealized)298ddf958eSPaolo Bonzini static SCSIDevice *do_scsi_device_find(SCSIBus *bus,
308ddf958eSPaolo Bonzini int channel, int id, int lun,
318ddf958eSPaolo Bonzini bool include_unrealized)
328ddf958eSPaolo Bonzini {
338ddf958eSPaolo Bonzini BusChild *kid;
348ddf958eSPaolo Bonzini SCSIDevice *retval = NULL;
358ddf958eSPaolo Bonzini
368ddf958eSPaolo Bonzini QTAILQ_FOREACH_RCU(kid, &bus->qbus.children, sibling) {
378ddf958eSPaolo Bonzini DeviceState *qdev = kid->child;
388ddf958eSPaolo Bonzini SCSIDevice *dev = SCSI_DEVICE(qdev);
398ddf958eSPaolo Bonzini
408ddf958eSPaolo Bonzini if (dev->channel == channel && dev->id == id) {
418ddf958eSPaolo Bonzini if (dev->lun == lun) {
428ddf958eSPaolo Bonzini retval = dev;
438ddf958eSPaolo Bonzini break;
448ddf958eSPaolo Bonzini }
458ddf958eSPaolo Bonzini
468ddf958eSPaolo Bonzini /*
478ddf958eSPaolo Bonzini * If we don't find exact match (channel/bus/lun),
488ddf958eSPaolo Bonzini * we will return the first device which matches channel/bus
498ddf958eSPaolo Bonzini */
508ddf958eSPaolo Bonzini
518ddf958eSPaolo Bonzini if (!retval) {
528ddf958eSPaolo Bonzini retval = dev;
538ddf958eSPaolo Bonzini }
548ddf958eSPaolo Bonzini }
558ddf958eSPaolo Bonzini }
568ddf958eSPaolo Bonzini
578ddf958eSPaolo Bonzini /*
588ddf958eSPaolo Bonzini * This function might run on the IO thread and we might race against
598ddf958eSPaolo Bonzini * main thread hot-plugging the device.
608ddf958eSPaolo Bonzini * We assume that as soon as .realized is set to true we can let
618ddf958eSPaolo Bonzini * the user access the device.
628ddf958eSPaolo Bonzini */
638ddf958eSPaolo Bonzini
6426462a70SStefan Hajnoczi if (retval && !include_unrealized && !qdev_is_realized(&retval->qdev)) {
658ddf958eSPaolo Bonzini retval = NULL;
668ddf958eSPaolo Bonzini }
678ddf958eSPaolo Bonzini
688ddf958eSPaolo Bonzini return retval;
698ddf958eSPaolo Bonzini }
708ddf958eSPaolo Bonzini
scsi_device_find(SCSIBus * bus,int channel,int id,int lun)718ddf958eSPaolo Bonzini SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
728ddf958eSPaolo Bonzini {
738ddf958eSPaolo Bonzini RCU_READ_LOCK_GUARD();
748ddf958eSPaolo Bonzini return do_scsi_device_find(bus, channel, id, lun, false);
758ddf958eSPaolo Bonzini }
768ddf958eSPaolo Bonzini
scsi_device_get(SCSIBus * bus,int channel,int id,int lun)778ff34495SMaxim Levitsky SCSIDevice *scsi_device_get(SCSIBus *bus, int channel, int id, int lun)
788ff34495SMaxim Levitsky {
798ff34495SMaxim Levitsky SCSIDevice *d;
808ff34495SMaxim Levitsky RCU_READ_LOCK_GUARD();
818ff34495SMaxim Levitsky d = do_scsi_device_find(bus, channel, id, lun, false);
828ff34495SMaxim Levitsky if (d) {
838ff34495SMaxim Levitsky object_ref(d);
848ff34495SMaxim Levitsky }
858ff34495SMaxim Levitsky return d;
868ff34495SMaxim Levitsky }
878ff34495SMaxim Levitsky
88eaad0fe2SStefan Hajnoczi /*
89eaad0fe2SStefan Hajnoczi * Invoke @fn() for each enqueued request in device @s. Must be called from the
90eaad0fe2SStefan Hajnoczi * main loop thread while the guest is stopped. This is only suitable for
91eaad0fe2SStefan Hajnoczi * vmstate ->put(), use scsi_device_for_each_req_async() for other cases.
92eaad0fe2SStefan Hajnoczi */
scsi_device_for_each_req_sync(SCSIDevice * s,void (* fn)(SCSIRequest *,void *),void * opaque)93eaad0fe2SStefan Hajnoczi static void scsi_device_for_each_req_sync(SCSIDevice *s,
94eaad0fe2SStefan Hajnoczi void (*fn)(SCSIRequest *, void *),
95eaad0fe2SStefan Hajnoczi void *opaque)
96eaad0fe2SStefan Hajnoczi {
97eaad0fe2SStefan Hajnoczi SCSIRequest *req;
98eaad0fe2SStefan Hajnoczi SCSIRequest *next_req;
99eaad0fe2SStefan Hajnoczi
100eaad0fe2SStefan Hajnoczi assert(!runstate_is_running());
101eaad0fe2SStefan Hajnoczi assert(qemu_in_main_thread());
102eaad0fe2SStefan Hajnoczi
103eaad0fe2SStefan Hajnoczi QTAILQ_FOREACH_SAFE(req, &s->requests, next, next_req) {
104eaad0fe2SStefan Hajnoczi fn(req, opaque);
105eaad0fe2SStefan Hajnoczi }
106eaad0fe2SStefan Hajnoczi }
107eaad0fe2SStefan Hajnoczi
108eaad0fe2SStefan Hajnoczi typedef struct {
109eaad0fe2SStefan Hajnoczi SCSIDevice *s;
110eaad0fe2SStefan Hajnoczi void (*fn)(SCSIRequest *, void *);
111eaad0fe2SStefan Hajnoczi void *fn_opaque;
112eaad0fe2SStefan Hajnoczi } SCSIDeviceForEachReqAsyncData;
113eaad0fe2SStefan Hajnoczi
scsi_device_for_each_req_async_bh(void * opaque)114eaad0fe2SStefan Hajnoczi static void scsi_device_for_each_req_async_bh(void *opaque)
115eaad0fe2SStefan Hajnoczi {
116eaad0fe2SStefan Hajnoczi g_autofree SCSIDeviceForEachReqAsyncData *data = opaque;
117eaad0fe2SStefan Hajnoczi SCSIDevice *s = data->s;
118eaad0fe2SStefan Hajnoczi AioContext *ctx;
119eaad0fe2SStefan Hajnoczi SCSIRequest *req;
120eaad0fe2SStefan Hajnoczi SCSIRequest *next;
121eaad0fe2SStefan Hajnoczi
122eaad0fe2SStefan Hajnoczi /*
1231604c049SHanna Czenczek * The BB cannot have changed contexts between this BH being scheduled and
1241604c049SHanna Czenczek * now: BBs' AioContexts, when they have a node attached, can only be
1251604c049SHanna Czenczek * changed via bdrv_try_change_aio_context(), in a drained section. While
1261604c049SHanna Czenczek * we have the in-flight counter incremented, that drain must block.
127eaad0fe2SStefan Hajnoczi */
128eaad0fe2SStefan Hajnoczi ctx = blk_get_aio_context(s->conf.blk);
1291604c049SHanna Czenczek assert(ctx == qemu_get_current_aio_context());
130eaad0fe2SStefan Hajnoczi
131eaad0fe2SStefan Hajnoczi QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) {
132eaad0fe2SStefan Hajnoczi data->fn(req, data->fn_opaque);
133eaad0fe2SStefan Hajnoczi }
134eaad0fe2SStefan Hajnoczi
135eaad0fe2SStefan Hajnoczi /* Drop the reference taken by scsi_device_for_each_req_async() */
136eaad0fe2SStefan Hajnoczi object_unref(OBJECT(s));
1371604c049SHanna Czenczek
1381604c049SHanna Czenczek /* Paired with blk_inc_in_flight() in scsi_device_for_each_req_async() */
1391604c049SHanna Czenczek blk_dec_in_flight(s->conf.blk);
140eaad0fe2SStefan Hajnoczi }
141eaad0fe2SStefan Hajnoczi
142eaad0fe2SStefan Hajnoczi /*
143eaad0fe2SStefan Hajnoczi * Schedule @fn() to be invoked for each enqueued request in device @s. @fn()
144eaad0fe2SStefan Hajnoczi * runs in the AioContext that is executing the request.
1451604c049SHanna Czenczek * Keeps the BlockBackend's in-flight counter incremented until everything is
1461604c049SHanna Czenczek * done, so draining it will settle all scheduled @fn() calls.
147eaad0fe2SStefan Hajnoczi */
scsi_device_for_each_req_async(SCSIDevice * s,void (* fn)(SCSIRequest *,void *),void * opaque)148eaad0fe2SStefan Hajnoczi static void scsi_device_for_each_req_async(SCSIDevice *s,
149eaad0fe2SStefan Hajnoczi void (*fn)(SCSIRequest *, void *),
150eaad0fe2SStefan Hajnoczi void *opaque)
151eaad0fe2SStefan Hajnoczi {
152eaad0fe2SStefan Hajnoczi assert(qemu_in_main_thread());
153eaad0fe2SStefan Hajnoczi
154eaad0fe2SStefan Hajnoczi SCSIDeviceForEachReqAsyncData *data =
155eaad0fe2SStefan Hajnoczi g_new(SCSIDeviceForEachReqAsyncData, 1);
156eaad0fe2SStefan Hajnoczi
157eaad0fe2SStefan Hajnoczi data->s = s;
158eaad0fe2SStefan Hajnoczi data->fn = fn;
159eaad0fe2SStefan Hajnoczi data->fn_opaque = opaque;
160eaad0fe2SStefan Hajnoczi
161eaad0fe2SStefan Hajnoczi /*
162eaad0fe2SStefan Hajnoczi * Hold a reference to the SCSIDevice until
163eaad0fe2SStefan Hajnoczi * scsi_device_for_each_req_async_bh() finishes.
164eaad0fe2SStefan Hajnoczi */
165eaad0fe2SStefan Hajnoczi object_ref(OBJECT(s));
166eaad0fe2SStefan Hajnoczi
1671604c049SHanna Czenczek /* Paired with blk_dec_in_flight() in scsi_device_for_each_req_async_bh() */
1681604c049SHanna Czenczek blk_inc_in_flight(s->conf.blk);
169eaad0fe2SStefan Hajnoczi aio_bh_schedule_oneshot(blk_get_aio_context(s->conf.blk),
170eaad0fe2SStefan Hajnoczi scsi_device_for_each_req_async_bh,
171eaad0fe2SStefan Hajnoczi data);
172eaad0fe2SStefan Hajnoczi }
173eaad0fe2SStefan Hajnoczi
scsi_device_realize(SCSIDevice * s,Error ** errp)174a818a4b6SFam Zheng static void scsi_device_realize(SCSIDevice *s, Error **errp)
17549ab747fSPaolo Bonzini {
17649ab747fSPaolo Bonzini SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
177a818a4b6SFam Zheng if (sc->realize) {
178a818a4b6SFam Zheng sc->realize(s, errp);
17949ab747fSPaolo Bonzini }
18049ab747fSPaolo Bonzini }
18149ab747fSPaolo Bonzini
scsi_device_unrealize(SCSIDevice * s)182b69c3c21SMarkus Armbruster static void scsi_device_unrealize(SCSIDevice *s)
1836b98c5aaSSam Eiderman {
1846b98c5aaSSam Eiderman SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
1856b98c5aaSSam Eiderman if (sc->unrealize) {
186b69c3c21SMarkus Armbruster sc->unrealize(s);
1876b98c5aaSSam Eiderman }
1886b98c5aaSSam Eiderman }
1896b98c5aaSSam Eiderman
scsi_bus_parse_cdb(SCSIDevice * dev,SCSICommand * cmd,uint8_t * buf,size_t buf_len,void * hba_private)190ff34c32cSPaolo Bonzini int scsi_bus_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
191fe9d8927SJohn Millikin size_t buf_len, void *hba_private)
192ff34c32cSPaolo Bonzini {
193ff34c32cSPaolo Bonzini SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
194ff34c32cSPaolo Bonzini int rc;
195ff34c32cSPaolo Bonzini
196ff34c32cSPaolo Bonzini assert(cmd->len == 0);
197fe9d8927SJohn Millikin rc = scsi_req_parse_cdb(dev, cmd, buf, buf_len);
198ff34c32cSPaolo Bonzini if (bus->info->parse_cdb) {
199fe9d8927SJohn Millikin rc = bus->info->parse_cdb(dev, cmd, buf, buf_len, hba_private);
200ff34c32cSPaolo Bonzini }
201ff34c32cSPaolo Bonzini return rc;
202ff34c32cSPaolo Bonzini }
203ff34c32cSPaolo Bonzini
scsi_device_alloc_req(SCSIDevice * s,uint32_t tag,uint32_t lun,uint8_t * buf,void * hba_private)20449ab747fSPaolo Bonzini static SCSIRequest *scsi_device_alloc_req(SCSIDevice *s, uint32_t tag, uint32_t lun,
20549ab747fSPaolo Bonzini uint8_t *buf, void *hba_private)
20649ab747fSPaolo Bonzini {
20749ab747fSPaolo Bonzini SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
20849ab747fSPaolo Bonzini if (sc->alloc_req) {
20949ab747fSPaolo Bonzini return sc->alloc_req(s, tag, lun, buf, hba_private);
21049ab747fSPaolo Bonzini }
21149ab747fSPaolo Bonzini
21249ab747fSPaolo Bonzini return NULL;
21349ab747fSPaolo Bonzini }
21449ab747fSPaolo Bonzini
scsi_device_unit_attention_reported(SCSIDevice * s)2158d72db68SHannes Reinecke void scsi_device_unit_attention_reported(SCSIDevice *s)
21649ab747fSPaolo Bonzini {
21749ab747fSPaolo Bonzini SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
21849ab747fSPaolo Bonzini if (sc->unit_attention_reported) {
21949ab747fSPaolo Bonzini sc->unit_attention_reported(s);
22049ab747fSPaolo Bonzini }
22149ab747fSPaolo Bonzini }
22249ab747fSPaolo Bonzini
22349ab747fSPaolo Bonzini /* Create a scsi bus, and attach devices to it. */
scsi_bus_init_named(SCSIBus * bus,size_t bus_size,DeviceState * host,const SCSIBusInfo * info,const char * bus_name)224739e95f5SPeter Maydell void scsi_bus_init_named(SCSIBus *bus, size_t bus_size, DeviceState *host,
225b1187b51SAndreas Färber const SCSIBusInfo *info, const char *bus_name)
22649ab747fSPaolo Bonzini {
227d637e1dcSPeter Maydell qbus_init(bus, bus_size, TYPE_SCSI_BUS, host, bus_name);
22849ab747fSPaolo Bonzini bus->busnr = next_scsi_bus++;
22949ab747fSPaolo Bonzini bus->info = info;
230cd7c8660SMarkus Armbruster qbus_set_bus_hotplug_handler(BUS(bus));
23149ab747fSPaolo Bonzini }
23249ab747fSPaolo Bonzini
scsi_req_retry(SCSIRequest * req)233eaad0fe2SStefan Hajnoczi void scsi_req_retry(SCSIRequest *req)
23449ab747fSPaolo Bonzini {
235eaad0fe2SStefan Hajnoczi req->retry = true;
236eaad0fe2SStefan Hajnoczi }
23749ab747fSPaolo Bonzini
238eaad0fe2SStefan Hajnoczi /* Called in the AioContext that is executing the request */
scsi_dma_restart_req(SCSIRequest * req,void * opaque)239eaad0fe2SStefan Hajnoczi static void scsi_dma_restart_req(SCSIRequest *req, void *opaque)
240eaad0fe2SStefan Hajnoczi {
24149ab747fSPaolo Bonzini scsi_req_ref(req);
24249ab747fSPaolo Bonzini if (req->retry) {
24349ab747fSPaolo Bonzini req->retry = false;
24449ab747fSPaolo Bonzini switch (req->cmd.mode) {
24549ab747fSPaolo Bonzini case SCSI_XFER_FROM_DEV:
24649ab747fSPaolo Bonzini case SCSI_XFER_TO_DEV:
24749ab747fSPaolo Bonzini scsi_req_continue(req);
24849ab747fSPaolo Bonzini break;
24949ab747fSPaolo Bonzini case SCSI_XFER_NONE:
25049ab747fSPaolo Bonzini scsi_req_dequeue(req);
25149ab747fSPaolo Bonzini scsi_req_enqueue(req);
25249ab747fSPaolo Bonzini break;
25349ab747fSPaolo Bonzini }
25449ab747fSPaolo Bonzini }
25549ab747fSPaolo Bonzini scsi_req_unref(req);
25649ab747fSPaolo Bonzini }
25749ab747fSPaolo Bonzini
scsi_dma_restart_cb(void * opaque,bool running,RunState state)258538f0497SPhilippe Mathieu-Daudé static void scsi_dma_restart_cb(void *opaque, bool running, RunState state)
25949ab747fSPaolo Bonzini {
26049ab747fSPaolo Bonzini SCSIDevice *s = opaque;
26149ab747fSPaolo Bonzini
262eaad0fe2SStefan Hajnoczi assert(qemu_in_main_thread());
263eaad0fe2SStefan Hajnoczi
26449ab747fSPaolo Bonzini if (!running) {
26549ab747fSPaolo Bonzini return;
26649ab747fSPaolo Bonzini }
267eaad0fe2SStefan Hajnoczi
268eaad0fe2SStefan Hajnoczi scsi_device_for_each_req_async(s, scsi_dma_restart_req, NULL);
26949ab747fSPaolo Bonzini }
27049ab747fSPaolo Bonzini
scsi_bus_is_address_free(SCSIBus * bus,int channel,int target,int lun,SCSIDevice ** p_dev)27142a90a89SPaolo Bonzini static bool scsi_bus_is_address_free(SCSIBus *bus,
27242a90a89SPaolo Bonzini int channel, int target, int lun,
27342a90a89SPaolo Bonzini SCSIDevice **p_dev)
27442a90a89SPaolo Bonzini {
2758ddf958eSPaolo Bonzini SCSIDevice *d;
2768ddf958eSPaolo Bonzini
2778ddf958eSPaolo Bonzini RCU_READ_LOCK_GUARD();
2788ddf958eSPaolo Bonzini d = do_scsi_device_find(bus, channel, target, lun, true);
27942a90a89SPaolo Bonzini if (d && d->lun == lun) {
28042a90a89SPaolo Bonzini if (p_dev) {
28142a90a89SPaolo Bonzini *p_dev = d;
28242a90a89SPaolo Bonzini }
28342a90a89SPaolo Bonzini return false;
28442a90a89SPaolo Bonzini }
28542a90a89SPaolo Bonzini if (p_dev) {
28642a90a89SPaolo Bonzini *p_dev = NULL;
28742a90a89SPaolo Bonzini }
28842a90a89SPaolo Bonzini return true;
28942a90a89SPaolo Bonzini }
29042a90a89SPaolo Bonzini
scsi_bus_check_address(BusState * qbus,DeviceState * qdev,Error ** errp)29142a90a89SPaolo Bonzini static bool scsi_bus_check_address(BusState *qbus, DeviceState *qdev, Error **errp)
29242a90a89SPaolo Bonzini {
29342a90a89SPaolo Bonzini SCSIDevice *dev = SCSI_DEVICE(qdev);
29442a90a89SPaolo Bonzini SCSIBus *bus = SCSI_BUS(qbus);
29542a90a89SPaolo Bonzini
29642a90a89SPaolo Bonzini if (dev->channel > bus->info->max_channel) {
29742a90a89SPaolo Bonzini error_setg(errp, "bad scsi channel id: %d", dev->channel);
29842a90a89SPaolo Bonzini return false;
29942a90a89SPaolo Bonzini }
30042a90a89SPaolo Bonzini if (dev->id != -1 && dev->id > bus->info->max_target) {
30142a90a89SPaolo Bonzini error_setg(errp, "bad scsi device id: %d", dev->id);
30242a90a89SPaolo Bonzini return false;
30342a90a89SPaolo Bonzini }
30442a90a89SPaolo Bonzini if (dev->lun != -1 && dev->lun > bus->info->max_lun) {
30542a90a89SPaolo Bonzini error_setg(errp, "bad scsi device lun: %d", dev->lun);
30642a90a89SPaolo Bonzini return false;
30742a90a89SPaolo Bonzini }
30842a90a89SPaolo Bonzini
30942a90a89SPaolo Bonzini if (dev->id != -1 && dev->lun != -1) {
31042a90a89SPaolo Bonzini SCSIDevice *d;
31142a90a89SPaolo Bonzini if (!scsi_bus_is_address_free(bus, dev->channel, dev->id, dev->lun, &d)) {
31242a90a89SPaolo Bonzini error_setg(errp, "lun already used by '%s'", d->qdev.id);
31342a90a89SPaolo Bonzini return false;
31442a90a89SPaolo Bonzini }
31542a90a89SPaolo Bonzini }
31642a90a89SPaolo Bonzini
31742a90a89SPaolo Bonzini return true;
31842a90a89SPaolo Bonzini }
31942a90a89SPaolo Bonzini
scsi_qdev_realize(DeviceState * qdev,Error ** errp)320a818a4b6SFam Zheng static void scsi_qdev_realize(DeviceState *qdev, Error **errp)
32149ab747fSPaolo Bonzini {
32249ab747fSPaolo Bonzini SCSIDevice *dev = SCSI_DEVICE(qdev);
32349ab747fSPaolo Bonzini SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
32442a90a89SPaolo Bonzini bool is_free;
325a818a4b6SFam Zheng Error *local_err = NULL;
32649ab747fSPaolo Bonzini
32749ab747fSPaolo Bonzini if (dev->id == -1) {
32849ab747fSPaolo Bonzini int id = -1;
32949ab747fSPaolo Bonzini if (dev->lun == -1) {
33049ab747fSPaolo Bonzini dev->lun = 0;
33149ab747fSPaolo Bonzini }
33249ab747fSPaolo Bonzini do {
33342a90a89SPaolo Bonzini is_free = scsi_bus_is_address_free(bus, dev->channel, ++id, dev->lun, NULL);
33442a90a89SPaolo Bonzini } while (!is_free && id < bus->info->max_target);
33542a90a89SPaolo Bonzini if (!is_free) {
336a818a4b6SFam Zheng error_setg(errp, "no free target");
337a818a4b6SFam Zheng return;
33849ab747fSPaolo Bonzini }
33949ab747fSPaolo Bonzini dev->id = id;
34049ab747fSPaolo Bonzini } else if (dev->lun == -1) {
34149ab747fSPaolo Bonzini int lun = -1;
34249ab747fSPaolo Bonzini do {
34342a90a89SPaolo Bonzini is_free = scsi_bus_is_address_free(bus, dev->channel, dev->id, ++lun, NULL);
34442a90a89SPaolo Bonzini } while (!is_free && lun < bus->info->max_lun);
34542a90a89SPaolo Bonzini if (!is_free) {
346a818a4b6SFam Zheng error_setg(errp, "no free lun");
347a818a4b6SFam Zheng return;
34849ab747fSPaolo Bonzini }
34949ab747fSPaolo Bonzini dev->lun = lun;
35049ab747fSPaolo Bonzini }
35149ab747fSPaolo Bonzini
35249ab747fSPaolo Bonzini QTAILQ_INIT(&dev->requests);
353a818a4b6SFam Zheng scsi_device_realize(dev, &local_err);
354a818a4b6SFam Zheng if (local_err) {
355a818a4b6SFam Zheng error_propagate(errp, local_err);
356a818a4b6SFam Zheng return;
357a818a4b6SFam Zheng }
3581a8c091cSStefan Hajnoczi dev->vmsentry = qdev_add_vm_change_state_handler(DEVICE(dev),
3591a8c091cSStefan Hajnoczi scsi_dma_restart_cb, dev);
36049ab747fSPaolo Bonzini }
36149ab747fSPaolo Bonzini
scsi_qdev_unrealize(DeviceState * qdev)362b69c3c21SMarkus Armbruster static void scsi_qdev_unrealize(DeviceState *qdev)
36349ab747fSPaolo Bonzini {
36449ab747fSPaolo Bonzini SCSIDevice *dev = SCSI_DEVICE(qdev);
36549ab747fSPaolo Bonzini
36649ab747fSPaolo Bonzini if (dev->vmsentry) {
36749ab747fSPaolo Bonzini qemu_del_vm_change_state_handler(dev->vmsentry);
36849ab747fSPaolo Bonzini }
369fb7b5c0dSPaolo Bonzini
370fb7b5c0dSPaolo Bonzini scsi_device_purge_requests(dev, SENSE_CODE(NO_SENSE));
3716b98c5aaSSam Eiderman
372b69c3c21SMarkus Armbruster scsi_device_unrealize(dev);
3736b98c5aaSSam Eiderman
374fb7b5c0dSPaolo Bonzini blockdev_mark_auto_del(dev->conf.blk);
37549ab747fSPaolo Bonzini }
37649ab747fSPaolo Bonzini
37749ab747fSPaolo Bonzini /* handle legacy '-drive if=scsi,...' cmd line args */
scsi_bus_legacy_add_drive(SCSIBus * bus,BlockBackend * blk,int unit,bool removable,BlockConf * conf,const char * serial,Error ** errp)3784be74634SMarkus Armbruster SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
37930896374SKevin Wolf int unit, bool removable, BlockConf *conf,
380caad4eb3SAndreas Färber const char *serial, Error **errp)
38149ab747fSPaolo Bonzini {
38249ab747fSPaolo Bonzini const char *driver;
38322647504SPaolo Bonzini char *name;
38449ab747fSPaolo Bonzini DeviceState *dev;
38530896374SKevin Wolf SCSIDevice *s;
3860d074bf8SPaolo Bonzini DriveInfo *dinfo;
387*57a8a80dSFiona Ebner Error *local_err = NULL;
38849ab747fSPaolo Bonzini
3890d074bf8SPaolo Bonzini if (blk_is_sg(blk)) {
3900d074bf8SPaolo Bonzini driver = "scsi-generic";
3910d074bf8SPaolo Bonzini } else {
3920d074bf8SPaolo Bonzini dinfo = blk_legacy_dinfo(blk);
3930d074bf8SPaolo Bonzini if (dinfo && dinfo->media_cd) {
3940d074bf8SPaolo Bonzini driver = "scsi-cd";
3950d074bf8SPaolo Bonzini } else {
3960d074bf8SPaolo Bonzini driver = "scsi-hd";
3970d074bf8SPaolo Bonzini }
3980d074bf8SPaolo Bonzini }
3993e80f690SMarkus Armbruster dev = qdev_new(driver);
40022647504SPaolo Bonzini name = g_strdup_printf("legacy[%d]", unit);
401d2623129SMarkus Armbruster object_property_add_child(OBJECT(bus), name, OBJECT(dev));
40222647504SPaolo Bonzini g_free(name);
40322647504SPaolo Bonzini
40430896374SKevin Wolf s = SCSI_DEVICE(dev);
40530896374SKevin Wolf s->conf = *conf;
40630896374SKevin Wolf
407*57a8a80dSFiona Ebner check_boot_index(conf->bootindex, &local_err);
408*57a8a80dSFiona Ebner if (local_err) {
409*57a8a80dSFiona Ebner object_unparent(OBJECT(dev));
410*57a8a80dSFiona Ebner error_propagate(errp, local_err);
411*57a8a80dSFiona Ebner return NULL;
412*57a8a80dSFiona Ebner }
413*57a8a80dSFiona Ebner add_boot_device_path(conf->bootindex, dev, NULL);
414*57a8a80dSFiona Ebner
41549ab747fSPaolo Bonzini qdev_prop_set_uint32(dev, "scsi-id", unit);
416efba1595SDaniel P. Berrangé if (object_property_find(OBJECT(dev), "removable")) {
41749ab747fSPaolo Bonzini qdev_prop_set_bit(dev, "removable", removable);
41849ab747fSPaolo Bonzini }
419efba1595SDaniel P. Berrangé if (serial && object_property_find(OBJECT(dev), "serial")) {
42049ab747fSPaolo Bonzini qdev_prop_set_string(dev, "serial", serial);
42149ab747fSPaolo Bonzini }
422668f62ecSMarkus Armbruster if (!qdev_prop_set_drive_err(dev, "drive", blk, errp)) {
42302a5c4c9SStefan Hajnoczi object_unparent(OBJECT(dev));
42449ab747fSPaolo Bonzini return NULL;
42549ab747fSPaolo Bonzini }
426b8efb36bSKevin Wolf
427668f62ecSMarkus Armbruster if (!qdev_realize_and_unref(dev, &bus->qbus, errp)) {
42802a5c4c9SStefan Hajnoczi object_unparent(OBJECT(dev));
42949ab747fSPaolo Bonzini return NULL;
430caad4eb3SAndreas Färber }
43130896374SKevin Wolf return s;
43249ab747fSPaolo Bonzini }
43349ab747fSPaolo Bonzini
scsi_bus_legacy_handle_cmdline(SCSIBus * bus)43414545097SThomas Huth void scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
43549ab747fSPaolo Bonzini {
43649ab747fSPaolo Bonzini Location loc;
43749ab747fSPaolo Bonzini DriveInfo *dinfo;
438caad4eb3SAndreas Färber int unit;
43930896374SKevin Wolf BlockConf conf = {
44030896374SKevin Wolf .bootindex = -1,
44130896374SKevin Wolf .share_rw = false,
44230896374SKevin Wolf .rerror = BLOCKDEV_ON_ERROR_AUTO,
44330896374SKevin Wolf .werror = BLOCKDEV_ON_ERROR_AUTO,
44430896374SKevin Wolf };
44549ab747fSPaolo Bonzini
44649ab747fSPaolo Bonzini loc_push_none(&loc);
44749ab747fSPaolo Bonzini for (unit = 0; unit <= bus->info->max_target; unit++) {
44849ab747fSPaolo Bonzini dinfo = drive_get(IF_SCSI, bus->busnr, unit);
44949ab747fSPaolo Bonzini if (dinfo == NULL) {
45049ab747fSPaolo Bonzini continue;
45149ab747fSPaolo Bonzini }
45249ab747fSPaolo Bonzini qemu_opts_loc_restore(dinfo->opts);
4534be74634SMarkus Armbruster scsi_bus_legacy_add_drive(bus, blk_by_legacy_dinfo(dinfo),
45430896374SKevin Wolf unit, false, &conf, NULL, &error_fatal);
45549ab747fSPaolo Bonzini }
45649ab747fSPaolo Bonzini loc_pop(&loc);
45749ab747fSPaolo Bonzini }
45849ab747fSPaolo Bonzini
scsi_invalid_field(SCSIRequest * req,uint8_t * buf)45949ab747fSPaolo Bonzini static int32_t scsi_invalid_field(SCSIRequest *req, uint8_t *buf)
46049ab747fSPaolo Bonzini {
46149ab747fSPaolo Bonzini scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD));
46249ab747fSPaolo Bonzini scsi_req_complete(req, CHECK_CONDITION);
46349ab747fSPaolo Bonzini return 0;
46449ab747fSPaolo Bonzini }
46549ab747fSPaolo Bonzini
46649ab747fSPaolo Bonzini static const struct SCSIReqOps reqops_invalid_field = {
46749ab747fSPaolo Bonzini .size = sizeof(SCSIRequest),
46849ab747fSPaolo Bonzini .send_command = scsi_invalid_field
46949ab747fSPaolo Bonzini };
47049ab747fSPaolo Bonzini
47149ab747fSPaolo Bonzini /* SCSIReqOps implementation for invalid commands. */
47249ab747fSPaolo Bonzini
scsi_invalid_command(SCSIRequest * req,uint8_t * buf)47349ab747fSPaolo Bonzini static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf)
47449ab747fSPaolo Bonzini {
47549ab747fSPaolo Bonzini scsi_req_build_sense(req, SENSE_CODE(INVALID_OPCODE));
47649ab747fSPaolo Bonzini scsi_req_complete(req, CHECK_CONDITION);
47749ab747fSPaolo Bonzini return 0;
47849ab747fSPaolo Bonzini }
47949ab747fSPaolo Bonzini
48049ab747fSPaolo Bonzini static const struct SCSIReqOps reqops_invalid_opcode = {
48149ab747fSPaolo Bonzini .size = sizeof(SCSIRequest),
48249ab747fSPaolo Bonzini .send_command = scsi_invalid_command
48349ab747fSPaolo Bonzini };
48449ab747fSPaolo Bonzini
48549ab747fSPaolo Bonzini /* SCSIReqOps implementation for unit attention conditions. */
48649ab747fSPaolo Bonzini
scsi_fetch_unit_attention_sense(SCSIRequest * req)4879472083eSStefano Garzarella static void scsi_fetch_unit_attention_sense(SCSIRequest *req)
4889472083eSStefano Garzarella {
4899472083eSStefano Garzarella SCSISense *ua = NULL;
4909472083eSStefano Garzarella
4919472083eSStefano Garzarella if (req->dev->unit_attention.key == UNIT_ATTENTION) {
4929472083eSStefano Garzarella ua = &req->dev->unit_attention;
4939472083eSStefano Garzarella } else if (req->bus->unit_attention.key == UNIT_ATTENTION) {
4949472083eSStefano Garzarella ua = &req->bus->unit_attention;
4959472083eSStefano Garzarella }
4969472083eSStefano Garzarella
4979472083eSStefano Garzarella /*
4989472083eSStefano Garzarella * Fetch the unit attention sense immediately so that another
4999472083eSStefano Garzarella * scsi_req_new does not use reqops_unit_attention.
5009472083eSStefano Garzarella */
5019472083eSStefano Garzarella if (ua) {
5029472083eSStefano Garzarella scsi_req_build_sense(req, *ua);
5039472083eSStefano Garzarella *ua = SENSE_CODE(NO_SENSE);
5049472083eSStefano Garzarella }
5059472083eSStefano Garzarella }
5069472083eSStefano Garzarella
scsi_unit_attention(SCSIRequest * req,uint8_t * buf)50749ab747fSPaolo Bonzini static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
50849ab747fSPaolo Bonzini {
50949ab747fSPaolo Bonzini scsi_req_complete(req, CHECK_CONDITION);
51049ab747fSPaolo Bonzini return 0;
51149ab747fSPaolo Bonzini }
51249ab747fSPaolo Bonzini
51349ab747fSPaolo Bonzini static const struct SCSIReqOps reqops_unit_attention = {
51449ab747fSPaolo Bonzini .size = sizeof(SCSIRequest),
5159472083eSStefano Garzarella .init_req = scsi_fetch_unit_attention_sense,
51649ab747fSPaolo Bonzini .send_command = scsi_unit_attention
51749ab747fSPaolo Bonzini };
51849ab747fSPaolo Bonzini
51949ab747fSPaolo Bonzini /* SCSIReqOps implementation for REPORT LUNS and for commands sent to
52049ab747fSPaolo Bonzini an invalid LUN. */
52149ab747fSPaolo Bonzini
52249ab747fSPaolo Bonzini typedef struct SCSITargetReq SCSITargetReq;
52349ab747fSPaolo Bonzini
52449ab747fSPaolo Bonzini struct SCSITargetReq {
52549ab747fSPaolo Bonzini SCSIRequest req;
52649ab747fSPaolo Bonzini int len;
52784642435SAsias He uint8_t *buf;
52884642435SAsias He int buf_len;
52949ab747fSPaolo Bonzini };
53049ab747fSPaolo Bonzini
store_lun(uint8_t * outbuf,int lun)53149ab747fSPaolo Bonzini static void store_lun(uint8_t *outbuf, int lun)
53249ab747fSPaolo Bonzini {
53349ab747fSPaolo Bonzini if (lun < 256) {
5348cfe8013SMaxim Levitsky /* Simple logical unit addressing method*/
5358cfe8013SMaxim Levitsky outbuf[0] = 0;
53649ab747fSPaolo Bonzini outbuf[1] = lun;
5378cfe8013SMaxim Levitsky } else {
5388cfe8013SMaxim Levitsky /* Flat space addressing method */
5398cfe8013SMaxim Levitsky outbuf[0] = 0x40 | (lun >> 8);
54049ab747fSPaolo Bonzini outbuf[1] = (lun & 255);
5418cfe8013SMaxim Levitsky }
54249ab747fSPaolo Bonzini }
54349ab747fSPaolo Bonzini
scsi_target_emulate_report_luns(SCSITargetReq * r)54449ab747fSPaolo Bonzini static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
54549ab747fSPaolo Bonzini {
54649ab747fSPaolo Bonzini BusChild *kid;
54749ab747fSPaolo Bonzini int channel, id;
5488cfe8013SMaxim Levitsky uint8_t tmp[8] = {0};
5498cfe8013SMaxim Levitsky int len = 0;
5508cfe8013SMaxim Levitsky GByteArray *buf;
55149ab747fSPaolo Bonzini
55249ab747fSPaolo Bonzini if (r->req.cmd.xfer < 16) {
55349ab747fSPaolo Bonzini return false;
55449ab747fSPaolo Bonzini }
55549ab747fSPaolo Bonzini if (r->req.cmd.buf[2] > 2) {
55649ab747fSPaolo Bonzini return false;
55749ab747fSPaolo Bonzini }
5588cfe8013SMaxim Levitsky
5598cfe8013SMaxim Levitsky /* reserve space for 63 LUNs*/
5608cfe8013SMaxim Levitsky buf = g_byte_array_sized_new(512);
5618cfe8013SMaxim Levitsky
56249ab747fSPaolo Bonzini channel = r->req.dev->channel;
56349ab747fSPaolo Bonzini id = r->req.dev->id;
5642d24a646SMaxim Levitsky
5658cfe8013SMaxim Levitsky /* add size (will be updated later to correct value */
5668cfe8013SMaxim Levitsky g_byte_array_append(buf, tmp, 8);
5678cfe8013SMaxim Levitsky len += 8;
5682d24a646SMaxim Levitsky
5698cfe8013SMaxim Levitsky /* add LUN0 */
5708cfe8013SMaxim Levitsky g_byte_array_append(buf, tmp, 8);
5718cfe8013SMaxim Levitsky len += 8;
5728cfe8013SMaxim Levitsky
5738cfe8013SMaxim Levitsky WITH_RCU_READ_LOCK_GUARD() {
5742d24a646SMaxim Levitsky QTAILQ_FOREACH_RCU(kid, &r->req.bus->qbus.children, sibling) {
57549ab747fSPaolo Bonzini DeviceState *qdev = kid->child;
57649ab747fSPaolo Bonzini SCSIDevice *dev = SCSI_DEVICE(qdev);
57749ab747fSPaolo Bonzini
5784382f167SStefan Hajnoczi if (dev->channel == channel && dev->id == id && dev->lun != 0 &&
5794382f167SStefan Hajnoczi qdev_is_realized(&dev->qdev)) {
5808cfe8013SMaxim Levitsky store_lun(tmp, dev->lun);
5818cfe8013SMaxim Levitsky g_byte_array_append(buf, tmp, 8);
5828cfe8013SMaxim Levitsky len += 8;
58349ab747fSPaolo Bonzini }
58449ab747fSPaolo Bonzini }
58549ab747fSPaolo Bonzini }
5862d24a646SMaxim Levitsky
5878cfe8013SMaxim Levitsky r->buf_len = len;
5888cfe8013SMaxim Levitsky r->buf = g_byte_array_free(buf, FALSE);
5898cfe8013SMaxim Levitsky r->len = MIN(len, r->req.cmd.xfer & ~7);
5908cfe8013SMaxim Levitsky
5918cfe8013SMaxim Levitsky /* store the LUN list length */
5928cfe8013SMaxim Levitsky stl_be_p(&r->buf[0], len - 8);
5932eb5599eSStefano Garzarella
5942eb5599eSStefano Garzarella /*
5952eb5599eSStefano Garzarella * If a REPORT LUNS command enters the enabled command state, [...]
5962eb5599eSStefano Garzarella * the device server shall clear any pending unit attention condition
5972eb5599eSStefano Garzarella * with an additional sense code of REPORTED LUNS DATA HAS CHANGED.
5982eb5599eSStefano Garzarella */
5992eb5599eSStefano Garzarella scsi_clear_reported_luns_changed(&r->req);
6002eb5599eSStefano Garzarella
60149ab747fSPaolo Bonzini return true;
60249ab747fSPaolo Bonzini }
60349ab747fSPaolo Bonzini
scsi_target_emulate_inquiry(SCSITargetReq * r)60449ab747fSPaolo Bonzini static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
60549ab747fSPaolo Bonzini {
60649ab747fSPaolo Bonzini assert(r->req.dev->lun != r->req.lun);
60784642435SAsias He
60884642435SAsias He scsi_target_alloc_buf(&r->req, SCSI_INQUIRY_LEN);
60984642435SAsias He
61049ab747fSPaolo Bonzini if (r->req.cmd.buf[1] & 0x2) {
61149ab747fSPaolo Bonzini /* Command support data - optional, not implemented */
61249ab747fSPaolo Bonzini return false;
61349ab747fSPaolo Bonzini }
61449ab747fSPaolo Bonzini
61549ab747fSPaolo Bonzini if (r->req.cmd.buf[1] & 0x1) {
61649ab747fSPaolo Bonzini /* Vital product data */
61749ab747fSPaolo Bonzini uint8_t page_code = r->req.cmd.buf[2];
61849ab747fSPaolo Bonzini r->buf[r->len++] = page_code ; /* this page */
61949ab747fSPaolo Bonzini r->buf[r->len++] = 0x00;
62049ab747fSPaolo Bonzini
62149ab747fSPaolo Bonzini switch (page_code) {
62249ab747fSPaolo Bonzini case 0x00: /* Supported page codes, mandatory */
62349ab747fSPaolo Bonzini {
62449ab747fSPaolo Bonzini int pages;
62549ab747fSPaolo Bonzini pages = r->len++;
62649ab747fSPaolo Bonzini r->buf[r->len++] = 0x00; /* list of supported pages (this page) */
62749ab747fSPaolo Bonzini r->buf[pages] = r->len - pages - 1; /* number of pages */
62849ab747fSPaolo Bonzini break;
62949ab747fSPaolo Bonzini }
63049ab747fSPaolo Bonzini default:
63149ab747fSPaolo Bonzini return false;
63249ab747fSPaolo Bonzini }
63349ab747fSPaolo Bonzini /* done with EVPD */
63484642435SAsias He assert(r->len < r->buf_len);
63549ab747fSPaolo Bonzini r->len = MIN(r->req.cmd.xfer, r->len);
63649ab747fSPaolo Bonzini return true;
63749ab747fSPaolo Bonzini }
63849ab747fSPaolo Bonzini
63949ab747fSPaolo Bonzini /* Standard INQUIRY data */
64049ab747fSPaolo Bonzini if (r->req.cmd.buf[2] != 0) {
64149ab747fSPaolo Bonzini return false;
64249ab747fSPaolo Bonzini }
64349ab747fSPaolo Bonzini
64449ab747fSPaolo Bonzini /* PAGE CODE == 0 */
64584642435SAsias He r->len = MIN(r->req.cmd.xfer, SCSI_INQUIRY_LEN);
64649ab747fSPaolo Bonzini memset(r->buf, 0, r->len);
64749ab747fSPaolo Bonzini if (r->req.lun != 0) {
64849ab747fSPaolo Bonzini r->buf[0] = TYPE_NO_LUN;
64949ab747fSPaolo Bonzini } else {
65049ab747fSPaolo Bonzini r->buf[0] = TYPE_NOT_PRESENT | TYPE_INACTIVE;
65149ab747fSPaolo Bonzini r->buf[2] = 5; /* Version */
65249ab747fSPaolo Bonzini r->buf[3] = 2 | 0x10; /* HiSup, response data format */
65349ab747fSPaolo Bonzini r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */
65449ab747fSPaolo Bonzini r->buf[7] = 0x10 | (r->req.bus->info->tcq ? 0x02 : 0); /* Sync, TCQ. */
65549ab747fSPaolo Bonzini memcpy(&r->buf[8], "QEMU ", 8);
65649ab747fSPaolo Bonzini memcpy(&r->buf[16], "QEMU TARGET ", 16);
65735c2c8dcSEduardo Habkost pstrcpy((char *) &r->buf[32], 4, qemu_hw_version());
65849ab747fSPaolo Bonzini }
65949ab747fSPaolo Bonzini return true;
66049ab747fSPaolo Bonzini }
66149ab747fSPaolo Bonzini
scsi_sense_len(SCSIRequest * req)6626959e508SJarkko Lavinen static size_t scsi_sense_len(SCSIRequest *req)
6636959e508SJarkko Lavinen {
6646959e508SJarkko Lavinen if (req->dev->type == TYPE_SCANNER)
6656959e508SJarkko Lavinen return SCSI_SENSE_LEN_SCANNER;
6666959e508SJarkko Lavinen else
6676959e508SJarkko Lavinen return SCSI_SENSE_LEN;
6686959e508SJarkko Lavinen }
6696959e508SJarkko Lavinen
scsi_target_send_command(SCSIRequest * req,uint8_t * buf)67049ab747fSPaolo Bonzini static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
67149ab747fSPaolo Bonzini {
67249ab747fSPaolo Bonzini SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
673b07fbce6SHannes Reinecke int fixed_sense = (req->cmd.buf[1] & 1) == 0;
67449ab747fSPaolo Bonzini
675b07fbce6SHannes Reinecke if (req->lun != 0 &&
676b07fbce6SHannes Reinecke buf[0] != INQUIRY && buf[0] != REQUEST_SENSE) {
677ded6ddc5SHannes Reinecke scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
678ded6ddc5SHannes Reinecke scsi_req_complete(req, CHECK_CONDITION);
679ded6ddc5SHannes Reinecke return 0;
680ded6ddc5SHannes Reinecke }
68149ab747fSPaolo Bonzini switch (buf[0]) {
68249ab747fSPaolo Bonzini case REPORT_LUNS:
68349ab747fSPaolo Bonzini if (!scsi_target_emulate_report_luns(r)) {
68449ab747fSPaolo Bonzini goto illegal_request;
68549ab747fSPaolo Bonzini }
68649ab747fSPaolo Bonzini break;
68749ab747fSPaolo Bonzini case INQUIRY:
68849ab747fSPaolo Bonzini if (!scsi_target_emulate_inquiry(r)) {
68949ab747fSPaolo Bonzini goto illegal_request;
69049ab747fSPaolo Bonzini }
69149ab747fSPaolo Bonzini break;
69249ab747fSPaolo Bonzini case REQUEST_SENSE:
6936959e508SJarkko Lavinen scsi_target_alloc_buf(&r->req, scsi_sense_len(req));
694b07fbce6SHannes Reinecke if (req->lun != 0) {
695b07fbce6SHannes Reinecke const struct SCSISense sense = SENSE_CODE(LUN_NOT_SUPPORTED);
696b07fbce6SHannes Reinecke
697f68d98b2SPaolo Bonzini r->len = scsi_build_sense_buf(r->buf, req->cmd.xfer,
698f68d98b2SPaolo Bonzini sense, fixed_sense);
699b07fbce6SHannes Reinecke } else {
70049ab747fSPaolo Bonzini r->len = scsi_device_get_sense(r->req.dev, r->buf,
70184642435SAsias He MIN(req->cmd.xfer, r->buf_len),
702b07fbce6SHannes Reinecke fixed_sense);
703b07fbce6SHannes Reinecke }
70449ab747fSPaolo Bonzini if (r->req.dev->sense_is_ua) {
70549ab747fSPaolo Bonzini scsi_device_unit_attention_reported(req->dev);
70649ab747fSPaolo Bonzini r->req.dev->sense_len = 0;
70749ab747fSPaolo Bonzini r->req.dev->sense_is_ua = false;
70849ab747fSPaolo Bonzini }
70949ab747fSPaolo Bonzini break;
7101cb27d92SPaolo Bonzini case TEST_UNIT_READY:
7111cb27d92SPaolo Bonzini break;
71249ab747fSPaolo Bonzini default:
713ded6ddc5SHannes Reinecke scsi_req_build_sense(req, SENSE_CODE(INVALID_OPCODE));
71449ab747fSPaolo Bonzini scsi_req_complete(req, CHECK_CONDITION);
71549ab747fSPaolo Bonzini return 0;
71649ab747fSPaolo Bonzini illegal_request:
71749ab747fSPaolo Bonzini scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD));
71849ab747fSPaolo Bonzini scsi_req_complete(req, CHECK_CONDITION);
71949ab747fSPaolo Bonzini return 0;
72049ab747fSPaolo Bonzini }
72149ab747fSPaolo Bonzini
72249ab747fSPaolo Bonzini if (!r->len) {
72349ab747fSPaolo Bonzini scsi_req_complete(req, GOOD);
72449ab747fSPaolo Bonzini }
72549ab747fSPaolo Bonzini return r->len;
72649ab747fSPaolo Bonzini }
72749ab747fSPaolo Bonzini
scsi_target_read_data(SCSIRequest * req)72849ab747fSPaolo Bonzini static void scsi_target_read_data(SCSIRequest *req)
72949ab747fSPaolo Bonzini {
73049ab747fSPaolo Bonzini SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
73149ab747fSPaolo Bonzini uint32_t n;
73249ab747fSPaolo Bonzini
73349ab747fSPaolo Bonzini n = r->len;
73449ab747fSPaolo Bonzini if (n > 0) {
73549ab747fSPaolo Bonzini r->len = 0;
73649ab747fSPaolo Bonzini scsi_req_data(&r->req, n);
73749ab747fSPaolo Bonzini } else {
73849ab747fSPaolo Bonzini scsi_req_complete(&r->req, GOOD);
73949ab747fSPaolo Bonzini }
74049ab747fSPaolo Bonzini }
74149ab747fSPaolo Bonzini
scsi_target_get_buf(SCSIRequest * req)74249ab747fSPaolo Bonzini static uint8_t *scsi_target_get_buf(SCSIRequest *req)
74349ab747fSPaolo Bonzini {
74449ab747fSPaolo Bonzini SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
74549ab747fSPaolo Bonzini
74649ab747fSPaolo Bonzini return r->buf;
74749ab747fSPaolo Bonzini }
74849ab747fSPaolo Bonzini
scsi_target_alloc_buf(SCSIRequest * req,size_t len)74984642435SAsias He static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len)
75084642435SAsias He {
75184642435SAsias He SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
75284642435SAsias He
75384642435SAsias He r->buf = g_malloc(len);
75484642435SAsias He r->buf_len = len;
75584642435SAsias He
75684642435SAsias He return r->buf;
75784642435SAsias He }
75884642435SAsias He
scsi_target_free_buf(SCSIRequest * req)75984642435SAsias He static void scsi_target_free_buf(SCSIRequest *req)
76084642435SAsias He {
76184642435SAsias He SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
76284642435SAsias He
76384642435SAsias He g_free(r->buf);
76484642435SAsias He }
76584642435SAsias He
76649ab747fSPaolo Bonzini static const struct SCSIReqOps reqops_target_command = {
76749ab747fSPaolo Bonzini .size = sizeof(SCSITargetReq),
76849ab747fSPaolo Bonzini .send_command = scsi_target_send_command,
76949ab747fSPaolo Bonzini .read_data = scsi_target_read_data,
77049ab747fSPaolo Bonzini .get_buf = scsi_target_get_buf,
77184642435SAsias He .free_req = scsi_target_free_buf,
77249ab747fSPaolo Bonzini };
77349ab747fSPaolo Bonzini
77449ab747fSPaolo Bonzini
scsi_req_alloc(const SCSIReqOps * reqops,SCSIDevice * d,uint32_t tag,uint32_t lun,void * hba_private)77549ab747fSPaolo Bonzini SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
77649ab747fSPaolo Bonzini uint32_t tag, uint32_t lun, void *hba_private)
77749ab747fSPaolo Bonzini {
77849ab747fSPaolo Bonzini SCSIRequest *req;
779cac3c384SPaolo Bonzini SCSIBus *bus = scsi_bus_from_device(d);
780cac3c384SPaolo Bonzini BusState *qbus = BUS(bus);
78161e68b3fSFam Zheng const int memset_off = offsetof(SCSIRequest, sense)
78261e68b3fSFam Zheng + sizeof(req->sense);
78349ab747fSPaolo Bonzini
784633dccb4SPaolo Bonzini req = g_malloc(reqops->size);
78561e68b3fSFam Zheng memset((uint8_t *)req + memset_off, 0, reqops->size - memset_off);
78649ab747fSPaolo Bonzini req->refcount = 1;
787cac3c384SPaolo Bonzini req->bus = bus;
78849ab747fSPaolo Bonzini req->dev = d;
78949ab747fSPaolo Bonzini req->tag = tag;
79049ab747fSPaolo Bonzini req->lun = lun;
79149ab747fSPaolo Bonzini req->hba_private = hba_private;
79249ab747fSPaolo Bonzini req->status = -1;
793f3126d65SHannes Reinecke req->host_status = -1;
79449ab747fSPaolo Bonzini req->ops = reqops;
795cac3c384SPaolo Bonzini object_ref(OBJECT(d));
796cac3c384SPaolo Bonzini object_ref(OBJECT(qbus->parent));
7978e0a9320SFam Zheng notifier_list_init(&req->cancel_notifiers);
7989472083eSStefano Garzarella
7999472083eSStefano Garzarella if (reqops->init_req) {
8009472083eSStefano Garzarella reqops->init_req(req);
8019472083eSStefano Garzarella }
8029472083eSStefano Garzarella
80349ab747fSPaolo Bonzini trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
80449ab747fSPaolo Bonzini return req;
80549ab747fSPaolo Bonzini }
80649ab747fSPaolo Bonzini
scsi_req_new(SCSIDevice * d,uint32_t tag,uint32_t lun,uint8_t * buf,size_t buf_len,void * hba_private)80749ab747fSPaolo Bonzini SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
808fe9d8927SJohn Millikin uint8_t *buf, size_t buf_len, void *hba_private)
80949ab747fSPaolo Bonzini {
81049ab747fSPaolo Bonzini SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
811769998a1SPaolo Bonzini const SCSIReqOps *ops;
812ff34c32cSPaolo Bonzini SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(d);
81349ab747fSPaolo Bonzini SCSIRequest *req;
814769998a1SPaolo Bonzini SCSICommand cmd = { .len = 0 };
815769998a1SPaolo Bonzini int ret;
81649ab747fSPaolo Bonzini
8176d1511ceSJohn Millikin if (buf_len == 0) {
8186d1511ceSJohn Millikin trace_scsi_req_parse_bad(d->id, lun, tag, 0);
8196d1511ceSJohn Millikin goto invalid_opcode;
8206d1511ceSJohn Millikin }
8216d1511ceSJohn Millikin
822769998a1SPaolo Bonzini if ((d->unit_attention.key == UNIT_ATTENTION ||
82349ab747fSPaolo Bonzini bus->unit_attention.key == UNIT_ATTENTION) &&
82449ab747fSPaolo Bonzini (buf[0] != INQUIRY &&
82549ab747fSPaolo Bonzini buf[0] != REPORT_LUNS &&
82649ab747fSPaolo Bonzini buf[0] != GET_CONFIGURATION &&
82749ab747fSPaolo Bonzini buf[0] != GET_EVENT_STATUS_NOTIFICATION &&
82849ab747fSPaolo Bonzini
82949ab747fSPaolo Bonzini /*
83049ab747fSPaolo Bonzini * If we already have a pending unit attention condition,
83149ab747fSPaolo Bonzini * report this one before triggering another one.
83249ab747fSPaolo Bonzini */
83349ab747fSPaolo Bonzini !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) {
834769998a1SPaolo Bonzini ops = &reqops_unit_attention;
83549ab747fSPaolo Bonzini } else if (lun != d->lun ||
83649ab747fSPaolo Bonzini buf[0] == REPORT_LUNS ||
83749ab747fSPaolo Bonzini (buf[0] == REQUEST_SENSE && d->sense_len)) {
838769998a1SPaolo Bonzini ops = &reqops_target_command;
839769998a1SPaolo Bonzini } else {
840769998a1SPaolo Bonzini ops = NULL;
841769998a1SPaolo Bonzini }
842769998a1SPaolo Bonzini
843ff34c32cSPaolo Bonzini if (ops != NULL || !sc->parse_cdb) {
844fe9d8927SJohn Millikin ret = scsi_req_parse_cdb(d, &cmd, buf, buf_len);
845ff34c32cSPaolo Bonzini } else {
846fe9d8927SJohn Millikin ret = sc->parse_cdb(d, &cmd, buf, buf_len, hba_private);
847ff34c32cSPaolo Bonzini }
848ff34c32cSPaolo Bonzini
849769998a1SPaolo Bonzini if (ret != 0) {
850769998a1SPaolo Bonzini trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]);
8516d1511ceSJohn Millikin invalid_opcode:
852769998a1SPaolo Bonzini req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private);
853769998a1SPaolo Bonzini } else {
854769998a1SPaolo Bonzini assert(cmd.len != 0);
855769998a1SPaolo Bonzini trace_scsi_req_parsed(d->id, lun, tag, buf[0],
856769998a1SPaolo Bonzini cmd.mode, cmd.xfer);
857769998a1SPaolo Bonzini if (cmd.lba != -1) {
858769998a1SPaolo Bonzini trace_scsi_req_parsed_lba(d->id, lun, tag, buf[0],
859769998a1SPaolo Bonzini cmd.lba);
860769998a1SPaolo Bonzini }
861769998a1SPaolo Bonzini
862769998a1SPaolo Bonzini if (cmd.xfer > INT32_MAX) {
863769998a1SPaolo Bonzini req = scsi_req_alloc(&reqops_invalid_field, d, tag, lun, hba_private);
864769998a1SPaolo Bonzini } else if (ops) {
865769998a1SPaolo Bonzini req = scsi_req_alloc(ops, d, tag, lun, hba_private);
86649ab747fSPaolo Bonzini } else {
86749ab747fSPaolo Bonzini req = scsi_device_alloc_req(d, tag, lun, buf, hba_private);
86849ab747fSPaolo Bonzini }
86949ab747fSPaolo Bonzini }
87049ab747fSPaolo Bonzini
87149ab747fSPaolo Bonzini req->cmd = cmd;
8725f412602SPhilippe Mathieu-Daudé req->residual = req->cmd.xfer;
87349ab747fSPaolo Bonzini
87449ab747fSPaolo Bonzini switch (buf[0]) {
87549ab747fSPaolo Bonzini case INQUIRY:
87649ab747fSPaolo Bonzini trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]);
87749ab747fSPaolo Bonzini break;
87849ab747fSPaolo Bonzini case TEST_UNIT_READY:
87949ab747fSPaolo Bonzini trace_scsi_test_unit_ready(d->id, lun, tag);
88049ab747fSPaolo Bonzini break;
88149ab747fSPaolo Bonzini case REPORT_LUNS:
88249ab747fSPaolo Bonzini trace_scsi_report_luns(d->id, lun, tag);
88349ab747fSPaolo Bonzini break;
88449ab747fSPaolo Bonzini case REQUEST_SENSE:
88549ab747fSPaolo Bonzini trace_scsi_request_sense(d->id, lun, tag);
88649ab747fSPaolo Bonzini break;
88749ab747fSPaolo Bonzini default:
88849ab747fSPaolo Bonzini break;
88949ab747fSPaolo Bonzini }
89049ab747fSPaolo Bonzini
89149ab747fSPaolo Bonzini return req;
89249ab747fSPaolo Bonzini }
89349ab747fSPaolo Bonzini
scsi_req_get_buf(SCSIRequest * req)89449ab747fSPaolo Bonzini uint8_t *scsi_req_get_buf(SCSIRequest *req)
89549ab747fSPaolo Bonzini {
89649ab747fSPaolo Bonzini return req->ops->get_buf(req);
89749ab747fSPaolo Bonzini }
89849ab747fSPaolo Bonzini
scsi_clear_reported_luns_changed(SCSIRequest * req)8992eb5599eSStefano Garzarella static void scsi_clear_reported_luns_changed(SCSIRequest *req)
90049ab747fSPaolo Bonzini {
90149ab747fSPaolo Bonzini SCSISense *ua;
9029472083eSStefano Garzarella
90349ab747fSPaolo Bonzini if (req->dev->unit_attention.key == UNIT_ATTENTION) {
90449ab747fSPaolo Bonzini ua = &req->dev->unit_attention;
905ba947dabSStefano Garzarella } else if (req->bus->unit_attention.key == UNIT_ATTENTION) {
90649ab747fSPaolo Bonzini ua = &req->bus->unit_attention;
907ba947dabSStefano Garzarella } else {
908ba947dabSStefano Garzarella return;
90949ab747fSPaolo Bonzini }
91049ab747fSPaolo Bonzini
9112eb5599eSStefano Garzarella if (ua->asc == SENSE_CODE(REPORTED_LUNS_CHANGED).asc &&
912ba947dabSStefano Garzarella ua->ascq == SENSE_CODE(REPORTED_LUNS_CHANGED).ascq) {
91349ab747fSPaolo Bonzini *ua = SENSE_CODE(NO_SENSE);
91449ab747fSPaolo Bonzini }
915ba947dabSStefano Garzarella }
91649ab747fSPaolo Bonzini
scsi_req_get_sense(SCSIRequest * req,uint8_t * buf,int len)91749ab747fSPaolo Bonzini int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
91849ab747fSPaolo Bonzini {
91949ab747fSPaolo Bonzini int ret;
92049ab747fSPaolo Bonzini
92149ab747fSPaolo Bonzini assert(len >= 14);
92249ab747fSPaolo Bonzini if (!req->sense_len) {
92349ab747fSPaolo Bonzini return 0;
92449ab747fSPaolo Bonzini }
92549ab747fSPaolo Bonzini
92637b6045cSPaolo Bonzini ret = scsi_convert_sense(req->sense, req->sense_len, buf, len, true);
92749ab747fSPaolo Bonzini
92849ab747fSPaolo Bonzini /*
92949ab747fSPaolo Bonzini * FIXME: clearing unit attention conditions upon autosense should be done
93049ab747fSPaolo Bonzini * only if the UA_INTLCK_CTRL field in the Control mode page is set to 00b
93149ab747fSPaolo Bonzini * (SAM-5, 5.14).
93249ab747fSPaolo Bonzini *
93349ab747fSPaolo Bonzini * We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and
93449ab747fSPaolo Bonzini * 10b for HBAs that do not support it (do not call scsi_req_get_sense).
93549ab747fSPaolo Bonzini * Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
93649ab747fSPaolo Bonzini */
93749ab747fSPaolo Bonzini if (req->dev->sense_is_ua) {
93849ab747fSPaolo Bonzini scsi_device_unit_attention_reported(req->dev);
93949ab747fSPaolo Bonzini req->dev->sense_len = 0;
94049ab747fSPaolo Bonzini req->dev->sense_is_ua = false;
94149ab747fSPaolo Bonzini }
94249ab747fSPaolo Bonzini return ret;
94349ab747fSPaolo Bonzini }
94449ab747fSPaolo Bonzini
scsi_device_get_sense(SCSIDevice * dev,uint8_t * buf,int len,bool fixed)94549ab747fSPaolo Bonzini int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed)
94649ab747fSPaolo Bonzini {
94737b6045cSPaolo Bonzini return scsi_convert_sense(dev->sense, dev->sense_len, buf, len, fixed);
94849ab747fSPaolo Bonzini }
94949ab747fSPaolo Bonzini
scsi_req_build_sense(SCSIRequest * req,SCSISense sense)95049ab747fSPaolo Bonzini void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
95149ab747fSPaolo Bonzini {
95249ab747fSPaolo Bonzini trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag,
95349ab747fSPaolo Bonzini sense.key, sense.asc, sense.ascq);
954a3760467SPaolo Bonzini req->sense_len = scsi_build_sense(req->sense, sense);
95549ab747fSPaolo Bonzini }
95649ab747fSPaolo Bonzini
scsi_req_enqueue_internal(SCSIRequest * req)95749ab747fSPaolo Bonzini static void scsi_req_enqueue_internal(SCSIRequest *req)
95849ab747fSPaolo Bonzini {
95949ab747fSPaolo Bonzini assert(!req->enqueued);
96049ab747fSPaolo Bonzini scsi_req_ref(req);
96149ab747fSPaolo Bonzini if (req->bus->info->get_sg_list) {
96249ab747fSPaolo Bonzini req->sg = req->bus->info->get_sg_list(req);
96349ab747fSPaolo Bonzini } else {
96449ab747fSPaolo Bonzini req->sg = NULL;
96549ab747fSPaolo Bonzini }
96649ab747fSPaolo Bonzini req->enqueued = true;
96749ab747fSPaolo Bonzini QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);
96849ab747fSPaolo Bonzini }
96949ab747fSPaolo Bonzini
scsi_req_enqueue(SCSIRequest * req)97049ab747fSPaolo Bonzini int32_t scsi_req_enqueue(SCSIRequest *req)
97149ab747fSPaolo Bonzini {
97249ab747fSPaolo Bonzini int32_t rc;
97349ab747fSPaolo Bonzini
97449ab747fSPaolo Bonzini assert(!req->retry);
97549ab747fSPaolo Bonzini scsi_req_enqueue_internal(req);
97649ab747fSPaolo Bonzini scsi_req_ref(req);
97749ab747fSPaolo Bonzini rc = req->ops->send_command(req, req->cmd.buf);
97849ab747fSPaolo Bonzini scsi_req_unref(req);
97949ab747fSPaolo Bonzini return rc;
98049ab747fSPaolo Bonzini }
98149ab747fSPaolo Bonzini
scsi_req_dequeue(SCSIRequest * req)98249ab747fSPaolo Bonzini static void scsi_req_dequeue(SCSIRequest *req)
98349ab747fSPaolo Bonzini {
98449ab747fSPaolo Bonzini trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag);
98549ab747fSPaolo Bonzini req->retry = false;
98649ab747fSPaolo Bonzini if (req->enqueued) {
98749ab747fSPaolo Bonzini QTAILQ_REMOVE(&req->dev->requests, req, next);
98849ab747fSPaolo Bonzini req->enqueued = false;
98949ab747fSPaolo Bonzini scsi_req_unref(req);
99049ab747fSPaolo Bonzini }
99149ab747fSPaolo Bonzini }
99249ab747fSPaolo Bonzini
scsi_get_performance_length(int num_desc,int type,int data_type)99349ab747fSPaolo Bonzini static int scsi_get_performance_length(int num_desc, int type, int data_type)
99449ab747fSPaolo Bonzini {
99549ab747fSPaolo Bonzini /* MMC-6, paragraph 6.7. */
99649ab747fSPaolo Bonzini switch (type) {
99749ab747fSPaolo Bonzini case 0:
99849ab747fSPaolo Bonzini if ((data_type & 3) == 0) {
99949ab747fSPaolo Bonzini /* Each descriptor is as in Table 295 - Nominal performance. */
100049ab747fSPaolo Bonzini return 16 * num_desc + 8;
100149ab747fSPaolo Bonzini } else {
100249ab747fSPaolo Bonzini /* Each descriptor is as in Table 296 - Exceptions. */
100349ab747fSPaolo Bonzini return 6 * num_desc + 8;
100449ab747fSPaolo Bonzini }
100549ab747fSPaolo Bonzini case 1:
100649ab747fSPaolo Bonzini case 4:
100749ab747fSPaolo Bonzini case 5:
100849ab747fSPaolo Bonzini return 8 * num_desc + 8;
100949ab747fSPaolo Bonzini case 2:
101049ab747fSPaolo Bonzini return 2048 * num_desc + 8;
101149ab747fSPaolo Bonzini case 3:
101249ab747fSPaolo Bonzini return 16 * num_desc + 8;
101349ab747fSPaolo Bonzini default:
101449ab747fSPaolo Bonzini return 8;
101549ab747fSPaolo Bonzini }
101649ab747fSPaolo Bonzini }
101749ab747fSPaolo Bonzini
ata_passthrough_xfer_unit(SCSIDevice * dev,uint8_t * buf)101849ab747fSPaolo Bonzini static int ata_passthrough_xfer_unit(SCSIDevice *dev, uint8_t *buf)
101949ab747fSPaolo Bonzini {
102049ab747fSPaolo Bonzini int byte_block = (buf[2] >> 2) & 0x1;
102149ab747fSPaolo Bonzini int type = (buf[2] >> 4) & 0x1;
102249ab747fSPaolo Bonzini int xfer_unit;
102349ab747fSPaolo Bonzini
102449ab747fSPaolo Bonzini if (byte_block) {
102549ab747fSPaolo Bonzini if (type) {
102649ab747fSPaolo Bonzini xfer_unit = dev->blocksize;
102749ab747fSPaolo Bonzini } else {
102849ab747fSPaolo Bonzini xfer_unit = 512;
102949ab747fSPaolo Bonzini }
103049ab747fSPaolo Bonzini } else {
103149ab747fSPaolo Bonzini xfer_unit = 1;
103249ab747fSPaolo Bonzini }
103349ab747fSPaolo Bonzini
103449ab747fSPaolo Bonzini return xfer_unit;
103549ab747fSPaolo Bonzini }
103649ab747fSPaolo Bonzini
ata_passthrough_12_xfer(SCSIDevice * dev,uint8_t * buf)10371894df02SHannes Reinecke static int ata_passthrough_12_xfer(SCSIDevice *dev, uint8_t *buf)
103849ab747fSPaolo Bonzini {
103949ab747fSPaolo Bonzini int length = buf[2] & 0x3;
104049ab747fSPaolo Bonzini int xfer;
104149ab747fSPaolo Bonzini int unit = ata_passthrough_xfer_unit(dev, buf);
104249ab747fSPaolo Bonzini
104349ab747fSPaolo Bonzini switch (length) {
104449ab747fSPaolo Bonzini case 0:
104549ab747fSPaolo Bonzini case 3: /* USB-specific. */
104649ab747fSPaolo Bonzini default:
104749ab747fSPaolo Bonzini xfer = 0;
104849ab747fSPaolo Bonzini break;
104949ab747fSPaolo Bonzini case 1:
105049ab747fSPaolo Bonzini xfer = buf[3];
105149ab747fSPaolo Bonzini break;
105249ab747fSPaolo Bonzini case 2:
105349ab747fSPaolo Bonzini xfer = buf[4];
105449ab747fSPaolo Bonzini break;
105549ab747fSPaolo Bonzini }
105649ab747fSPaolo Bonzini
105749ab747fSPaolo Bonzini return xfer * unit;
105849ab747fSPaolo Bonzini }
105949ab747fSPaolo Bonzini
ata_passthrough_16_xfer(SCSIDevice * dev,uint8_t * buf)10601894df02SHannes Reinecke static int ata_passthrough_16_xfer(SCSIDevice *dev, uint8_t *buf)
106149ab747fSPaolo Bonzini {
106249ab747fSPaolo Bonzini int extend = buf[1] & 0x1;
106349ab747fSPaolo Bonzini int length = buf[2] & 0x3;
106449ab747fSPaolo Bonzini int xfer;
106549ab747fSPaolo Bonzini int unit = ata_passthrough_xfer_unit(dev, buf);
106649ab747fSPaolo Bonzini
106749ab747fSPaolo Bonzini switch (length) {
106849ab747fSPaolo Bonzini case 0:
106949ab747fSPaolo Bonzini case 3: /* USB-specific. */
107049ab747fSPaolo Bonzini default:
107149ab747fSPaolo Bonzini xfer = 0;
107249ab747fSPaolo Bonzini break;
107349ab747fSPaolo Bonzini case 1:
107449ab747fSPaolo Bonzini xfer = buf[4];
107549ab747fSPaolo Bonzini xfer |= (extend ? buf[3] << 8 : 0);
107649ab747fSPaolo Bonzini break;
107749ab747fSPaolo Bonzini case 2:
107849ab747fSPaolo Bonzini xfer = buf[6];
107949ab747fSPaolo Bonzini xfer |= (extend ? buf[5] << 8 : 0);
108049ab747fSPaolo Bonzini break;
108149ab747fSPaolo Bonzini }
108249ab747fSPaolo Bonzini
108349ab747fSPaolo Bonzini return xfer * unit;
108449ab747fSPaolo Bonzini }
108549ab747fSPaolo Bonzini
scsi_req_xfer(SCSICommand * cmd,SCSIDevice * dev,uint8_t * buf)10861894df02SHannes Reinecke static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
108749ab747fSPaolo Bonzini {
10881894df02SHannes Reinecke cmd->xfer = scsi_cdb_xfer(buf);
108949ab747fSPaolo Bonzini switch (buf[0]) {
109049ab747fSPaolo Bonzini case TEST_UNIT_READY:
109149ab747fSPaolo Bonzini case REWIND:
109249ab747fSPaolo Bonzini case START_STOP:
109349ab747fSPaolo Bonzini case SET_CAPACITY:
109449ab747fSPaolo Bonzini case WRITE_FILEMARKS:
109549ab747fSPaolo Bonzini case WRITE_FILEMARKS_16:
109649ab747fSPaolo Bonzini case SPACE:
109749ab747fSPaolo Bonzini case RESERVE:
109849ab747fSPaolo Bonzini case RELEASE:
109949ab747fSPaolo Bonzini case ERASE:
110049ab747fSPaolo Bonzini case ALLOW_MEDIUM_REMOVAL:
110149ab747fSPaolo Bonzini case SEEK_10:
110249ab747fSPaolo Bonzini case SYNCHRONIZE_CACHE:
110349ab747fSPaolo Bonzini case SYNCHRONIZE_CACHE_16:
110449ab747fSPaolo Bonzini case LOCATE_16:
110549ab747fSPaolo Bonzini case LOCK_UNLOCK_CACHE:
110649ab747fSPaolo Bonzini case SET_CD_SPEED:
110749ab747fSPaolo Bonzini case SET_LIMITS:
110849ab747fSPaolo Bonzini case WRITE_LONG_10:
110949ab747fSPaolo Bonzini case UPDATE_BLOCK:
111049ab747fSPaolo Bonzini case RESERVE_TRACK:
111149ab747fSPaolo Bonzini case SET_READ_AHEAD:
111249ab747fSPaolo Bonzini case PRE_FETCH:
111349ab747fSPaolo Bonzini case PRE_FETCH_16:
111449ab747fSPaolo Bonzini case ALLOW_OVERWRITE:
111549ab747fSPaolo Bonzini cmd->xfer = 0;
111649ab747fSPaolo Bonzini break;
1117d12ad44cSPaolo Bonzini case VERIFY_10:
1118d12ad44cSPaolo Bonzini case VERIFY_12:
1119d12ad44cSPaolo Bonzini case VERIFY_16:
1120d12ad44cSPaolo Bonzini if ((buf[1] & 2) == 0) {
1121d12ad44cSPaolo Bonzini cmd->xfer = 0;
11227ef8cf9aSMarkus Armbruster } else if ((buf[1] & 4) != 0) {
1123d12ad44cSPaolo Bonzini cmd->xfer = 1;
1124d12ad44cSPaolo Bonzini }
1125d12ad44cSPaolo Bonzini cmd->xfer *= dev->blocksize;
1126d12ad44cSPaolo Bonzini break;
112749ab747fSPaolo Bonzini case MODE_SENSE:
112849ab747fSPaolo Bonzini break;
112949ab747fSPaolo Bonzini case WRITE_SAME_10:
113049ab747fSPaolo Bonzini case WRITE_SAME_16:
11314397a018SPaolo Bonzini cmd->xfer = buf[1] & 1 ? 0 : dev->blocksize;
113249ab747fSPaolo Bonzini break;
113349ab747fSPaolo Bonzini case READ_CAPACITY_10:
113449ab747fSPaolo Bonzini cmd->xfer = 8;
113549ab747fSPaolo Bonzini break;
113649ab747fSPaolo Bonzini case READ_BLOCK_LIMITS:
113749ab747fSPaolo Bonzini cmd->xfer = 6;
113849ab747fSPaolo Bonzini break;
113949ab747fSPaolo Bonzini case SEND_VOLUME_TAG:
114049ab747fSPaolo Bonzini /* GPCMD_SET_STREAMING from multimedia commands. */
114149ab747fSPaolo Bonzini if (dev->type == TYPE_ROM) {
114249ab747fSPaolo Bonzini cmd->xfer = buf[10] | (buf[9] << 8);
114349ab747fSPaolo Bonzini } else {
114449ab747fSPaolo Bonzini cmd->xfer = buf[9] | (buf[8] << 8);
114549ab747fSPaolo Bonzini }
114649ab747fSPaolo Bonzini break;
114749ab747fSPaolo Bonzini case WRITE_6:
114849ab747fSPaolo Bonzini /* length 0 means 256 blocks */
114949ab747fSPaolo Bonzini if (cmd->xfer == 0) {
115049ab747fSPaolo Bonzini cmd->xfer = 256;
115149ab747fSPaolo Bonzini }
1152c4ce4c4bSMarkus Armbruster /* fall through */
115349ab747fSPaolo Bonzini case WRITE_10:
115449ab747fSPaolo Bonzini case WRITE_VERIFY_10:
115549ab747fSPaolo Bonzini case WRITE_12:
115649ab747fSPaolo Bonzini case WRITE_VERIFY_12:
115749ab747fSPaolo Bonzini case WRITE_16:
115849ab747fSPaolo Bonzini case WRITE_VERIFY_16:
115949ab747fSPaolo Bonzini cmd->xfer *= dev->blocksize;
116049ab747fSPaolo Bonzini break;
116149ab747fSPaolo Bonzini case READ_6:
116249ab747fSPaolo Bonzini case READ_REVERSE:
116349ab747fSPaolo Bonzini /* length 0 means 256 blocks */
116449ab747fSPaolo Bonzini if (cmd->xfer == 0) {
116549ab747fSPaolo Bonzini cmd->xfer = 256;
116649ab747fSPaolo Bonzini }
1167c4ce4c4bSMarkus Armbruster /* fall through */
116849ab747fSPaolo Bonzini case READ_10:
116949ab747fSPaolo Bonzini case READ_12:
117049ab747fSPaolo Bonzini case READ_16:
117149ab747fSPaolo Bonzini cmd->xfer *= dev->blocksize;
117249ab747fSPaolo Bonzini break;
117349ab747fSPaolo Bonzini case FORMAT_UNIT:
117449ab747fSPaolo Bonzini /* MMC mandates the parameter list to be 12-bytes long. Parameters
117549ab747fSPaolo Bonzini * for block devices are restricted to the header right now. */
117649ab747fSPaolo Bonzini if (dev->type == TYPE_ROM && (buf[1] & 16)) {
117749ab747fSPaolo Bonzini cmd->xfer = 12;
117849ab747fSPaolo Bonzini } else {
117949ab747fSPaolo Bonzini cmd->xfer = (buf[1] & 16) == 0 ? 0 : (buf[1] & 32 ? 8 : 4);
118049ab747fSPaolo Bonzini }
118149ab747fSPaolo Bonzini break;
118249ab747fSPaolo Bonzini case INQUIRY:
118349ab747fSPaolo Bonzini case RECEIVE_DIAGNOSTIC:
118449ab747fSPaolo Bonzini case SEND_DIAGNOSTIC:
118549ab747fSPaolo Bonzini cmd->xfer = buf[4] | (buf[3] << 8);
118649ab747fSPaolo Bonzini break;
118749ab747fSPaolo Bonzini case READ_CD:
118849ab747fSPaolo Bonzini case READ_BUFFER:
118949ab747fSPaolo Bonzini case WRITE_BUFFER:
119049ab747fSPaolo Bonzini case SEND_CUE_SHEET:
119149ab747fSPaolo Bonzini cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16);
119249ab747fSPaolo Bonzini break;
119349ab747fSPaolo Bonzini case PERSISTENT_RESERVE_OUT:
119449ab747fSPaolo Bonzini cmd->xfer = ldl_be_p(&buf[5]) & 0xffffffffULL;
119549ab747fSPaolo Bonzini break;
119649ab747fSPaolo Bonzini case ERASE_12:
119749ab747fSPaolo Bonzini if (dev->type == TYPE_ROM) {
119849ab747fSPaolo Bonzini /* MMC command GET PERFORMANCE. */
119949ab747fSPaolo Bonzini cmd->xfer = scsi_get_performance_length(buf[9] | (buf[8] << 8),
120049ab747fSPaolo Bonzini buf[10], buf[1] & 0x1f);
120149ab747fSPaolo Bonzini }
120249ab747fSPaolo Bonzini break;
120349ab747fSPaolo Bonzini case MECHANISM_STATUS:
120449ab747fSPaolo Bonzini case READ_DVD_STRUCTURE:
120549ab747fSPaolo Bonzini case SEND_DVD_STRUCTURE:
120649ab747fSPaolo Bonzini case MAINTENANCE_OUT:
120749ab747fSPaolo Bonzini case MAINTENANCE_IN:
120849ab747fSPaolo Bonzini if (dev->type == TYPE_ROM) {
120949ab747fSPaolo Bonzini /* GPCMD_REPORT_KEY and GPCMD_SEND_KEY from multi media commands */
121049ab747fSPaolo Bonzini cmd->xfer = buf[9] | (buf[8] << 8);
121149ab747fSPaolo Bonzini }
121249ab747fSPaolo Bonzini break;
121349ab747fSPaolo Bonzini case ATA_PASSTHROUGH_12:
121449ab747fSPaolo Bonzini if (dev->type == TYPE_ROM) {
121549ab747fSPaolo Bonzini /* BLANK command of MMC */
121649ab747fSPaolo Bonzini cmd->xfer = 0;
121749ab747fSPaolo Bonzini } else {
12181894df02SHannes Reinecke cmd->xfer = ata_passthrough_12_xfer(dev, buf);
121949ab747fSPaolo Bonzini }
122049ab747fSPaolo Bonzini break;
122149ab747fSPaolo Bonzini case ATA_PASSTHROUGH_16:
12221894df02SHannes Reinecke cmd->xfer = ata_passthrough_16_xfer(dev, buf);
122349ab747fSPaolo Bonzini break;
122449ab747fSPaolo Bonzini }
122549ab747fSPaolo Bonzini return 0;
122649ab747fSPaolo Bonzini }
122749ab747fSPaolo Bonzini
scsi_req_stream_xfer(SCSICommand * cmd,SCSIDevice * dev,uint8_t * buf)12281894df02SHannes Reinecke static int scsi_req_stream_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
122949ab747fSPaolo Bonzini {
123049ab747fSPaolo Bonzini switch (buf[0]) {
123149ab747fSPaolo Bonzini /* stream commands */
123249ab747fSPaolo Bonzini case ERASE_12:
123349ab747fSPaolo Bonzini case ERASE_16:
123449ab747fSPaolo Bonzini cmd->xfer = 0;
123549ab747fSPaolo Bonzini break;
123649ab747fSPaolo Bonzini case READ_6:
123749ab747fSPaolo Bonzini case READ_REVERSE:
123849ab747fSPaolo Bonzini case RECOVER_BUFFERED_DATA:
123949ab747fSPaolo Bonzini case WRITE_6:
124049ab747fSPaolo Bonzini cmd->xfer = buf[4] | (buf[3] << 8) | (buf[2] << 16);
124149ab747fSPaolo Bonzini if (buf[1] & 0x01) { /* fixed */
124249ab747fSPaolo Bonzini cmd->xfer *= dev->blocksize;
124349ab747fSPaolo Bonzini }
124449ab747fSPaolo Bonzini break;
124549ab747fSPaolo Bonzini case READ_16:
124649ab747fSPaolo Bonzini case READ_REVERSE_16:
124749ab747fSPaolo Bonzini case VERIFY_16:
124849ab747fSPaolo Bonzini case WRITE_16:
124949ab747fSPaolo Bonzini cmd->xfer = buf[14] | (buf[13] << 8) | (buf[12] << 16);
125049ab747fSPaolo Bonzini if (buf[1] & 0x01) { /* fixed */
125149ab747fSPaolo Bonzini cmd->xfer *= dev->blocksize;
125249ab747fSPaolo Bonzini }
125349ab747fSPaolo Bonzini break;
125449ab747fSPaolo Bonzini case REWIND:
125549ab747fSPaolo Bonzini case LOAD_UNLOAD:
125649ab747fSPaolo Bonzini cmd->xfer = 0;
125749ab747fSPaolo Bonzini break;
125849ab747fSPaolo Bonzini case SPACE_16:
125949ab747fSPaolo Bonzini cmd->xfer = buf[13] | (buf[12] << 8);
126049ab747fSPaolo Bonzini break;
126149ab747fSPaolo Bonzini case READ_POSITION:
126249ab747fSPaolo Bonzini switch (buf[1] & 0x1f) /* operation code */ {
126349ab747fSPaolo Bonzini case SHORT_FORM_BLOCK_ID:
126449ab747fSPaolo Bonzini case SHORT_FORM_VENDOR_SPECIFIC:
126549ab747fSPaolo Bonzini cmd->xfer = 20;
126649ab747fSPaolo Bonzini break;
126749ab747fSPaolo Bonzini case LONG_FORM:
126849ab747fSPaolo Bonzini cmd->xfer = 32;
126949ab747fSPaolo Bonzini break;
127049ab747fSPaolo Bonzini case EXTENDED_FORM:
127149ab747fSPaolo Bonzini cmd->xfer = buf[8] | (buf[7] << 8);
127249ab747fSPaolo Bonzini break;
127349ab747fSPaolo Bonzini default:
127449ab747fSPaolo Bonzini return -1;
127549ab747fSPaolo Bonzini }
127649ab747fSPaolo Bonzini
127749ab747fSPaolo Bonzini break;
127849ab747fSPaolo Bonzini case FORMAT_UNIT:
127949ab747fSPaolo Bonzini cmd->xfer = buf[4] | (buf[3] << 8);
128049ab747fSPaolo Bonzini break;
128149ab747fSPaolo Bonzini /* generic commands */
128249ab747fSPaolo Bonzini default:
12831894df02SHannes Reinecke return scsi_req_xfer(cmd, dev, buf);
128449ab747fSPaolo Bonzini }
128549ab747fSPaolo Bonzini return 0;
128649ab747fSPaolo Bonzini }
128749ab747fSPaolo Bonzini
scsi_req_medium_changer_xfer(SCSICommand * cmd,SCSIDevice * dev,uint8_t * buf)12881894df02SHannes Reinecke static int scsi_req_medium_changer_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
128949ab747fSPaolo Bonzini {
129049ab747fSPaolo Bonzini switch (buf[0]) {
129149ab747fSPaolo Bonzini /* medium changer commands */
129249ab747fSPaolo Bonzini case EXCHANGE_MEDIUM:
129349ab747fSPaolo Bonzini case INITIALIZE_ELEMENT_STATUS:
129449ab747fSPaolo Bonzini case INITIALIZE_ELEMENT_STATUS_WITH_RANGE:
129549ab747fSPaolo Bonzini case MOVE_MEDIUM:
129649ab747fSPaolo Bonzini case POSITION_TO_ELEMENT:
129749ab747fSPaolo Bonzini cmd->xfer = 0;
129849ab747fSPaolo Bonzini break;
129949ab747fSPaolo Bonzini case READ_ELEMENT_STATUS:
130049ab747fSPaolo Bonzini cmd->xfer = buf[9] | (buf[8] << 8) | (buf[7] << 16);
130149ab747fSPaolo Bonzini break;
130249ab747fSPaolo Bonzini
130349ab747fSPaolo Bonzini /* generic commands */
130449ab747fSPaolo Bonzini default:
13051894df02SHannes Reinecke return scsi_req_xfer(cmd, dev, buf);
130649ab747fSPaolo Bonzini }
130749ab747fSPaolo Bonzini return 0;
130849ab747fSPaolo Bonzini }
130949ab747fSPaolo Bonzini
scsi_req_scanner_length(SCSICommand * cmd,SCSIDevice * dev,uint8_t * buf)1310297b044aSJarkko Lavinen static int scsi_req_scanner_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
1311297b044aSJarkko Lavinen {
1312297b044aSJarkko Lavinen switch (buf[0]) {
1313297b044aSJarkko Lavinen /* Scanner commands */
1314297b044aSJarkko Lavinen case OBJECT_POSITION:
1315297b044aSJarkko Lavinen cmd->xfer = 0;
1316297b044aSJarkko Lavinen break;
1317297b044aSJarkko Lavinen case SCAN:
1318297b044aSJarkko Lavinen cmd->xfer = buf[4];
1319297b044aSJarkko Lavinen break;
1320297b044aSJarkko Lavinen case READ_10:
1321297b044aSJarkko Lavinen case SEND:
1322297b044aSJarkko Lavinen case GET_WINDOW:
1323297b044aSJarkko Lavinen case SET_WINDOW:
1324297b044aSJarkko Lavinen cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16);
1325297b044aSJarkko Lavinen break;
1326297b044aSJarkko Lavinen default:
1327297b044aSJarkko Lavinen /* GET_DATA_BUFFER_STATUS xfer handled by scsi_req_xfer */
1328297b044aSJarkko Lavinen return scsi_req_xfer(cmd, dev, buf);
1329297b044aSJarkko Lavinen }
1330297b044aSJarkko Lavinen
1331297b044aSJarkko Lavinen return 0;
1332297b044aSJarkko Lavinen }
133349ab747fSPaolo Bonzini
scsi_cmd_xfer_mode(SCSICommand * cmd)133449ab747fSPaolo Bonzini static void scsi_cmd_xfer_mode(SCSICommand *cmd)
133549ab747fSPaolo Bonzini {
133649ab747fSPaolo Bonzini if (!cmd->xfer) {
133749ab747fSPaolo Bonzini cmd->mode = SCSI_XFER_NONE;
133849ab747fSPaolo Bonzini return;
133949ab747fSPaolo Bonzini }
134049ab747fSPaolo Bonzini switch (cmd->buf[0]) {
134149ab747fSPaolo Bonzini case WRITE_6:
134249ab747fSPaolo Bonzini case WRITE_10:
134349ab747fSPaolo Bonzini case WRITE_VERIFY_10:
134449ab747fSPaolo Bonzini case WRITE_12:
134549ab747fSPaolo Bonzini case WRITE_VERIFY_12:
134649ab747fSPaolo Bonzini case WRITE_16:
134749ab747fSPaolo Bonzini case WRITE_VERIFY_16:
1348d12ad44cSPaolo Bonzini case VERIFY_10:
1349d12ad44cSPaolo Bonzini case VERIFY_12:
1350d12ad44cSPaolo Bonzini case VERIFY_16:
135149ab747fSPaolo Bonzini case COPY:
135249ab747fSPaolo Bonzini case COPY_VERIFY:
135349ab747fSPaolo Bonzini case COMPARE:
135449ab747fSPaolo Bonzini case CHANGE_DEFINITION:
135549ab747fSPaolo Bonzini case LOG_SELECT:
135649ab747fSPaolo Bonzini case MODE_SELECT:
135749ab747fSPaolo Bonzini case MODE_SELECT_10:
135849ab747fSPaolo Bonzini case SEND_DIAGNOSTIC:
135949ab747fSPaolo Bonzini case WRITE_BUFFER:
136049ab747fSPaolo Bonzini case FORMAT_UNIT:
136149ab747fSPaolo Bonzini case REASSIGN_BLOCKS:
136249ab747fSPaolo Bonzini case SEARCH_EQUAL:
136349ab747fSPaolo Bonzini case SEARCH_HIGH:
136449ab747fSPaolo Bonzini case SEARCH_LOW:
136549ab747fSPaolo Bonzini case UPDATE_BLOCK:
136649ab747fSPaolo Bonzini case WRITE_LONG_10:
136749ab747fSPaolo Bonzini case WRITE_SAME_10:
136849ab747fSPaolo Bonzini case WRITE_SAME_16:
136949ab747fSPaolo Bonzini case UNMAP:
137049ab747fSPaolo Bonzini case SEARCH_HIGH_12:
137149ab747fSPaolo Bonzini case SEARCH_EQUAL_12:
137249ab747fSPaolo Bonzini case SEARCH_LOW_12:
137349ab747fSPaolo Bonzini case MEDIUM_SCAN:
137449ab747fSPaolo Bonzini case SEND_VOLUME_TAG:
137549ab747fSPaolo Bonzini case SEND_CUE_SHEET:
137649ab747fSPaolo Bonzini case SEND_DVD_STRUCTURE:
137749ab747fSPaolo Bonzini case PERSISTENT_RESERVE_OUT:
137849ab747fSPaolo Bonzini case MAINTENANCE_OUT:
1379297b044aSJarkko Lavinen case SET_WINDOW:
1380297b044aSJarkko Lavinen case SCAN:
1381297b044aSJarkko Lavinen /* SCAN conflicts with START_STOP. START_STOP has cmd->xfer set to 0 for
1382297b044aSJarkko Lavinen * non-scanner devices, so we only get here for SCAN and not for START_STOP.
1383297b044aSJarkko Lavinen */
138449ab747fSPaolo Bonzini cmd->mode = SCSI_XFER_TO_DEV;
138549ab747fSPaolo Bonzini break;
138649ab747fSPaolo Bonzini case ATA_PASSTHROUGH_12:
138749ab747fSPaolo Bonzini case ATA_PASSTHROUGH_16:
138849ab747fSPaolo Bonzini /* T_DIR */
138949ab747fSPaolo Bonzini cmd->mode = (cmd->buf[2] & 0x8) ?
139049ab747fSPaolo Bonzini SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV;
139149ab747fSPaolo Bonzini break;
139249ab747fSPaolo Bonzini default:
139349ab747fSPaolo Bonzini cmd->mode = SCSI_XFER_FROM_DEV;
139449ab747fSPaolo Bonzini break;
139549ab747fSPaolo Bonzini }
139649ab747fSPaolo Bonzini }
139749ab747fSPaolo Bonzini
scsi_req_parse_cdb(SCSIDevice * dev,SCSICommand * cmd,uint8_t * buf,size_t buf_len)1398fe9d8927SJohn Millikin int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
1399fe9d8927SJohn Millikin size_t buf_len)
140049ab747fSPaolo Bonzini {
140149ab747fSPaolo Bonzini int rc;
1402c170aad8SPaolo Bonzini int len;
140349ab747fSPaolo Bonzini
1404769998a1SPaolo Bonzini cmd->lba = -1;
1405c170aad8SPaolo Bonzini len = scsi_cdb_length(buf);
14066d1511ceSJohn Millikin if (len < 0 || len > buf_len) {
1407c170aad8SPaolo Bonzini return -1;
1408c170aad8SPaolo Bonzini }
140949ab747fSPaolo Bonzini
1410c170aad8SPaolo Bonzini cmd->len = len;
141149ab747fSPaolo Bonzini switch (dev->type) {
141249ab747fSPaolo Bonzini case TYPE_TAPE:
14131894df02SHannes Reinecke rc = scsi_req_stream_xfer(cmd, dev, buf);
141449ab747fSPaolo Bonzini break;
141549ab747fSPaolo Bonzini case TYPE_MEDIUM_CHANGER:
14161894df02SHannes Reinecke rc = scsi_req_medium_changer_xfer(cmd, dev, buf);
141749ab747fSPaolo Bonzini break;
1418297b044aSJarkko Lavinen case TYPE_SCANNER:
1419297b044aSJarkko Lavinen rc = scsi_req_scanner_length(cmd, dev, buf);
1420297b044aSJarkko Lavinen break;
142149ab747fSPaolo Bonzini default:
14221894df02SHannes Reinecke rc = scsi_req_xfer(cmd, dev, buf);
142349ab747fSPaolo Bonzini break;
142449ab747fSPaolo Bonzini }
142549ab747fSPaolo Bonzini
142649ab747fSPaolo Bonzini if (rc != 0)
142749ab747fSPaolo Bonzini return rc;
142849ab747fSPaolo Bonzini
142949ab747fSPaolo Bonzini memcpy(cmd->buf, buf, cmd->len);
143049ab747fSPaolo Bonzini scsi_cmd_xfer_mode(cmd);
143149ab747fSPaolo Bonzini cmd->lba = scsi_cmd_lba(cmd);
143249ab747fSPaolo Bonzini return 0;
143349ab747fSPaolo Bonzini }
143449ab747fSPaolo Bonzini
scsi_device_report_change(SCSIDevice * dev,SCSISense sense)143549ab747fSPaolo Bonzini void scsi_device_report_change(SCSIDevice *dev, SCSISense sense)
143649ab747fSPaolo Bonzini {
143749ab747fSPaolo Bonzini SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
143849ab747fSPaolo Bonzini
143949ab747fSPaolo Bonzini scsi_device_set_ua(dev, sense);
144049ab747fSPaolo Bonzini if (bus->info->change) {
144149ab747fSPaolo Bonzini bus->info->change(bus, dev, sense);
144249ab747fSPaolo Bonzini }
144349ab747fSPaolo Bonzini }
144449ab747fSPaolo Bonzini
scsi_req_ref(SCSIRequest * req)144549ab747fSPaolo Bonzini SCSIRequest *scsi_req_ref(SCSIRequest *req)
144649ab747fSPaolo Bonzini {
144749ab747fSPaolo Bonzini assert(req->refcount > 0);
144849ab747fSPaolo Bonzini req->refcount++;
144949ab747fSPaolo Bonzini return req;
145049ab747fSPaolo Bonzini }
145149ab747fSPaolo Bonzini
scsi_req_unref(SCSIRequest * req)145249ab747fSPaolo Bonzini void scsi_req_unref(SCSIRequest *req)
145349ab747fSPaolo Bonzini {
145449ab747fSPaolo Bonzini assert(req->refcount > 0);
145549ab747fSPaolo Bonzini if (--req->refcount == 0) {
1456cac3c384SPaolo Bonzini BusState *qbus = req->dev->qdev.parent_bus;
1457cac3c384SPaolo Bonzini SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, qbus);
1458cac3c384SPaolo Bonzini
145949ab747fSPaolo Bonzini if (bus->info->free_request && req->hba_private) {
146049ab747fSPaolo Bonzini bus->info->free_request(bus, req->hba_private);
146149ab747fSPaolo Bonzini }
146249ab747fSPaolo Bonzini if (req->ops->free_req) {
146349ab747fSPaolo Bonzini req->ops->free_req(req);
146449ab747fSPaolo Bonzini }
1465cac3c384SPaolo Bonzini object_unref(OBJECT(req->dev));
1466cac3c384SPaolo Bonzini object_unref(OBJECT(qbus->parent));
1467633dccb4SPaolo Bonzini g_free(req);
146849ab747fSPaolo Bonzini }
146949ab747fSPaolo Bonzini }
147049ab747fSPaolo Bonzini
147149ab747fSPaolo Bonzini /* Tell the device that we finished processing this chunk of I/O. It
147249ab747fSPaolo Bonzini will start the next chunk or complete the command. */
scsi_req_continue(SCSIRequest * req)147349ab747fSPaolo Bonzini void scsi_req_continue(SCSIRequest *req)
147449ab747fSPaolo Bonzini {
147549ab747fSPaolo Bonzini if (req->io_canceled) {
147649ab747fSPaolo Bonzini trace_scsi_req_continue_canceled(req->dev->id, req->lun, req->tag);
147749ab747fSPaolo Bonzini return;
147849ab747fSPaolo Bonzini }
147949ab747fSPaolo Bonzini trace_scsi_req_continue(req->dev->id, req->lun, req->tag);
148049ab747fSPaolo Bonzini if (req->cmd.mode == SCSI_XFER_TO_DEV) {
148149ab747fSPaolo Bonzini req->ops->write_data(req);
148249ab747fSPaolo Bonzini } else {
148349ab747fSPaolo Bonzini req->ops->read_data(req);
148449ab747fSPaolo Bonzini }
148549ab747fSPaolo Bonzini }
148649ab747fSPaolo Bonzini
148749ab747fSPaolo Bonzini /* Called by the devices when data is ready for the HBA. The HBA should
148849ab747fSPaolo Bonzini start a DMA operation to read or fill the device's data buffer.
148949ab747fSPaolo Bonzini Once it completes, calling scsi_req_continue will restart I/O. */
scsi_req_data(SCSIRequest * req,int len)149049ab747fSPaolo Bonzini void scsi_req_data(SCSIRequest *req, int len)
149149ab747fSPaolo Bonzini {
149249ab747fSPaolo Bonzini uint8_t *buf;
149349ab747fSPaolo Bonzini if (req->io_canceled) {
149449ab747fSPaolo Bonzini trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len);
149549ab747fSPaolo Bonzini return;
149649ab747fSPaolo Bonzini }
149749ab747fSPaolo Bonzini trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
149849ab747fSPaolo Bonzini assert(req->cmd.mode != SCSI_XFER_NONE);
149949ab747fSPaolo Bonzini if (!req->sg) {
15005f412602SPhilippe Mathieu-Daudé req->residual -= len;
150149ab747fSPaolo Bonzini req->bus->info->transfer_data(req, len);
150249ab747fSPaolo Bonzini return;
150349ab747fSPaolo Bonzini }
150449ab747fSPaolo Bonzini
150549ab747fSPaolo Bonzini /* If the device calls scsi_req_data and the HBA specified a
150649ab747fSPaolo Bonzini * scatter/gather list, the transfer has to happen in a single
150749ab747fSPaolo Bonzini * step. */
150849ab747fSPaolo Bonzini assert(!req->dma_started);
150949ab747fSPaolo Bonzini req->dma_started = true;
151049ab747fSPaolo Bonzini
151149ab747fSPaolo Bonzini buf = scsi_req_get_buf(req);
151249ab747fSPaolo Bonzini if (req->cmd.mode == SCSI_XFER_FROM_DEV) {
1513f02b664aSPhilippe Mathieu-Daudé dma_buf_read(buf, len, &req->residual, req->sg,
1514f02b664aSPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED);
151549ab747fSPaolo Bonzini } else {
1516f02b664aSPhilippe Mathieu-Daudé dma_buf_write(buf, len, &req->residual, req->sg,
1517f02b664aSPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED);
151849ab747fSPaolo Bonzini }
151949ab747fSPaolo Bonzini scsi_req_continue(req);
152049ab747fSPaolo Bonzini }
152149ab747fSPaolo Bonzini
scsi_req_print(SCSIRequest * req)152249ab747fSPaolo Bonzini void scsi_req_print(SCSIRequest *req)
152349ab747fSPaolo Bonzini {
152449ab747fSPaolo Bonzini FILE *fp = stderr;
152549ab747fSPaolo Bonzini int i;
152649ab747fSPaolo Bonzini
152749ab747fSPaolo Bonzini fprintf(fp, "[%s id=%d] %s",
152849ab747fSPaolo Bonzini req->dev->qdev.parent_bus->name,
152949ab747fSPaolo Bonzini req->dev->id,
153049ab747fSPaolo Bonzini scsi_command_name(req->cmd.buf[0]));
153149ab747fSPaolo Bonzini for (i = 1; i < req->cmd.len; i++) {
153249ab747fSPaolo Bonzini fprintf(fp, " 0x%02x", req->cmd.buf[i]);
153349ab747fSPaolo Bonzini }
153449ab747fSPaolo Bonzini switch (req->cmd.mode) {
153549ab747fSPaolo Bonzini case SCSI_XFER_NONE:
153649ab747fSPaolo Bonzini fprintf(fp, " - none\n");
153749ab747fSPaolo Bonzini break;
153849ab747fSPaolo Bonzini case SCSI_XFER_FROM_DEV:
153949ab747fSPaolo Bonzini fprintf(fp, " - from-dev len=%zd\n", req->cmd.xfer);
154049ab747fSPaolo Bonzini break;
154149ab747fSPaolo Bonzini case SCSI_XFER_TO_DEV:
154249ab747fSPaolo Bonzini fprintf(fp, " - to-dev len=%zd\n", req->cmd.xfer);
154349ab747fSPaolo Bonzini break;
154449ab747fSPaolo Bonzini default:
154549ab747fSPaolo Bonzini fprintf(fp, " - Oops\n");
154649ab747fSPaolo Bonzini break;
154749ab747fSPaolo Bonzini }
154849ab747fSPaolo Bonzini }
154949ab747fSPaolo Bonzini
scsi_req_complete_failed(SCSIRequest * req,int host_status)1550f3126d65SHannes Reinecke void scsi_req_complete_failed(SCSIRequest *req, int host_status)
1551f3126d65SHannes Reinecke {
1552f3126d65SHannes Reinecke SCSISense sense;
1553f3126d65SHannes Reinecke int status;
1554f3126d65SHannes Reinecke
1555f3126d65SHannes Reinecke assert(req->status == -1 && req->host_status == -1);
1556f3126d65SHannes Reinecke assert(req->ops != &reqops_unit_attention);
1557f3126d65SHannes Reinecke
1558f3126d65SHannes Reinecke if (!req->bus->info->fail) {
1559f3126d65SHannes Reinecke status = scsi_sense_from_host_status(req->host_status, &sense);
1560f3126d65SHannes Reinecke if (status == CHECK_CONDITION) {
1561f3126d65SHannes Reinecke scsi_req_build_sense(req, sense);
1562f3126d65SHannes Reinecke }
1563f3126d65SHannes Reinecke scsi_req_complete(req, status);
1564f3126d65SHannes Reinecke return;
1565f3126d65SHannes Reinecke }
1566f3126d65SHannes Reinecke
1567f3126d65SHannes Reinecke req->host_status = host_status;
1568f3126d65SHannes Reinecke scsi_req_ref(req);
1569f3126d65SHannes Reinecke scsi_req_dequeue(req);
1570f3126d65SHannes Reinecke req->bus->info->fail(req);
1571f3126d65SHannes Reinecke
1572f3126d65SHannes Reinecke /* Cancelled requests might end up being completed instead of cancelled */
1573f3126d65SHannes Reinecke notifier_list_notify(&req->cancel_notifiers, req);
1574f3126d65SHannes Reinecke scsi_req_unref(req);
1575f3126d65SHannes Reinecke }
1576f3126d65SHannes Reinecke
scsi_req_complete(SCSIRequest * req,int status)157749ab747fSPaolo Bonzini void scsi_req_complete(SCSIRequest *req, int status)
157849ab747fSPaolo Bonzini {
1579f3126d65SHannes Reinecke assert(req->status == -1 && req->host_status == -1);
158049ab747fSPaolo Bonzini req->status = status;
1581f3126d65SHannes Reinecke req->host_status = SCSI_HOST_OK;
158249ab747fSPaolo Bonzini
158349ab747fSPaolo Bonzini assert(req->sense_len <= sizeof(req->sense));
158449ab747fSPaolo Bonzini if (status == GOOD) {
158549ab747fSPaolo Bonzini req->sense_len = 0;
158649ab747fSPaolo Bonzini }
158749ab747fSPaolo Bonzini
158849ab747fSPaolo Bonzini if (req->sense_len) {
158949ab747fSPaolo Bonzini memcpy(req->dev->sense, req->sense, req->sense_len);
159049ab747fSPaolo Bonzini req->dev->sense_len = req->sense_len;
159149ab747fSPaolo Bonzini req->dev->sense_is_ua = (req->ops == &reqops_unit_attention);
159249ab747fSPaolo Bonzini } else {
159349ab747fSPaolo Bonzini req->dev->sense_len = 0;
159449ab747fSPaolo Bonzini req->dev->sense_is_ua = false;
159549ab747fSPaolo Bonzini }
159649ab747fSPaolo Bonzini
159749ab747fSPaolo Bonzini scsi_req_ref(req);
159849ab747fSPaolo Bonzini scsi_req_dequeue(req);
15995f412602SPhilippe Mathieu-Daudé req->bus->info->complete(req, req->residual);
16008e0a9320SFam Zheng
16018e0a9320SFam Zheng /* Cancelled requests might end up being completed instead of cancelled */
16028e0a9320SFam Zheng notifier_list_notify(&req->cancel_notifiers, req);
160349ab747fSPaolo Bonzini scsi_req_unref(req);
160449ab747fSPaolo Bonzini }
160549ab747fSPaolo Bonzini
1606d5776465SFam Zheng /* Called by the devices when the request is canceled. */
scsi_req_cancel_complete(SCSIRequest * req)1607d5776465SFam Zheng void scsi_req_cancel_complete(SCSIRequest *req)
1608d5776465SFam Zheng {
1609d5776465SFam Zheng assert(req->io_canceled);
1610d5776465SFam Zheng if (req->bus->info->cancel) {
1611d5776465SFam Zheng req->bus->info->cancel(req);
1612d5776465SFam Zheng }
16138e0a9320SFam Zheng notifier_list_notify(&req->cancel_notifiers, req);
1614d5776465SFam Zheng scsi_req_unref(req);
1615d5776465SFam Zheng }
1616d5776465SFam Zheng
16178e0a9320SFam Zheng /* Cancel @req asynchronously. @notifier is added to @req's cancellation
16188e0a9320SFam Zheng * notifier list, the bus will be notified the requests cancellation is
16198e0a9320SFam Zheng * completed.
16208e0a9320SFam Zheng * */
scsi_req_cancel_async(SCSIRequest * req,Notifier * notifier)16218e0a9320SFam Zheng void scsi_req_cancel_async(SCSIRequest *req, Notifier *notifier)
16228e0a9320SFam Zheng {
16238e0a9320SFam Zheng trace_scsi_req_cancel(req->dev->id, req->lun, req->tag);
16248e0a9320SFam Zheng if (notifier) {
16258e0a9320SFam Zheng notifier_list_add(&req->cancel_notifiers, notifier);
16268e0a9320SFam Zheng }
16273daa4107SPaolo Bonzini if (req->io_canceled) {
16283daa4107SPaolo Bonzini /* A blk_aio_cancel_async is pending; when it finishes,
16293daa4107SPaolo Bonzini * scsi_req_cancel_complete will be called and will
16303daa4107SPaolo Bonzini * call the notifier we just added. Just wait for that.
16313daa4107SPaolo Bonzini */
16323daa4107SPaolo Bonzini assert(req->aiocb);
16333daa4107SPaolo Bonzini return;
16343daa4107SPaolo Bonzini }
16353daa4107SPaolo Bonzini /* Dropped in scsi_req_cancel_complete. */
16368e0a9320SFam Zheng scsi_req_ref(req);
16378e0a9320SFam Zheng scsi_req_dequeue(req);
16388e0a9320SFam Zheng req->io_canceled = true;
16398e0a9320SFam Zheng if (req->aiocb) {
16404be74634SMarkus Armbruster blk_aio_cancel_async(req->aiocb);
16412aeba9d8SFam Zheng } else {
16422aeba9d8SFam Zheng scsi_req_cancel_complete(req);
16438e0a9320SFam Zheng }
16448e0a9320SFam Zheng }
16458e0a9320SFam Zheng
scsi_req_cancel(SCSIRequest * req)164649ab747fSPaolo Bonzini void scsi_req_cancel(SCSIRequest *req)
164749ab747fSPaolo Bonzini {
164849ab747fSPaolo Bonzini trace_scsi_req_cancel(req->dev->id, req->lun, req->tag);
164949ab747fSPaolo Bonzini if (!req->enqueued) {
165049ab747fSPaolo Bonzini return;
165149ab747fSPaolo Bonzini }
16523daa4107SPaolo Bonzini assert(!req->io_canceled);
16533daa4107SPaolo Bonzini /* Dropped in scsi_req_cancel_complete. */
165449ab747fSPaolo Bonzini scsi_req_ref(req);
165549ab747fSPaolo Bonzini scsi_req_dequeue(req);
165649ab747fSPaolo Bonzini req->io_canceled = true;
1657a83cfd12SFam Zheng if (req->aiocb) {
16584be74634SMarkus Armbruster blk_aio_cancel(req->aiocb);
1659488eef2fSPaolo Bonzini } else {
1660488eef2fSPaolo Bonzini scsi_req_cancel_complete(req);
166149ab747fSPaolo Bonzini }
166249ab747fSPaolo Bonzini }
166349ab747fSPaolo Bonzini
scsi_ua_precedence(SCSISense sense)166449ab747fSPaolo Bonzini static int scsi_ua_precedence(SCSISense sense)
166549ab747fSPaolo Bonzini {
166649ab747fSPaolo Bonzini if (sense.key != UNIT_ATTENTION) {
166749ab747fSPaolo Bonzini return INT_MAX;
166849ab747fSPaolo Bonzini }
166949ab747fSPaolo Bonzini if (sense.asc == 0x29 && sense.ascq == 0x04) {
167049ab747fSPaolo Bonzini /* DEVICE INTERNAL RESET goes with POWER ON OCCURRED */
167149ab747fSPaolo Bonzini return 1;
167249ab747fSPaolo Bonzini } else if (sense.asc == 0x3F && sense.ascq == 0x01) {
167349ab747fSPaolo Bonzini /* MICROCODE HAS BEEN CHANGED goes with SCSI BUS RESET OCCURRED */
167449ab747fSPaolo Bonzini return 2;
167549ab747fSPaolo Bonzini } else if (sense.asc == 0x29 && (sense.ascq == 0x05 || sense.ascq == 0x06)) {
167649ab747fSPaolo Bonzini /* These two go with "all others". */
167749ab747fSPaolo Bonzini ;
167849ab747fSPaolo Bonzini } else if (sense.asc == 0x29 && sense.ascq <= 0x07) {
167949ab747fSPaolo Bonzini /* POWER ON, RESET OR BUS DEVICE RESET OCCURRED = 0
168049ab747fSPaolo Bonzini * POWER ON OCCURRED = 1
168149ab747fSPaolo Bonzini * SCSI BUS RESET OCCURRED = 2
168249ab747fSPaolo Bonzini * BUS DEVICE RESET FUNCTION OCCURRED = 3
168349ab747fSPaolo Bonzini * I_T NEXUS LOSS OCCURRED = 7
168449ab747fSPaolo Bonzini */
168549ab747fSPaolo Bonzini return sense.ascq;
168649ab747fSPaolo Bonzini } else if (sense.asc == 0x2F && sense.ascq == 0x01) {
168749ab747fSPaolo Bonzini /* COMMANDS CLEARED BY POWER LOSS NOTIFICATION */
168849ab747fSPaolo Bonzini return 8;
168949ab747fSPaolo Bonzini }
169049ab747fSPaolo Bonzini return (sense.asc << 8) | sense.ascq;
169149ab747fSPaolo Bonzini }
169249ab747fSPaolo Bonzini
scsi_bus_set_ua(SCSIBus * bus,SCSISense sense)16938cc5583aSVenu Busireddy void scsi_bus_set_ua(SCSIBus *bus, SCSISense sense)
16948cc5583aSVenu Busireddy {
16958cc5583aSVenu Busireddy int prec1, prec2;
16968cc5583aSVenu Busireddy if (sense.key != UNIT_ATTENTION) {
16978cc5583aSVenu Busireddy return;
16988cc5583aSVenu Busireddy }
16998cc5583aSVenu Busireddy
17008cc5583aSVenu Busireddy /*
17018cc5583aSVenu Busireddy * Override a pre-existing unit attention condition, except for a more
17028cc5583aSVenu Busireddy * important reset condition.
17038cc5583aSVenu Busireddy */
17048cc5583aSVenu Busireddy prec1 = scsi_ua_precedence(bus->unit_attention);
17058cc5583aSVenu Busireddy prec2 = scsi_ua_precedence(sense);
17068cc5583aSVenu Busireddy if (prec2 < prec1) {
17078cc5583aSVenu Busireddy bus->unit_attention = sense;
17088cc5583aSVenu Busireddy }
17098cc5583aSVenu Busireddy }
17108cc5583aSVenu Busireddy
scsi_device_set_ua(SCSIDevice * sdev,SCSISense sense)171149ab747fSPaolo Bonzini void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense)
171249ab747fSPaolo Bonzini {
171349ab747fSPaolo Bonzini int prec1, prec2;
171449ab747fSPaolo Bonzini if (sense.key != UNIT_ATTENTION) {
171549ab747fSPaolo Bonzini return;
171649ab747fSPaolo Bonzini }
171749ab747fSPaolo Bonzini trace_scsi_device_set_ua(sdev->id, sdev->lun, sense.key,
171849ab747fSPaolo Bonzini sense.asc, sense.ascq);
171949ab747fSPaolo Bonzini
172049ab747fSPaolo Bonzini /*
172149ab747fSPaolo Bonzini * Override a pre-existing unit attention condition, except for a more
172249ab747fSPaolo Bonzini * important reset condition.
172349ab747fSPaolo Bonzini */
172449ab747fSPaolo Bonzini prec1 = scsi_ua_precedence(sdev->unit_attention);
172549ab747fSPaolo Bonzini prec2 = scsi_ua_precedence(sense);
172649ab747fSPaolo Bonzini if (prec2 < prec1) {
172749ab747fSPaolo Bonzini sdev->unit_attention = sense;
172849ab747fSPaolo Bonzini }
172949ab747fSPaolo Bonzini }
173049ab747fSPaolo Bonzini
scsi_device_purge_one_req(SCSIRequest * req,void * opaque)1731eaad0fe2SStefan Hajnoczi static void scsi_device_purge_one_req(SCSIRequest *req, void *opaque)
173249ab747fSPaolo Bonzini {
17338aad35f6SPaolo Bonzini scsi_req_cancel_async(req, NULL);
173449ab747fSPaolo Bonzini }
1735eaad0fe2SStefan Hajnoczi
17361604c049SHanna Czenczek /**
17371604c049SHanna Czenczek * Cancel all requests, and block until they are deleted.
17381604c049SHanna Czenczek */
scsi_device_purge_requests(SCSIDevice * sdev,SCSISense sense)1739eaad0fe2SStefan Hajnoczi void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
1740eaad0fe2SStefan Hajnoczi {
1741eaad0fe2SStefan Hajnoczi scsi_device_for_each_req_async(sdev, scsi_device_purge_one_req, NULL);
1742eaad0fe2SStefan Hajnoczi
17431604c049SHanna Czenczek /*
17441604c049SHanna Czenczek * Await all the scsi_device_purge_one_req() calls scheduled by
17451604c049SHanna Czenczek * scsi_device_for_each_req_async(), and all I/O requests that were
17461604c049SHanna Czenczek * cancelled this way, but may still take a bit of time to settle.
17471604c049SHanna Czenczek */
17488aad35f6SPaolo Bonzini blk_drain(sdev->conf.blk);
17491604c049SHanna Czenczek
175049ab747fSPaolo Bonzini scsi_device_set_ua(sdev, sense);
175149ab747fSPaolo Bonzini }
175249ab747fSPaolo Bonzini
scsi_device_drained_begin(SCSIDevice * sdev)1753766aa2deSStefan Hajnoczi void scsi_device_drained_begin(SCSIDevice *sdev)
1754766aa2deSStefan Hajnoczi {
1755766aa2deSStefan Hajnoczi SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, sdev->qdev.parent_bus);
1756766aa2deSStefan Hajnoczi if (!bus) {
1757766aa2deSStefan Hajnoczi return;
1758766aa2deSStefan Hajnoczi }
1759766aa2deSStefan Hajnoczi
1760766aa2deSStefan Hajnoczi assert(qemu_get_current_aio_context() == qemu_get_aio_context());
1761766aa2deSStefan Hajnoczi assert(bus->drain_count < INT_MAX);
1762766aa2deSStefan Hajnoczi
1763766aa2deSStefan Hajnoczi /*
1764766aa2deSStefan Hajnoczi * Multiple BlockBackends can be on a SCSIBus and each may begin/end
1765766aa2deSStefan Hajnoczi * draining at any time. Keep a counter so HBAs only see begin/end once.
1766766aa2deSStefan Hajnoczi */
1767766aa2deSStefan Hajnoczi if (bus->drain_count++ == 0) {
1768766aa2deSStefan Hajnoczi trace_scsi_bus_drained_begin(bus, sdev);
1769766aa2deSStefan Hajnoczi if (bus->info->drained_begin) {
1770766aa2deSStefan Hajnoczi bus->info->drained_begin(bus);
1771766aa2deSStefan Hajnoczi }
1772766aa2deSStefan Hajnoczi }
1773766aa2deSStefan Hajnoczi }
1774766aa2deSStefan Hajnoczi
scsi_device_drained_end(SCSIDevice * sdev)1775766aa2deSStefan Hajnoczi void scsi_device_drained_end(SCSIDevice *sdev)
1776766aa2deSStefan Hajnoczi {
1777766aa2deSStefan Hajnoczi SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, sdev->qdev.parent_bus);
1778766aa2deSStefan Hajnoczi if (!bus) {
1779766aa2deSStefan Hajnoczi return;
1780766aa2deSStefan Hajnoczi }
1781766aa2deSStefan Hajnoczi
1782766aa2deSStefan Hajnoczi assert(qemu_get_current_aio_context() == qemu_get_aio_context());
1783766aa2deSStefan Hajnoczi assert(bus->drain_count > 0);
1784766aa2deSStefan Hajnoczi
1785766aa2deSStefan Hajnoczi if (bus->drain_count-- == 1) {
1786766aa2deSStefan Hajnoczi trace_scsi_bus_drained_end(bus, sdev);
1787766aa2deSStefan Hajnoczi if (bus->info->drained_end) {
1788766aa2deSStefan Hajnoczi bus->info->drained_end(bus);
1789766aa2deSStefan Hajnoczi }
1790766aa2deSStefan Hajnoczi }
1791766aa2deSStefan Hajnoczi }
1792766aa2deSStefan Hajnoczi
scsibus_get_dev_path(DeviceState * dev)179349ab747fSPaolo Bonzini static char *scsibus_get_dev_path(DeviceState *dev)
179449ab747fSPaolo Bonzini {
1795e1dc6815SCao jin SCSIDevice *d = SCSI_DEVICE(dev);
179649ab747fSPaolo Bonzini DeviceState *hba = dev->parent_bus->parent;
179749ab747fSPaolo Bonzini char *id;
179849ab747fSPaolo Bonzini char *path;
179949ab747fSPaolo Bonzini
180049ab747fSPaolo Bonzini id = qdev_get_dev_path(hba);
180149ab747fSPaolo Bonzini if (id) {
180249ab747fSPaolo Bonzini path = g_strdup_printf("%s/%d:%d:%d", id, d->channel, d->id, d->lun);
180349ab747fSPaolo Bonzini } else {
180449ab747fSPaolo Bonzini path = g_strdup_printf("%d:%d:%d", d->channel, d->id, d->lun);
180549ab747fSPaolo Bonzini }
180649ab747fSPaolo Bonzini g_free(id);
180749ab747fSPaolo Bonzini return path;
180849ab747fSPaolo Bonzini }
180949ab747fSPaolo Bonzini
scsibus_get_fw_dev_path(DeviceState * dev)181049ab747fSPaolo Bonzini static char *scsibus_get_fw_dev_path(DeviceState *dev)
181149ab747fSPaolo Bonzini {
181249ab747fSPaolo Bonzini SCSIDevice *d = SCSI_DEVICE(dev);
181349ab747fSPaolo Bonzini return g_strdup_printf("channel@%x/%s@%x,%x", d->channel,
181449ab747fSPaolo Bonzini qdev_fw_name(dev), d->id, d->lun);
181549ab747fSPaolo Bonzini }
181649ab747fSPaolo Bonzini
181749ab747fSPaolo Bonzini /* SCSI request list. For simplicity, pv points to the whole device */
181849ab747fSPaolo Bonzini
put_scsi_req(SCSIRequest * req,void * opaque)1819eaad0fe2SStefan Hajnoczi static void put_scsi_req(SCSIRequest *req, void *opaque)
182049ab747fSPaolo Bonzini {
1821eaad0fe2SStefan Hajnoczi QEMUFile *f = opaque;
182249ab747fSPaolo Bonzini
182349ab747fSPaolo Bonzini assert(!req->io_canceled);
1824f3126d65SHannes Reinecke assert(req->status == -1 && req->host_status == -1);
182549ab747fSPaolo Bonzini assert(req->enqueued);
182649ab747fSPaolo Bonzini
182749ab747fSPaolo Bonzini qemu_put_sbyte(f, req->retry ? 1 : 2);
182849ab747fSPaolo Bonzini qemu_put_buffer(f, req->cmd.buf, sizeof(req->cmd.buf));
182949ab747fSPaolo Bonzini qemu_put_be32s(f, &req->tag);
183049ab747fSPaolo Bonzini qemu_put_be32s(f, &req->lun);
1831eaad0fe2SStefan Hajnoczi if (req->bus->info->save_request) {
1832eaad0fe2SStefan Hajnoczi req->bus->info->save_request(f, req);
183349ab747fSPaolo Bonzini }
183449ab747fSPaolo Bonzini if (req->ops->save_request) {
183549ab747fSPaolo Bonzini req->ops->save_request(f, req);
183649ab747fSPaolo Bonzini }
183749ab747fSPaolo Bonzini }
18382c21ee76SJianjun Duan
put_scsi_requests(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)1839eaad0fe2SStefan Hajnoczi static int put_scsi_requests(QEMUFile *f, void *pv, size_t size,
1840eaad0fe2SStefan Hajnoczi const VMStateField *field, JSONWriter *vmdesc)
1841eaad0fe2SStefan Hajnoczi {
1842eaad0fe2SStefan Hajnoczi SCSIDevice *s = pv;
1843eaad0fe2SStefan Hajnoczi
1844eaad0fe2SStefan Hajnoczi scsi_device_for_each_req_sync(s, put_scsi_req, f);
1845eaad0fe2SStefan Hajnoczi qemu_put_sbyte(f, 0);
18462c21ee76SJianjun Duan return 0;
184749ab747fSPaolo Bonzini }
184849ab747fSPaolo Bonzini
get_scsi_requests(QEMUFile * f,void * pv,size_t size,const VMStateField * field)18492c21ee76SJianjun Duan static int get_scsi_requests(QEMUFile *f, void *pv, size_t size,
185003fee66fSMarc-André Lureau const VMStateField *field)
185149ab747fSPaolo Bonzini {
185249ab747fSPaolo Bonzini SCSIDevice *s = pv;
185349ab747fSPaolo Bonzini SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus);
185449ab747fSPaolo Bonzini int8_t sbyte;
185549ab747fSPaolo Bonzini
185649ab747fSPaolo Bonzini while ((sbyte = qemu_get_sbyte(f)) > 0) {
185749ab747fSPaolo Bonzini uint8_t buf[SCSI_CMD_BUF_SIZE];
185849ab747fSPaolo Bonzini uint32_t tag;
185949ab747fSPaolo Bonzini uint32_t lun;
186049ab747fSPaolo Bonzini SCSIRequest *req;
186149ab747fSPaolo Bonzini
186249ab747fSPaolo Bonzini qemu_get_buffer(f, buf, sizeof(buf));
186349ab747fSPaolo Bonzini qemu_get_be32s(f, &tag);
186449ab747fSPaolo Bonzini qemu_get_be32s(f, &lun);
1865fe9d8927SJohn Millikin /*
1866fe9d8927SJohn Millikin * A too-short CDB would have been rejected by scsi_req_new, so just use
1867fe9d8927SJohn Millikin * SCSI_CMD_BUF_SIZE as the CDB length.
1868fe9d8927SJohn Millikin */
1869fe9d8927SJohn Millikin req = scsi_req_new(s, tag, lun, buf, sizeof(buf), NULL);
187049ab747fSPaolo Bonzini req->retry = (sbyte == 1);
187149ab747fSPaolo Bonzini if (bus->info->load_request) {
187249ab747fSPaolo Bonzini req->hba_private = bus->info->load_request(f, req);
187349ab747fSPaolo Bonzini }
187449ab747fSPaolo Bonzini if (req->ops->load_request) {
187549ab747fSPaolo Bonzini req->ops->load_request(f, req);
187649ab747fSPaolo Bonzini }
187749ab747fSPaolo Bonzini
187849ab747fSPaolo Bonzini /* Just restart it later. */
187949ab747fSPaolo Bonzini scsi_req_enqueue_internal(req);
188049ab747fSPaolo Bonzini
188149ab747fSPaolo Bonzini /* At this point, the request will be kept alive by the reference
188249ab747fSPaolo Bonzini * added by scsi_req_enqueue_internal, so we can release our reference.
188349ab747fSPaolo Bonzini * The HBA of course will add its own reference in the load_request
188449ab747fSPaolo Bonzini * callback if it needs to hold on the SCSIRequest.
188549ab747fSPaolo Bonzini */
188649ab747fSPaolo Bonzini scsi_req_unref(req);
188749ab747fSPaolo Bonzini }
188849ab747fSPaolo Bonzini
188949ab747fSPaolo Bonzini return 0;
189049ab747fSPaolo Bonzini }
189149ab747fSPaolo Bonzini
189249ab747fSPaolo Bonzini static const VMStateInfo vmstate_info_scsi_requests = {
189349ab747fSPaolo Bonzini .name = "scsi-requests",
189449ab747fSPaolo Bonzini .get = get_scsi_requests,
189549ab747fSPaolo Bonzini .put = put_scsi_requests,
189649ab747fSPaolo Bonzini };
189749ab747fSPaolo Bonzini
scsi_sense_state_needed(void * opaque)18982e323f03SFam Zheng static bool scsi_sense_state_needed(void *opaque)
18992e323f03SFam Zheng {
19002e323f03SFam Zheng SCSIDevice *s = opaque;
19012e323f03SFam Zheng
19022e323f03SFam Zheng return s->sense_len > SCSI_SENSE_BUF_SIZE_OLD;
19032e323f03SFam Zheng }
19042e323f03SFam Zheng
19052e323f03SFam Zheng static const VMStateDescription vmstate_scsi_sense_state = {
19062e323f03SFam Zheng .name = "SCSIDevice/sense",
19072e323f03SFam Zheng .version_id = 1,
19082e323f03SFam Zheng .minimum_version_id = 1,
19095cd8cadaSJuan Quintela .needed = scsi_sense_state_needed,
19102d7b39a6SRichard Henderson .fields = (const VMStateField[]) {
19112e323f03SFam Zheng VMSTATE_UINT8_SUB_ARRAY(sense, SCSIDevice,
19122e323f03SFam Zheng SCSI_SENSE_BUF_SIZE_OLD,
19132e323f03SFam Zheng SCSI_SENSE_BUF_SIZE - SCSI_SENSE_BUF_SIZE_OLD),
19142e323f03SFam Zheng VMSTATE_END_OF_LIST()
19152e323f03SFam Zheng }
19162e323f03SFam Zheng };
19172e323f03SFam Zheng
191849ab747fSPaolo Bonzini const VMStateDescription vmstate_scsi_device = {
191949ab747fSPaolo Bonzini .name = "SCSIDevice",
192049ab747fSPaolo Bonzini .version_id = 1,
192149ab747fSPaolo Bonzini .minimum_version_id = 1,
19222d7b39a6SRichard Henderson .fields = (const VMStateField[]) {
192349ab747fSPaolo Bonzini VMSTATE_UINT8(unit_attention.key, SCSIDevice),
192449ab747fSPaolo Bonzini VMSTATE_UINT8(unit_attention.asc, SCSIDevice),
192549ab747fSPaolo Bonzini VMSTATE_UINT8(unit_attention.ascq, SCSIDevice),
192649ab747fSPaolo Bonzini VMSTATE_BOOL(sense_is_ua, SCSIDevice),
19272e323f03SFam Zheng VMSTATE_UINT8_SUB_ARRAY(sense, SCSIDevice, 0, SCSI_SENSE_BUF_SIZE_OLD),
192849ab747fSPaolo Bonzini VMSTATE_UINT32(sense_len, SCSIDevice),
192949ab747fSPaolo Bonzini {
193049ab747fSPaolo Bonzini .name = "requests",
193149ab747fSPaolo Bonzini .version_id = 0,
193249ab747fSPaolo Bonzini .field_exists = NULL,
193349ab747fSPaolo Bonzini .size = 0, /* ouch */
193449ab747fSPaolo Bonzini .info = &vmstate_info_scsi_requests,
193549ab747fSPaolo Bonzini .flags = VMS_SINGLE,
193649ab747fSPaolo Bonzini .offset = 0,
193749ab747fSPaolo Bonzini },
193849ab747fSPaolo Bonzini VMSTATE_END_OF_LIST()
19392e323f03SFam Zheng },
19402d7b39a6SRichard Henderson .subsections = (const VMStateDescription * const []) {
19415cd8cadaSJuan Quintela &vmstate_scsi_sense_state,
19425cd8cadaSJuan Quintela NULL
194349ab747fSPaolo Bonzini }
194449ab747fSPaolo Bonzini };
194549ab747fSPaolo Bonzini
194642a90a89SPaolo Bonzini static Property scsi_props[] = {
194742a90a89SPaolo Bonzini DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
194842a90a89SPaolo Bonzini DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
194942a90a89SPaolo Bonzini DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
195042a90a89SPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
195142a90a89SPaolo Bonzini };
195242a90a89SPaolo Bonzini
scsi_device_class_init(ObjectClass * klass,void * data)195349ab747fSPaolo Bonzini static void scsi_device_class_init(ObjectClass *klass, void *data)
195449ab747fSPaolo Bonzini {
195549ab747fSPaolo Bonzini DeviceClass *k = DEVICE_CLASS(klass);
1956125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
195749ab747fSPaolo Bonzini k->bus_type = TYPE_SCSI_BUS;
1958a818a4b6SFam Zheng k->realize = scsi_qdev_realize;
1959a818a4b6SFam Zheng k->unrealize = scsi_qdev_unrealize;
19604f67d30bSMarc-André Lureau device_class_set_props(k, scsi_props);
196149ab747fSPaolo Bonzini }
196249ab747fSPaolo Bonzini
scsi_dev_instance_init(Object * obj)196344fb6337SGonglei static void scsi_dev_instance_init(Object *obj)
196444fb6337SGonglei {
196544fb6337SGonglei DeviceState *dev = DEVICE(obj);
1966e1dc6815SCao jin SCSIDevice *s = SCSI_DEVICE(dev);
196744fb6337SGonglei
196844fb6337SGonglei device_add_bootindex_property(obj, &s->conf.bootindex,
196944fb6337SGonglei "bootindex", NULL,
197040c2281cSMarkus Armbruster &s->qdev);
197144fb6337SGonglei }
197244fb6337SGonglei
197349ab747fSPaolo Bonzini static const TypeInfo scsi_device_type_info = {
197449ab747fSPaolo Bonzini .name = TYPE_SCSI_DEVICE,
197549ab747fSPaolo Bonzini .parent = TYPE_DEVICE,
197649ab747fSPaolo Bonzini .instance_size = sizeof(SCSIDevice),
197749ab747fSPaolo Bonzini .abstract = true,
197849ab747fSPaolo Bonzini .class_size = sizeof(SCSIDeviceClass),
197949ab747fSPaolo Bonzini .class_init = scsi_device_class_init,
198044fb6337SGonglei .instance_init = scsi_dev_instance_init,
198149ab747fSPaolo Bonzini };
198249ab747fSPaolo Bonzini
scsi_bus_class_init(ObjectClass * klass,void * data)198342a90a89SPaolo Bonzini static void scsi_bus_class_init(ObjectClass *klass, void *data)
198442a90a89SPaolo Bonzini {
198542a90a89SPaolo Bonzini BusClass *k = BUS_CLASS(klass);
198642a90a89SPaolo Bonzini HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
198742a90a89SPaolo Bonzini
198842a90a89SPaolo Bonzini k->get_dev_path = scsibus_get_dev_path;
198942a90a89SPaolo Bonzini k->get_fw_dev_path = scsibus_get_fw_dev_path;
199042a90a89SPaolo Bonzini k->check_address = scsi_bus_check_address;
199142a90a89SPaolo Bonzini hc->unplug = qdev_simple_device_unplug_cb;
199242a90a89SPaolo Bonzini }
199342a90a89SPaolo Bonzini
199442a90a89SPaolo Bonzini static const TypeInfo scsi_bus_info = {
199542a90a89SPaolo Bonzini .name = TYPE_SCSI_BUS,
199642a90a89SPaolo Bonzini .parent = TYPE_BUS,
199742a90a89SPaolo Bonzini .instance_size = sizeof(SCSIBus),
199842a90a89SPaolo Bonzini .class_init = scsi_bus_class_init,
199942a90a89SPaolo Bonzini .interfaces = (InterfaceInfo[]) {
200042a90a89SPaolo Bonzini { TYPE_HOTPLUG_HANDLER },
200142a90a89SPaolo Bonzini { }
200242a90a89SPaolo Bonzini }
200342a90a89SPaolo Bonzini };
200442a90a89SPaolo Bonzini
scsi_register_types(void)200549ab747fSPaolo Bonzini static void scsi_register_types(void)
200649ab747fSPaolo Bonzini {
200749ab747fSPaolo Bonzini type_register_static(&scsi_bus_info);
200849ab747fSPaolo Bonzini type_register_static(&scsi_device_type_info);
200949ab747fSPaolo Bonzini }
201049ab747fSPaolo Bonzini
201149ab747fSPaolo Bonzini type_init(scsi_register_types)
2012