xref: /openbmc/qemu/hw/scsi/scsi-bus.c (revision 58ee924b97d1c0898555647a31820c5a20d55a73)
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