xref: /openbmc/qemu/hw/scsi/scsi-disk.c (revision 5eeb09d63e081d516f7d33b353a5179d58e1f9b6)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * SCSI Device emulation
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2006 CodeSourcery.
549ab747fSPaolo Bonzini  * Based on code by Fabrice Bellard
649ab747fSPaolo Bonzini  *
749ab747fSPaolo Bonzini  * Written by Paul Brook
849ab747fSPaolo Bonzini  * Modifications:
949ab747fSPaolo Bonzini  *  2009-Dec-12 Artyom Tarasenko : implemented stamdard inquiry for the case
1049ab747fSPaolo Bonzini  *                                 when the allocation length of CDB is smaller
1149ab747fSPaolo Bonzini  *                                 than 36.
1249ab747fSPaolo Bonzini  *  2009-Oct-13 Artyom Tarasenko : implemented the block descriptor in the
1349ab747fSPaolo Bonzini  *                                 MODE SENSE response.
1449ab747fSPaolo Bonzini  *
1549ab747fSPaolo Bonzini  * This code is licensed under the LGPL.
1649ab747fSPaolo Bonzini  *
1749ab747fSPaolo Bonzini  * Note that this file only handles the SCSI architecture model and device
1849ab747fSPaolo Bonzini  * commands.  Emulation of interface/link layer protocols is handled by
1949ab747fSPaolo Bonzini  * the host adapter emulator.
2049ab747fSPaolo Bonzini  */
2149ab747fSPaolo Bonzini 
22a4ab4792SPeter Maydell #include "qemu/osdep.h"
237e462605SPhilippe Mathieu-Daudé #include "qemu/units.h"
24da34e65cSMarkus Armbruster #include "qapi/error.h"
2549ab747fSPaolo Bonzini #include "qemu/error-report.h"
26db725815SMarkus Armbruster #include "qemu/main-loop.h"
270b8fa32fSMarkus Armbruster #include "qemu/module.h"
2815e09912SPeter Maydell #include "qemu/hw-version.h"
295df022cfSPeter Maydell #include "qemu/memalign.h"
3049ab747fSPaolo Bonzini #include "hw/scsi/scsi.h"
31ca77ee28SMarkus Armbruster #include "migration/qemu-file-types.h"
32d6454270SMarkus Armbruster #include "migration/vmstate.h"
333d4a8bf0SPaolo Bonzini #include "hw/scsi/emulation.h"
3408e2c9f1SPaolo Bonzini #include "scsi/constants.h"
35429442e5SThomas Huth #include "sysemu/arch_init.h"
364be74634SMarkus Armbruster #include "sysemu/block-backend.h"
3749ab747fSPaolo Bonzini #include "sysemu/blockdev.h"
3849ab747fSPaolo Bonzini #include "hw/block/block.h"
39a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
40ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
4149ab747fSPaolo Bonzini #include "sysemu/dma.h"
4271f571a2SSam Eiderman #include "sysemu/sysemu.h"
43f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
4459ee9500SLaurent Vivier #include "trace.h"
45db1015e9SEduardo Habkost #include "qom/object.h"
4649ab747fSPaolo Bonzini 
4749ab747fSPaolo Bonzini #ifdef __linux
4849ab747fSPaolo Bonzini #include <scsi/sg.h>
4949ab747fSPaolo Bonzini #endif
5049ab747fSPaolo Bonzini 
517e462605SPhilippe Mathieu-Daudé #define SCSI_WRITE_SAME_MAX         (512 * KiB)
527e462605SPhilippe Mathieu-Daudé #define SCSI_DMA_BUF_SIZE           (128 * KiB)
5349ab747fSPaolo Bonzini #define SCSI_MAX_INQUIRY_LEN        256
5449ab747fSPaolo Bonzini #define SCSI_MAX_MODE_LEN           256
5549ab747fSPaolo Bonzini 
567e462605SPhilippe Mathieu-Daudé #define DEFAULT_DISCARD_GRANULARITY (4 * KiB)
577e462605SPhilippe Mathieu-Daudé #define DEFAULT_MAX_UNMAP_SIZE      (1 * GiB)
58f8e1f533SPaolo Bonzini #define DEFAULT_MAX_IO_SIZE         INT_MAX     /* 2 GB - 1 block */
5949ab747fSPaolo Bonzini 
60993935f3SPaolo Bonzini #define TYPE_SCSI_DISK_BASE         "scsi-disk-base"
61993935f3SPaolo Bonzini 
6275997e18SKevin Wolf #define MAX_SERIAL_LEN              36
6375997e18SKevin Wolf #define MAX_SERIAL_LEN_FOR_DEVID    20
6475997e18SKevin Wolf 
65a489d195SEduardo Habkost OBJECT_DECLARE_TYPE(SCSIDiskState, SCSIDiskClass, SCSI_DISK_BASE)
66fcaafb10SPaolo Bonzini 
67db1015e9SEduardo Habkost struct SCSIDiskClass {
68fcaafb10SPaolo Bonzini     SCSIDeviceClass parent_class;
69cfe08808SKevin Wolf     /*
70cfe08808SKevin Wolf      * Callbacks receive ret == 0 for success. Errors are represented either as
71cfe08808SKevin Wolf      * negative errno values, or as positive SAM status codes.
728a049562SKevin Wolf      *
738a049562SKevin Wolf      * Beware: For errors returned in host_status, the function may directly
748a049562SKevin Wolf      * complete the request and never call the callback.
75cfe08808SKevin Wolf      */
76fcaafb10SPaolo Bonzini     DMAIOFunc       *dma_readv;
77fcaafb10SPaolo Bonzini     DMAIOFunc       *dma_writev;
7894f8ba11SPaolo Bonzini     bool            (*need_fua_emulation)(SCSICommand *cmd);
79d31347f5SShinichiro Kawasaki     void            (*update_sense)(SCSIRequest *r);
80db1015e9SEduardo Habkost };
8149ab747fSPaolo Bonzini 
8249ab747fSPaolo Bonzini typedef struct SCSIDiskReq {
8349ab747fSPaolo Bonzini     SCSIRequest req;
843dc516bfSPhilippe Mathieu-Daudé     /* Both sector and sector_count are in terms of BDRV_SECTOR_SIZE bytes.  */
8549ab747fSPaolo Bonzini     uint64_t sector;
8649ab747fSPaolo Bonzini     uint32_t sector_count;
8749ab747fSPaolo Bonzini     uint32_t buflen;
8849ab747fSPaolo Bonzini     bool started;
8994f8ba11SPaolo Bonzini     bool need_fua_emulation;
9049ab747fSPaolo Bonzini     struct iovec iov;
9149ab747fSPaolo Bonzini     QEMUIOVector qiov;
9249ab747fSPaolo Bonzini     BlockAcctCookie acct;
9349ab747fSPaolo Bonzini } SCSIDiskReq;
9449ab747fSPaolo Bonzini 
9549ab747fSPaolo Bonzini #define SCSI_DISK_F_REMOVABLE             0
9649ab747fSPaolo Bonzini #define SCSI_DISK_F_DPOFUA                1
9718e673b8SPavel Hrdina #define SCSI_DISK_F_NO_REMOVABLE_DEVOPS   2
9849ab747fSPaolo Bonzini 
99db1015e9SEduardo Habkost struct SCSIDiskState {
10049ab747fSPaolo Bonzini     SCSIDevice qdev;
10149ab747fSPaolo Bonzini     uint32_t features;
10249ab747fSPaolo Bonzini     bool media_changed;
10349ab747fSPaolo Bonzini     bool media_event;
10449ab747fSPaolo Bonzini     bool eject_request;
10564cc2284SRoland Dreier     uint16_t port_index;
1068a1bd297SPaolo Bonzini     uint64_t max_unmap_size;
107f8e1f533SPaolo Bonzini     uint64_t max_io_size;
1083412f9c3SMark Cave-Ayland     uint32_t quirks;
10949ab747fSPaolo Bonzini     QEMUBH *bh;
11049ab747fSPaolo Bonzini     char *version;
11149ab747fSPaolo Bonzini     char *serial;
11249ab747fSPaolo Bonzini     char *vendor;
11349ab747fSPaolo Bonzini     char *product;
1147471a649SKevin Wolf     char *device_id;
115429442e5SThomas Huth     char *loadparm;     /* only for s390x */
11649ab747fSPaolo Bonzini     bool tray_open;
11749ab747fSPaolo Bonzini     bool tray_locked;
118070f8009SDaniel P. Berrange     /*
119070f8009SDaniel P. Berrange      * 0x0000        - rotation rate not reported
120070f8009SDaniel P. Berrange      * 0x0001        - non-rotating medium (SSD)
121070f8009SDaniel P. Berrange      * 0x0002-0x0400 - reserved
122070f8009SDaniel P. Berrange      * 0x0401-0xffe  - rotations per minute
123070f8009SDaniel P. Berrange      * 0xffff        - reserved
124070f8009SDaniel P. Berrange      */
125070f8009SDaniel P. Berrange     uint16_t rotation_rate;
126b4912afaSHyman Huang     bool migrate_emulated_scsi_request;
127db1015e9SEduardo Habkost };
12849ab747fSPaolo Bonzini 
scsi_free_request(SCSIRequest * req)12949ab747fSPaolo Bonzini static void scsi_free_request(SCSIRequest *req)
13049ab747fSPaolo Bonzini {
13149ab747fSPaolo Bonzini     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
13249ab747fSPaolo Bonzini 
13349ab747fSPaolo Bonzini     qemu_vfree(r->iov.iov_base);
13449ab747fSPaolo Bonzini }
13549ab747fSPaolo Bonzini 
13649ab747fSPaolo Bonzini /* Helper function for command completion with sense.  */
scsi_check_condition(SCSIDiskReq * r,SCSISense sense)13749ab747fSPaolo Bonzini static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense)
13849ab747fSPaolo Bonzini {
13959ee9500SLaurent Vivier     trace_scsi_disk_check_condition(r->req.tag, sense.key, sense.asc,
14059ee9500SLaurent Vivier                                     sense.ascq);
14149ab747fSPaolo Bonzini     scsi_req_build_sense(&r->req, sense);
14249ab747fSPaolo Bonzini     scsi_req_complete(&r->req, CHECK_CONDITION);
14349ab747fSPaolo Bonzini }
14449ab747fSPaolo Bonzini 
scsi_init_iovec(SCSIDiskReq * r,size_t size)14503c90063SEric Blake static void scsi_init_iovec(SCSIDiskReq *r, size_t size)
14649ab747fSPaolo Bonzini {
14749ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
14849ab747fSPaolo Bonzini 
14949ab747fSPaolo Bonzini     if (!r->iov.iov_base) {
15049ab747fSPaolo Bonzini         r->buflen = size;
1514be74634SMarkus Armbruster         r->iov.iov_base = blk_blockalign(s->qdev.conf.blk, r->buflen);
15249ab747fSPaolo Bonzini     }
1533dc516bfSPhilippe Mathieu-Daudé     r->iov.iov_len = MIN(r->sector_count * BDRV_SECTOR_SIZE, r->buflen);
15449ab747fSPaolo Bonzini     qemu_iovec_init_external(&r->qiov, &r->iov, 1);
15549ab747fSPaolo Bonzini }
15649ab747fSPaolo Bonzini 
scsi_disk_save_request(QEMUFile * f,SCSIRequest * req)15749ab747fSPaolo Bonzini static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req)
15849ab747fSPaolo Bonzini {
15949ab747fSPaolo Bonzini     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
16049ab747fSPaolo Bonzini 
16149ab747fSPaolo Bonzini     qemu_put_be64s(f, &r->sector);
16249ab747fSPaolo Bonzini     qemu_put_be32s(f, &r->sector_count);
16349ab747fSPaolo Bonzini     qemu_put_be32s(f, &r->buflen);
16449ab747fSPaolo Bonzini     if (r->buflen) {
16549ab747fSPaolo Bonzini         if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
16649ab747fSPaolo Bonzini             qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len);
16749ab747fSPaolo Bonzini         } else if (!req->retry) {
16849ab747fSPaolo Bonzini             uint32_t len = r->iov.iov_len;
16949ab747fSPaolo Bonzini             qemu_put_be32s(f, &len);
17049ab747fSPaolo Bonzini             qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len);
17149ab747fSPaolo Bonzini         }
17249ab747fSPaolo Bonzini     }
17349ab747fSPaolo Bonzini }
17449ab747fSPaolo Bonzini 
scsi_disk_emulate_save_request(QEMUFile * f,SCSIRequest * req)175b4912afaSHyman Huang static void scsi_disk_emulate_save_request(QEMUFile *f, SCSIRequest *req)
176b4912afaSHyman Huang {
177b4912afaSHyman Huang     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
178b4912afaSHyman Huang 
179b4912afaSHyman Huang     if (s->migrate_emulated_scsi_request) {
180b4912afaSHyman Huang         scsi_disk_save_request(f, req);
181b4912afaSHyman Huang     }
182b4912afaSHyman Huang }
183b4912afaSHyman Huang 
scsi_disk_load_request(QEMUFile * f,SCSIRequest * req)18449ab747fSPaolo Bonzini static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req)
18549ab747fSPaolo Bonzini {
18649ab747fSPaolo Bonzini     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
18749ab747fSPaolo Bonzini 
18849ab747fSPaolo Bonzini     qemu_get_be64s(f, &r->sector);
18949ab747fSPaolo Bonzini     qemu_get_be32s(f, &r->sector_count);
19049ab747fSPaolo Bonzini     qemu_get_be32s(f, &r->buflen);
19149ab747fSPaolo Bonzini     if (r->buflen) {
19249ab747fSPaolo Bonzini         scsi_init_iovec(r, r->buflen);
19349ab747fSPaolo Bonzini         if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
19449ab747fSPaolo Bonzini             qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len);
19549ab747fSPaolo Bonzini         } else if (!r->req.retry) {
19649ab747fSPaolo Bonzini             uint32_t len;
19749ab747fSPaolo Bonzini             qemu_get_be32s(f, &len);
19849ab747fSPaolo Bonzini             r->iov.iov_len = len;
19949ab747fSPaolo Bonzini             assert(r->iov.iov_len <= r->buflen);
20049ab747fSPaolo Bonzini             qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len);
20149ab747fSPaolo Bonzini         }
20249ab747fSPaolo Bonzini     }
20349ab747fSPaolo Bonzini 
20449ab747fSPaolo Bonzini     qemu_iovec_init_external(&r->qiov, &r->iov, 1);
20549ab747fSPaolo Bonzini }
20649ab747fSPaolo Bonzini 
scsi_disk_emulate_load_request(QEMUFile * f,SCSIRequest * req)207b4912afaSHyman Huang static void scsi_disk_emulate_load_request(QEMUFile *f, SCSIRequest *req)
208b4912afaSHyman Huang {
209b4912afaSHyman Huang     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
210b4912afaSHyman Huang 
211b4912afaSHyman Huang     if (s->migrate_emulated_scsi_request) {
212b4912afaSHyman Huang         scsi_disk_load_request(f, req);
213b4912afaSHyman Huang     }
214b4912afaSHyman Huang }
215b4912afaSHyman Huang 
216f95f61c2SPaolo Bonzini /*
217f95f61c2SPaolo Bonzini  * scsi_handle_rw_error has two return values.  False means that the error
218f95f61c2SPaolo Bonzini  * must be ignored, true means that the error has been processed and the
219f95f61c2SPaolo Bonzini  * caller should not do anything else for this request.  Note that
220f95f61c2SPaolo Bonzini  * scsi_handle_rw_error always manages its reference counts, independent
221f95f61c2SPaolo Bonzini  * of the return value.
222f95f61c2SPaolo Bonzini  */
scsi_handle_rw_error(SCSIDiskReq * r,int ret,bool acct_failed)223f63c68bcSPaolo Bonzini static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
224f95f61c2SPaolo Bonzini {
225f95f61c2SPaolo Bonzini     bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV);
226f95f61c2SPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
227f95f61c2SPaolo Bonzini     SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
228f63c68bcSPaolo Bonzini     SCSISense sense = SENSE_CODE(NO_SENSE);
2299da6bd39SKevin Wolf     int error;
230f63c68bcSPaolo Bonzini     bool req_has_sense = false;
231f63c68bcSPaolo Bonzini     BlockErrorAction action;
232f63c68bcSPaolo Bonzini     int status;
233f95f61c2SPaolo Bonzini 
234f63c68bcSPaolo Bonzini     if (ret < 0) {
235f63c68bcSPaolo Bonzini         status = scsi_sense_from_errno(-ret, &sense);
236f63c68bcSPaolo Bonzini         error = -ret;
237f63c68bcSPaolo Bonzini     } else {
238f63c68bcSPaolo Bonzini         /* A passthrough command has completed with nonzero status.  */
239f63c68bcSPaolo Bonzini         status = ret;
2409da6bd39SKevin Wolf         switch (status) {
2419da6bd39SKevin Wolf         case CHECK_CONDITION:
242f63c68bcSPaolo Bonzini             req_has_sense = true;
243f63c68bcSPaolo Bonzini             error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
2449da6bd39SKevin Wolf             break;
2459da6bd39SKevin Wolf         case RESERVATION_CONFLICT:
2469da6bd39SKevin Wolf             /*
2479da6bd39SKevin Wolf              * Don't apply the error policy, always report to the guest.
2489da6bd39SKevin Wolf              *
2499da6bd39SKevin Wolf              * This is a passthrough code path, so it's not a backend error, but
2509da6bd39SKevin Wolf              * a response to an invalid guest request.
2519da6bd39SKevin Wolf              *
2529da6bd39SKevin Wolf              * Windows Failover Cluster validation intentionally sends invalid
2539da6bd39SKevin Wolf              * requests to verify that reservations work as intended. It is
2549da6bd39SKevin Wolf              * crucial that it sees the resulting errors.
2559da6bd39SKevin Wolf              *
2569da6bd39SKevin Wolf              * Treating a reservation conflict as a guest-side error is obvious
2579da6bd39SKevin Wolf              * when a pr-manager is in use. Without one, the situation is less
2589da6bd39SKevin Wolf              * clear, but there might be nothing that can be fixed on the host
2599da6bd39SKevin Wolf              * (like in the above example), and we don't want to be stuck in a
2609da6bd39SKevin Wolf              * loop where resuming the VM and retrying the request immediately
2619da6bd39SKevin Wolf              * stops it again. So always reporting is still the safer option in
2629da6bd39SKevin Wolf              * this case, too.
2639da6bd39SKevin Wolf              */
2649da6bd39SKevin Wolf             error = 0;
2659da6bd39SKevin Wolf             break;
2669da6bd39SKevin Wolf         default:
267f63c68bcSPaolo Bonzini             error = EINVAL;
2689da6bd39SKevin Wolf             break;
269f63c68bcSPaolo Bonzini         }
270f63c68bcSPaolo Bonzini     }
271f63c68bcSPaolo Bonzini 
272782a78c9SPaolo Bonzini     /*
273782a78c9SPaolo Bonzini      * Check whether the error has to be handled by the guest or should
274782a78c9SPaolo Bonzini      * rather follow the rerror=/werror= settings.  Guest-handled errors
275782a78c9SPaolo Bonzini      * are usually retried immediately, so do not post them to QMP and
276782a78c9SPaolo Bonzini      * do not account them as failed I/O.
277782a78c9SPaolo Bonzini      */
2789da6bd39SKevin Wolf     if (!error || (req_has_sense &&
2799da6bd39SKevin Wolf                    scsi_sense_buf_is_guest_recoverable(r->req.sense,
2809da6bd39SKevin Wolf                                                        sizeof(r->req.sense)))) {
281782a78c9SPaolo Bonzini         action = BLOCK_ERROR_ACTION_REPORT;
282782a78c9SPaolo Bonzini         acct_failed = false;
283782a78c9SPaolo Bonzini     } else {
284f63c68bcSPaolo Bonzini         action = blk_get_error_action(s->qdev.conf.blk, is_read, error);
285782a78c9SPaolo Bonzini         blk_error_action(s->qdev.conf.blk, action, is_read, error);
286782a78c9SPaolo Bonzini     }
287782a78c9SPaolo Bonzini 
288782a78c9SPaolo Bonzini     switch (action) {
289782a78c9SPaolo Bonzini     case BLOCK_ERROR_ACTION_REPORT:
290f95f61c2SPaolo Bonzini         if (acct_failed) {
291f95f61c2SPaolo Bonzini             block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
292f95f61c2SPaolo Bonzini         }
293f63c68bcSPaolo Bonzini         if (req_has_sense) {
294f95f61c2SPaolo Bonzini             sdc->update_sense(&r->req);
295782a78c9SPaolo Bonzini         } else if (status == CHECK_CONDITION) {
296d7a84021SPaolo Bonzini             scsi_req_build_sense(&r->req, sense);
297d7a84021SPaolo Bonzini         }
298d7a84021SPaolo Bonzini         scsi_req_complete(&r->req, status);
299f95f61c2SPaolo Bonzini         return true;
300782a78c9SPaolo Bonzini 
301782a78c9SPaolo Bonzini     case BLOCK_ERROR_ACTION_IGNORE:
302782a78c9SPaolo Bonzini         return false;
303782a78c9SPaolo Bonzini 
304782a78c9SPaolo Bonzini     case BLOCK_ERROR_ACTION_STOP:
305782a78c9SPaolo Bonzini         scsi_req_retry(&r->req);
306782a78c9SPaolo Bonzini         return true;
307782a78c9SPaolo Bonzini 
308782a78c9SPaolo Bonzini     default:
309782a78c9SPaolo Bonzini         g_assert_not_reached();
310782a78c9SPaolo Bonzini     }
311f95f61c2SPaolo Bonzini }
312f95f61c2SPaolo Bonzini 
scsi_disk_req_check_error(SCSIDiskReq * r,int ret,bool acct_failed)3135b956f41SPaolo Bonzini static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed)
3145b956f41SPaolo Bonzini {
3155b956f41SPaolo Bonzini     if (r->req.io_canceled) {
3165b956f41SPaolo Bonzini         scsi_req_cancel_complete(&r->req);
3175b956f41SPaolo Bonzini         return true;
3185b956f41SPaolo Bonzini     }
3195b956f41SPaolo Bonzini 
320cfe08808SKevin Wolf     if (ret != 0) {
321f63c68bcSPaolo Bonzini         return scsi_handle_rw_error(r, ret, acct_failed);
3225b956f41SPaolo Bonzini     }
3235b956f41SPaolo Bonzini 
3245b956f41SPaolo Bonzini     return false;
3255b956f41SPaolo Bonzini }
3265b956f41SPaolo Bonzini 
scsi_aio_complete(void * opaque,int ret)32749ab747fSPaolo Bonzini static void scsi_aio_complete(void *opaque, int ret)
32849ab747fSPaolo Bonzini {
32949ab747fSPaolo Bonzini     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
33049ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
33149ab747fSPaolo Bonzini 
33210bcb0d9SStefan Hajnoczi     /* The request must only run in the BlockBackend's AioContext */
33310bcb0d9SStefan Hajnoczi     assert(blk_get_aio_context(s->qdev.conf.blk) ==
33410bcb0d9SStefan Hajnoczi            qemu_get_current_aio_context());
33510bcb0d9SStefan Hajnoczi 
33649ab747fSPaolo Bonzini     assert(r->req.aiocb != NULL);
33749ab747fSPaolo Bonzini     r->req.aiocb = NULL;
3387b7fc3d0SStefan Hajnoczi 
3395b956f41SPaolo Bonzini     if (scsi_disk_req_check_error(r, ret, true)) {
34049ab747fSPaolo Bonzini         goto done;
34149ab747fSPaolo Bonzini     }
34249ab747fSPaolo Bonzini 
343d7628080SAlberto Garcia     block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
34449ab747fSPaolo Bonzini     scsi_req_complete(&r->req, GOOD);
34549ab747fSPaolo Bonzini 
34649ab747fSPaolo Bonzini done:
34749ab747fSPaolo Bonzini     scsi_req_unref(&r->req);
34849ab747fSPaolo Bonzini }
34949ab747fSPaolo Bonzini 
scsi_is_cmd_fua(SCSICommand * cmd)35049ab747fSPaolo Bonzini static bool scsi_is_cmd_fua(SCSICommand *cmd)
35149ab747fSPaolo Bonzini {
35249ab747fSPaolo Bonzini     switch (cmd->buf[0]) {
35349ab747fSPaolo Bonzini     case READ_10:
35449ab747fSPaolo Bonzini     case READ_12:
35549ab747fSPaolo Bonzini     case READ_16:
35649ab747fSPaolo Bonzini     case WRITE_10:
35749ab747fSPaolo Bonzini     case WRITE_12:
35849ab747fSPaolo Bonzini     case WRITE_16:
35949ab747fSPaolo Bonzini         return (cmd->buf[1] & 8) != 0;
36049ab747fSPaolo Bonzini 
36149ab747fSPaolo Bonzini     case VERIFY_10:
36249ab747fSPaolo Bonzini     case VERIFY_12:
36349ab747fSPaolo Bonzini     case VERIFY_16:
36449ab747fSPaolo Bonzini     case WRITE_VERIFY_10:
36549ab747fSPaolo Bonzini     case WRITE_VERIFY_12:
36649ab747fSPaolo Bonzini     case WRITE_VERIFY_16:
36749ab747fSPaolo Bonzini         return true;
36849ab747fSPaolo Bonzini 
36949ab747fSPaolo Bonzini     case READ_6:
37049ab747fSPaolo Bonzini     case WRITE_6:
37149ab747fSPaolo Bonzini     default:
37249ab747fSPaolo Bonzini         return false;
37349ab747fSPaolo Bonzini     }
37449ab747fSPaolo Bonzini }
37549ab747fSPaolo Bonzini 
scsi_write_do_fua(SCSIDiskReq * r)37649ab747fSPaolo Bonzini static void scsi_write_do_fua(SCSIDiskReq *r)
37749ab747fSPaolo Bonzini {
37849ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
37949ab747fSPaolo Bonzini 
3805fd2b563SPaolo Bonzini     assert(r->req.aiocb == NULL);
3815b956f41SPaolo Bonzini     assert(!r->req.io_canceled);
38249ab747fSPaolo Bonzini 
38394f8ba11SPaolo Bonzini     if (r->need_fua_emulation) {
3844be74634SMarkus Armbruster         block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
3855366d0c8SBenoît Canet                          BLOCK_ACCT_FLUSH);
3864be74634SMarkus Armbruster         r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r);
38749ab747fSPaolo Bonzini         return;
38849ab747fSPaolo Bonzini     }
38949ab747fSPaolo Bonzini 
39049ab747fSPaolo Bonzini     scsi_req_complete(&r->req, GOOD);
39149ab747fSPaolo Bonzini     scsi_req_unref(&r->req);
39249ab747fSPaolo Bonzini }
39349ab747fSPaolo Bonzini 
scsi_dma_complete_noio(SCSIDiskReq * r,int ret)3945fd2b563SPaolo Bonzini static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret)
39549ab747fSPaolo Bonzini {
3965fd2b563SPaolo Bonzini     assert(r->req.aiocb == NULL);
397cfe08808SKevin Wolf     if (scsi_disk_req_check_error(r, ret, ret > 0)) {
39849ab747fSPaolo Bonzini         goto done;
39949ab747fSPaolo Bonzini     }
40049ab747fSPaolo Bonzini 
40149ab747fSPaolo Bonzini     r->sector += r->sector_count;
40249ab747fSPaolo Bonzini     r->sector_count = 0;
40349ab747fSPaolo Bonzini     if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
40449ab747fSPaolo Bonzini         scsi_write_do_fua(r);
40549ab747fSPaolo Bonzini         return;
40649ab747fSPaolo Bonzini     } else {
40749ab747fSPaolo Bonzini         scsi_req_complete(&r->req, GOOD);
40849ab747fSPaolo Bonzini     }
40949ab747fSPaolo Bonzini 
41049ab747fSPaolo Bonzini done:
41149ab747fSPaolo Bonzini     scsi_req_unref(&r->req);
41249ab747fSPaolo Bonzini }
41349ab747fSPaolo Bonzini 
4148a049562SKevin Wolf /* May not be called in all error cases, don't rely on cleanup here */
scsi_dma_complete(void * opaque,int ret)415ef8489d4SPaolo Bonzini static void scsi_dma_complete(void *opaque, int ret)
416ef8489d4SPaolo Bonzini {
417ef8489d4SPaolo Bonzini     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
4185fd2b563SPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
419ef8489d4SPaolo Bonzini 
420ef8489d4SPaolo Bonzini     assert(r->req.aiocb != NULL);
4215fd2b563SPaolo Bonzini     r->req.aiocb = NULL;
4225fd2b563SPaolo Bonzini 
423cfe08808SKevin Wolf     /* ret > 0 is accounted for in scsi_disk_req_check_error() */
424d7628080SAlberto Garcia     if (ret < 0) {
425d7628080SAlberto Garcia         block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
426cfe08808SKevin Wolf     } else if (ret == 0) {
4275fd2b563SPaolo Bonzini         block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
428d7628080SAlberto Garcia     }
4295fd2b563SPaolo Bonzini     scsi_dma_complete_noio(r, ret);
430ef8489d4SPaolo Bonzini }
431ef8489d4SPaolo Bonzini 
scsi_read_complete_noio(SCSIDiskReq * r,int ret)4321505421aSZhengui Li static void scsi_read_complete_noio(SCSIDiskReq *r, int ret)
43349ab747fSPaolo Bonzini {
43410bcb0d9SStefan Hajnoczi     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
4351505421aSZhengui Li     uint32_t n;
43649ab747fSPaolo Bonzini 
43710bcb0d9SStefan Hajnoczi     /* The request must only run in the BlockBackend's AioContext */
43810bcb0d9SStefan Hajnoczi     assert(blk_get_aio_context(s->qdev.conf.blk) ==
43910bcb0d9SStefan Hajnoczi            qemu_get_current_aio_context());
44010bcb0d9SStefan Hajnoczi 
4411505421aSZhengui Li     assert(r->req.aiocb == NULL);
442cfe08808SKevin Wolf     if (scsi_disk_req_check_error(r, ret, ret > 0)) {
44349ab747fSPaolo Bonzini         goto done;
44449ab747fSPaolo Bonzini     }
44549ab747fSPaolo Bonzini 
4463dc516bfSPhilippe Mathieu-Daudé     n = r->qiov.size / BDRV_SECTOR_SIZE;
44749ab747fSPaolo Bonzini     r->sector += n;
44849ab747fSPaolo Bonzini     r->sector_count -= n;
44949ab747fSPaolo Bonzini     scsi_req_data(&r->req, r->qiov.size);
45049ab747fSPaolo Bonzini 
45149ab747fSPaolo Bonzini done:
45249ab747fSPaolo Bonzini     scsi_req_unref(&r->req);
4531505421aSZhengui Li }
4541505421aSZhengui Li 
4558a049562SKevin Wolf /* May not be called in all error cases, don't rely on cleanup here */
scsi_read_complete(void * opaque,int ret)4561505421aSZhengui Li static void scsi_read_complete(void *opaque, int ret)
4571505421aSZhengui Li {
4581505421aSZhengui Li     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
4591505421aSZhengui Li     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
4601505421aSZhengui Li 
4611505421aSZhengui Li     assert(r->req.aiocb != NULL);
4621505421aSZhengui Li     r->req.aiocb = NULL;
4631505421aSZhengui Li 
464cfe08808SKevin Wolf     /* ret > 0 is accounted for in scsi_disk_req_check_error() */
4651505421aSZhengui Li     if (ret < 0) {
4661505421aSZhengui Li         block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
467cfe08808SKevin Wolf     } else if (ret == 0) {
4681505421aSZhengui Li         block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
4691505421aSZhengui Li         trace_scsi_disk_read_complete(r->req.tag, r->qiov.size);
4701505421aSZhengui Li     }
4711505421aSZhengui Li     scsi_read_complete_noio(r, ret);
47249ab747fSPaolo Bonzini }
47349ab747fSPaolo Bonzini 
47449ab747fSPaolo Bonzini /* Actually issue a read to the block device.  */
scsi_do_read(SCSIDiskReq * r,int ret)4755fd2b563SPaolo Bonzini static void scsi_do_read(SCSIDiskReq *r, int ret)
47649ab747fSPaolo Bonzini {
47749ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
478fcaafb10SPaolo Bonzini     SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
47949ab747fSPaolo Bonzini 
4805fd2b563SPaolo Bonzini     assert (r->req.aiocb == NULL);
4815b956f41SPaolo Bonzini     if (scsi_disk_req_check_error(r, ret, false)) {
48249ab747fSPaolo Bonzini         goto done;
48349ab747fSPaolo Bonzini     }
48449ab747fSPaolo Bonzini 
48549ab747fSPaolo Bonzini     /* The request is used as the AIO opaque value, so add a ref.  */
48649ab747fSPaolo Bonzini     scsi_req_ref(&r->req);
48749ab747fSPaolo Bonzini 
48849ab747fSPaolo Bonzini     if (r->req.sg) {
4894be74634SMarkus Armbruster         dma_acct_start(s->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_READ);
4905f412602SPhilippe Mathieu-Daudé         r->req.residual -= r->req.sg->size;
491fcaafb10SPaolo Bonzini         r->req.aiocb = dma_blk_io(blk_get_aio_context(s->qdev.conf.blk),
492fcaafb10SPaolo Bonzini                                   r->req.sg, r->sector << BDRV_SECTOR_BITS,
49399868af3SMark Cave-Ayland                                   BDRV_SECTOR_SIZE,
494fcaafb10SPaolo Bonzini                                   sdc->dma_readv, r, scsi_dma_complete, r,
495fcaafb10SPaolo Bonzini                                   DMA_DIRECTION_FROM_DEVICE);
49649ab747fSPaolo Bonzini     } else {
49703c90063SEric Blake         scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
4984be74634SMarkus Armbruster         block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
49903c90063SEric Blake                          r->qiov.size, BLOCK_ACCT_READ);
500890e48d7SMark Cave-Ayland         r->req.aiocb = sdc->dma_readv(r->sector << BDRV_SECTOR_BITS, &r->qiov,
501fcaafb10SPaolo Bonzini                                       scsi_read_complete, r, r);
50249ab747fSPaolo Bonzini     }
50349ab747fSPaolo Bonzini 
50449ab747fSPaolo Bonzini done:
50549ab747fSPaolo Bonzini     scsi_req_unref(&r->req);
50649ab747fSPaolo Bonzini }
50749ab747fSPaolo Bonzini 
scsi_do_read_cb(void * opaque,int ret)5085fd2b563SPaolo Bonzini static void scsi_do_read_cb(void *opaque, int ret)
5095fd2b563SPaolo Bonzini {
5105fd2b563SPaolo Bonzini     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
5115fd2b563SPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
5125fd2b563SPaolo Bonzini 
5135fd2b563SPaolo Bonzini     assert (r->req.aiocb != NULL);
5145fd2b563SPaolo Bonzini     r->req.aiocb = NULL;
5155fd2b563SPaolo Bonzini 
516d7628080SAlberto Garcia     if (ret < 0) {
517d7628080SAlberto Garcia         block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
518d7628080SAlberto Garcia     } else {
5195fd2b563SPaolo Bonzini         block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
520d7628080SAlberto Garcia     }
5215fd2b563SPaolo Bonzini     scsi_do_read(opaque, ret);
5225fd2b563SPaolo Bonzini }
5235fd2b563SPaolo Bonzini 
52449ab747fSPaolo Bonzini /* Read more data from scsi device into buffer.  */
scsi_read_data(SCSIRequest * req)52549ab747fSPaolo Bonzini static void scsi_read_data(SCSIRequest *req)
52649ab747fSPaolo Bonzini {
52749ab747fSPaolo Bonzini     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
52849ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
52949ab747fSPaolo Bonzini     bool first;
53049ab747fSPaolo Bonzini 
53159ee9500SLaurent Vivier     trace_scsi_disk_read_data_count(r->sector_count);
53249ab747fSPaolo Bonzini     if (r->sector_count == 0) {
53349ab747fSPaolo Bonzini         /* This also clears the sense buffer for REQUEST SENSE.  */
53449ab747fSPaolo Bonzini         scsi_req_complete(&r->req, GOOD);
53549ab747fSPaolo Bonzini         return;
53649ab747fSPaolo Bonzini     }
53749ab747fSPaolo Bonzini 
53849ab747fSPaolo Bonzini     /* No data transfer may already be in progress */
53949ab747fSPaolo Bonzini     assert(r->req.aiocb == NULL);
54049ab747fSPaolo Bonzini 
54149ab747fSPaolo Bonzini     /* The request is used as the AIO opaque value, so add a ref.  */
54249ab747fSPaolo Bonzini     scsi_req_ref(&r->req);
54349ab747fSPaolo Bonzini     if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
54459ee9500SLaurent Vivier         trace_scsi_disk_read_data_invalid();
5451505421aSZhengui Li         scsi_read_complete_noio(r, -EINVAL);
54649ab747fSPaolo Bonzini         return;
54749ab747fSPaolo Bonzini     }
54849ab747fSPaolo Bonzini 
549cd723b85SFam Zheng     if (!blk_is_available(req->dev->conf.blk)) {
5501505421aSZhengui Li         scsi_read_complete_noio(r, -ENOMEDIUM);
55149ab747fSPaolo Bonzini         return;
55249ab747fSPaolo Bonzini     }
55349ab747fSPaolo Bonzini 
55449ab747fSPaolo Bonzini     first = !r->started;
55549ab747fSPaolo Bonzini     r->started = true;
55694f8ba11SPaolo Bonzini     if (first && r->need_fua_emulation) {
5574be74634SMarkus Armbruster         block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
5585366d0c8SBenoît Canet                          BLOCK_ACCT_FLUSH);
5595fd2b563SPaolo Bonzini         r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_do_read_cb, r);
56049ab747fSPaolo Bonzini     } else {
56149ab747fSPaolo Bonzini         scsi_do_read(r, 0);
56249ab747fSPaolo Bonzini     }
56349ab747fSPaolo Bonzini }
56449ab747fSPaolo Bonzini 
scsi_write_complete_noio(SCSIDiskReq * r,int ret)5655fd2b563SPaolo Bonzini static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
56649ab747fSPaolo Bonzini {
56710bcb0d9SStefan Hajnoczi     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
56849ab747fSPaolo Bonzini     uint32_t n;
56949ab747fSPaolo Bonzini 
57010bcb0d9SStefan Hajnoczi     /* The request must only run in the BlockBackend's AioContext */
57110bcb0d9SStefan Hajnoczi     assert(blk_get_aio_context(s->qdev.conf.blk) ==
57210bcb0d9SStefan Hajnoczi            qemu_get_current_aio_context());
57310bcb0d9SStefan Hajnoczi 
5745fd2b563SPaolo Bonzini     assert (r->req.aiocb == NULL);
575cfe08808SKevin Wolf     if (scsi_disk_req_check_error(r, ret, ret > 0)) {
57649ab747fSPaolo Bonzini         goto done;
57749ab747fSPaolo Bonzini     }
57849ab747fSPaolo Bonzini 
5793dc516bfSPhilippe Mathieu-Daudé     n = r->qiov.size / BDRV_SECTOR_SIZE;
58049ab747fSPaolo Bonzini     r->sector += n;
58149ab747fSPaolo Bonzini     r->sector_count -= n;
58249ab747fSPaolo Bonzini     if (r->sector_count == 0) {
58349ab747fSPaolo Bonzini         scsi_write_do_fua(r);
58449ab747fSPaolo Bonzini         return;
58549ab747fSPaolo Bonzini     } else {
58649ab747fSPaolo Bonzini         scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
58759ee9500SLaurent Vivier         trace_scsi_disk_write_complete_noio(r->req.tag, r->qiov.size);
58849ab747fSPaolo Bonzini         scsi_req_data(&r->req, r->qiov.size);
58949ab747fSPaolo Bonzini     }
59049ab747fSPaolo Bonzini 
59149ab747fSPaolo Bonzini done:
59249ab747fSPaolo Bonzini     scsi_req_unref(&r->req);
59349ab747fSPaolo Bonzini }
59449ab747fSPaolo Bonzini 
5958a049562SKevin Wolf /* May not be called in all error cases, don't rely on cleanup here */
scsi_write_complete(void * opaque,int ret)5965fd2b563SPaolo Bonzini static void scsi_write_complete(void * opaque, int ret)
5975fd2b563SPaolo Bonzini {
5985fd2b563SPaolo Bonzini     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
5995fd2b563SPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
6005fd2b563SPaolo Bonzini 
6015fd2b563SPaolo Bonzini     assert (r->req.aiocb != NULL);
6025fd2b563SPaolo Bonzini     r->req.aiocb = NULL;
6035fd2b563SPaolo Bonzini 
604cfe08808SKevin Wolf     /* ret > 0 is accounted for in scsi_disk_req_check_error() */
605d7628080SAlberto Garcia     if (ret < 0) {
606d7628080SAlberto Garcia         block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
607cfe08808SKevin Wolf     } else if (ret == 0) {
6085fd2b563SPaolo Bonzini         block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
609d7628080SAlberto Garcia     }
6105fd2b563SPaolo Bonzini     scsi_write_complete_noio(r, ret);
6115fd2b563SPaolo Bonzini }
6125fd2b563SPaolo Bonzini 
scsi_write_data(SCSIRequest * req)61349ab747fSPaolo Bonzini static void scsi_write_data(SCSIRequest *req)
61449ab747fSPaolo Bonzini {
61549ab747fSPaolo Bonzini     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
61649ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
617fcaafb10SPaolo Bonzini     SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
61849ab747fSPaolo Bonzini 
61949ab747fSPaolo Bonzini     /* No data transfer may already be in progress */
62049ab747fSPaolo Bonzini     assert(r->req.aiocb == NULL);
62149ab747fSPaolo Bonzini 
62249ab747fSPaolo Bonzini     /* The request is used as the AIO opaque value, so add a ref.  */
62349ab747fSPaolo Bonzini     scsi_req_ref(&r->req);
62449ab747fSPaolo Bonzini     if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
62559ee9500SLaurent Vivier         trace_scsi_disk_write_data_invalid();
6265fd2b563SPaolo Bonzini         scsi_write_complete_noio(r, -EINVAL);
62749ab747fSPaolo Bonzini         return;
62849ab747fSPaolo Bonzini     }
62949ab747fSPaolo Bonzini 
63049ab747fSPaolo Bonzini     if (!r->req.sg && !r->qiov.size) {
63149ab747fSPaolo Bonzini         /* Called for the first time.  Ask the driver to send us more data.  */
63249ab747fSPaolo Bonzini         r->started = true;
6335fd2b563SPaolo Bonzini         scsi_write_complete_noio(r, 0);
63449ab747fSPaolo Bonzini         return;
63549ab747fSPaolo Bonzini     }
636cd723b85SFam Zheng     if (!blk_is_available(req->dev->conf.blk)) {
6375fd2b563SPaolo Bonzini         scsi_write_complete_noio(r, -ENOMEDIUM);
63849ab747fSPaolo Bonzini         return;
63949ab747fSPaolo Bonzini     }
64049ab747fSPaolo Bonzini 
64149ab747fSPaolo Bonzini     if (r->req.cmd.buf[0] == VERIFY_10 || r->req.cmd.buf[0] == VERIFY_12 ||
64249ab747fSPaolo Bonzini         r->req.cmd.buf[0] == VERIFY_16) {
64349ab747fSPaolo Bonzini         if (r->req.sg) {
644ef8489d4SPaolo Bonzini             scsi_dma_complete_noio(r, 0);
64549ab747fSPaolo Bonzini         } else {
6465fd2b563SPaolo Bonzini             scsi_write_complete_noio(r, 0);
64749ab747fSPaolo Bonzini         }
64849ab747fSPaolo Bonzini         return;
64949ab747fSPaolo Bonzini     }
65049ab747fSPaolo Bonzini 
65149ab747fSPaolo Bonzini     if (r->req.sg) {
6524be74634SMarkus Armbruster         dma_acct_start(s->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_WRITE);
6535f412602SPhilippe Mathieu-Daudé         r->req.residual -= r->req.sg->size;
654fcaafb10SPaolo Bonzini         r->req.aiocb = dma_blk_io(blk_get_aio_context(s->qdev.conf.blk),
655fcaafb10SPaolo Bonzini                                   r->req.sg, r->sector << BDRV_SECTOR_BITS,
65699868af3SMark Cave-Ayland                                   BDRV_SECTOR_SIZE,
657fcaafb10SPaolo Bonzini                                   sdc->dma_writev, r, scsi_dma_complete, r,
658fcaafb10SPaolo Bonzini                                   DMA_DIRECTION_TO_DEVICE);
65949ab747fSPaolo Bonzini     } else {
6604be74634SMarkus Armbruster         block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
66103c90063SEric Blake                          r->qiov.size, BLOCK_ACCT_WRITE);
662fcaafb10SPaolo Bonzini         r->req.aiocb = sdc->dma_writev(r->sector << BDRV_SECTOR_BITS, &r->qiov,
663fcaafb10SPaolo Bonzini                                        scsi_write_complete, r, r);
66449ab747fSPaolo Bonzini     }
66549ab747fSPaolo Bonzini }
66649ab747fSPaolo Bonzini 
66749ab747fSPaolo Bonzini /* Return a pointer to the data buffer.  */
scsi_get_buf(SCSIRequest * req)66849ab747fSPaolo Bonzini static uint8_t *scsi_get_buf(SCSIRequest *req)
66949ab747fSPaolo Bonzini {
67049ab747fSPaolo Bonzini     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
67149ab747fSPaolo Bonzini 
67249ab747fSPaolo Bonzini     return (uint8_t *)r->iov.iov_base;
67349ab747fSPaolo Bonzini }
67449ab747fSPaolo Bonzini 
scsi_disk_emulate_vpd_page(SCSIRequest * req,uint8_t * outbuf)6753d4a8bf0SPaolo Bonzini static int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf)
67649ab747fSPaolo Bonzini {
67749ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
67849ab747fSPaolo Bonzini     uint8_t page_code = req->cmd.buf[2];
6790a96ca24SDaniel Henrique Barboza     int start, buflen = 0;
68049ab747fSPaolo Bonzini 
68149ab747fSPaolo Bonzini     outbuf[buflen++] = s->qdev.type & 0x1f;
6820a96ca24SDaniel Henrique Barboza     outbuf[buflen++] = page_code;
68349ab747fSPaolo Bonzini     outbuf[buflen++] = 0x00;
68449ab747fSPaolo Bonzini     outbuf[buflen++] = 0x00;
68549ab747fSPaolo Bonzini     start = buflen;
68649ab747fSPaolo Bonzini 
68749ab747fSPaolo Bonzini     switch (page_code) {
68849ab747fSPaolo Bonzini     case 0x00: /* Supported page codes, mandatory */
68949ab747fSPaolo Bonzini     {
69059ee9500SLaurent Vivier         trace_scsi_disk_emulate_vpd_page_00(req->cmd.xfer);
6910a96ca24SDaniel Henrique Barboza         outbuf[buflen++] = 0x00; /* list of supported pages (this page) */
69249ab747fSPaolo Bonzini         if (s->serial) {
6930a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0x80; /* unit serial number */
69449ab747fSPaolo Bonzini         }
6950a96ca24SDaniel Henrique Barboza         outbuf[buflen++] = 0x83; /* device identification */
69649ab747fSPaolo Bonzini         if (s->qdev.type == TYPE_DISK) {
6970a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0xb0; /* block limits */
698070f8009SDaniel P. Berrange             outbuf[buflen++] = 0xb1; /* block device characteristics */
6990a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0xb2; /* thin provisioning */
70049ab747fSPaolo Bonzini         }
70149ab747fSPaolo Bonzini         break;
70249ab747fSPaolo Bonzini     }
70349ab747fSPaolo Bonzini     case 0x80: /* Device serial number, optional */
70449ab747fSPaolo Bonzini     {
70549ab747fSPaolo Bonzini         int l;
70649ab747fSPaolo Bonzini 
70749ab747fSPaolo Bonzini         if (!s->serial) {
70859ee9500SLaurent Vivier             trace_scsi_disk_emulate_vpd_page_80_not_supported();
70949ab747fSPaolo Bonzini             return -1;
71049ab747fSPaolo Bonzini         }
71149ab747fSPaolo Bonzini 
71249ab747fSPaolo Bonzini         l = strlen(s->serial);
71375997e18SKevin Wolf         if (l > MAX_SERIAL_LEN) {
71475997e18SKevin Wolf             l = MAX_SERIAL_LEN;
71549ab747fSPaolo Bonzini         }
71649ab747fSPaolo Bonzini 
71759ee9500SLaurent Vivier         trace_scsi_disk_emulate_vpd_page_80(req->cmd.xfer);
71849ab747fSPaolo Bonzini         memcpy(outbuf + buflen, s->serial, l);
71949ab747fSPaolo Bonzini         buflen += l;
72049ab747fSPaolo Bonzini         break;
72149ab747fSPaolo Bonzini     }
72249ab747fSPaolo Bonzini 
72349ab747fSPaolo Bonzini     case 0x83: /* Device identification page, mandatory */
72449ab747fSPaolo Bonzini     {
7257471a649SKevin Wolf         int id_len = s->device_id ? MIN(strlen(s->device_id), 255 - 8) : 0;
72649ab747fSPaolo Bonzini 
72759ee9500SLaurent Vivier         trace_scsi_disk_emulate_vpd_page_83(req->cmd.xfer);
72849ab747fSPaolo Bonzini 
729a8f58afcSKevin Wolf         if (id_len) {
7300a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0x2; /* ASCII */
7310a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0;   /* not officially assigned */
7320a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0;   /* reserved */
7330a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = id_len; /* length of data following */
7347471a649SKevin Wolf             memcpy(outbuf + buflen, s->device_id, id_len);
73549ab747fSPaolo Bonzini             buflen += id_len;
736a8f58afcSKevin Wolf         }
73749ab747fSPaolo Bonzini 
7382ecab408SPaolo Bonzini         if (s->qdev.wwn) {
7390a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0x1; /* Binary */
7400a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0x3; /* NAA */
7410a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0;   /* reserved */
74249ab747fSPaolo Bonzini             outbuf[buflen++] = 8;
7432ecab408SPaolo Bonzini             stq_be_p(&outbuf[buflen], s->qdev.wwn);
74449ab747fSPaolo Bonzini             buflen += 8;
74549ab747fSPaolo Bonzini         }
74664cc2284SRoland Dreier 
7472ecab408SPaolo Bonzini         if (s->qdev.port_wwn) {
7480a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0x61; /* SAS / Binary */
7490a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0x93; /* PIV / Target port / NAA */
7500a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0;    /* reserved */
75164cc2284SRoland Dreier             outbuf[buflen++] = 8;
7522ecab408SPaolo Bonzini             stq_be_p(&outbuf[buflen], s->qdev.port_wwn);
75364cc2284SRoland Dreier             buflen += 8;
75464cc2284SRoland Dreier         }
75564cc2284SRoland Dreier 
75664cc2284SRoland Dreier         if (s->port_index) {
7570a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0x61; /* SAS / Binary */
7580a96ca24SDaniel Henrique Barboza 
7590a96ca24SDaniel Henrique Barboza             /* PIV/Target port/relative target port */
7600a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0x94;
7610a96ca24SDaniel Henrique Barboza 
7620a96ca24SDaniel Henrique Barboza             outbuf[buflen++] = 0;    /* reserved */
76364cc2284SRoland Dreier             outbuf[buflen++] = 4;
76464cc2284SRoland Dreier             stw_be_p(&outbuf[buflen + 2], s->port_index);
76564cc2284SRoland Dreier             buflen += 4;
76664cc2284SRoland Dreier         }
76749ab747fSPaolo Bonzini         break;
76849ab747fSPaolo Bonzini     }
76949ab747fSPaolo Bonzini     case 0xb0: /* block limits */
77049ab747fSPaolo Bonzini     {
7713d4a8bf0SPaolo Bonzini         SCSIBlockLimits bl = {};
77249ab747fSPaolo Bonzini 
77349ab747fSPaolo Bonzini         if (s->qdev.type == TYPE_ROM) {
77459ee9500SLaurent Vivier             trace_scsi_disk_emulate_vpd_page_b0_not_supported();
77549ab747fSPaolo Bonzini             return -1;
77649ab747fSPaolo Bonzini         }
7773d4a8bf0SPaolo Bonzini         bl.wsnz = 1;
7783d4a8bf0SPaolo Bonzini         bl.unmap_sectors =
7793d4a8bf0SPaolo Bonzini             s->qdev.conf.discard_granularity / s->qdev.blocksize;
7803d4a8bf0SPaolo Bonzini         bl.min_io_size =
7813d4a8bf0SPaolo Bonzini             s->qdev.conf.min_io_size / s->qdev.blocksize;
7823d4a8bf0SPaolo Bonzini         bl.opt_io_size =
7833d4a8bf0SPaolo Bonzini             s->qdev.conf.opt_io_size / s->qdev.blocksize;
7843d4a8bf0SPaolo Bonzini         bl.max_unmap_sectors =
7853d4a8bf0SPaolo Bonzini             s->max_unmap_size / s->qdev.blocksize;
7863d4a8bf0SPaolo Bonzini         bl.max_io_sectors =
7873d4a8bf0SPaolo Bonzini             s->max_io_size / s->qdev.blocksize;
7883d4a8bf0SPaolo Bonzini         /* 255 descriptors fit in 4 KiB with an 8-byte header */
7893d4a8bf0SPaolo Bonzini         bl.max_unmap_descr = 255;
7903d4a8bf0SPaolo Bonzini 
791d082d16aSDaniel Henrique Barboza         if (s->qdev.type == TYPE_DISK) {
792d082d16aSDaniel Henrique Barboza             int max_transfer_blk = blk_get_max_transfer(s->qdev.conf.blk);
793d082d16aSDaniel Henrique Barboza             int max_io_sectors_blk =
794d082d16aSDaniel Henrique Barboza                 max_transfer_blk / s->qdev.blocksize;
795d082d16aSDaniel Henrique Barboza 
7963d4a8bf0SPaolo Bonzini             bl.max_io_sectors =
7973d4a8bf0SPaolo Bonzini                 MIN_NON_ZERO(max_io_sectors_blk, bl.max_io_sectors);
79837c51741SFam Zheng         }
7993d4a8bf0SPaolo Bonzini         buflen += scsi_emulate_block_limits(outbuf + buflen, &bl);
80049ab747fSPaolo Bonzini         break;
80149ab747fSPaolo Bonzini     }
802070f8009SDaniel P. Berrange     case 0xb1: /* block device characteristics */
803070f8009SDaniel P. Berrange     {
804740842c9SDaniel Henrique Barboza         buflen = 0x40;
805070f8009SDaniel P. Berrange         outbuf[4] = (s->rotation_rate >> 8) & 0xff;
806070f8009SDaniel P. Berrange         outbuf[5] = s->rotation_rate & 0xff;
807740842c9SDaniel Henrique Barboza         outbuf[6] = 0; /* PRODUCT TYPE */
808740842c9SDaniel Henrique Barboza         outbuf[7] = 0; /* WABEREQ | WACEREQ | NOMINAL FORM FACTOR */
809740842c9SDaniel Henrique Barboza         outbuf[8] = 0; /* VBULS */
810070f8009SDaniel P. Berrange         break;
811070f8009SDaniel P. Berrange     }
81249ab747fSPaolo Bonzini     case 0xb2: /* thin provisioning */
81349ab747fSPaolo Bonzini     {
81449ab747fSPaolo Bonzini         buflen = 8;
81549ab747fSPaolo Bonzini         outbuf[4] = 0;
81649ab747fSPaolo Bonzini         outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */
81749ab747fSPaolo Bonzini         outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
81849ab747fSPaolo Bonzini         outbuf[7] = 0;
81949ab747fSPaolo Bonzini         break;
82049ab747fSPaolo Bonzini     }
82149ab747fSPaolo Bonzini     default:
82249ab747fSPaolo Bonzini         return -1;
82349ab747fSPaolo Bonzini     }
82449ab747fSPaolo Bonzini     /* done with EVPD */
82549ab747fSPaolo Bonzini     assert(buflen - start <= 255);
82649ab747fSPaolo Bonzini     outbuf[start - 1] = buflen - start;
82749ab747fSPaolo Bonzini     return buflen;
82849ab747fSPaolo Bonzini }
82949ab747fSPaolo Bonzini 
scsi_disk_emulate_inquiry(SCSIRequest * req,uint8_t * outbuf)8300a96ca24SDaniel Henrique Barboza static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
8310a96ca24SDaniel Henrique Barboza {
8320a96ca24SDaniel Henrique Barboza     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
8330a96ca24SDaniel Henrique Barboza     int buflen = 0;
8340a96ca24SDaniel Henrique Barboza 
8350a96ca24SDaniel Henrique Barboza     if (req->cmd.buf[1] & 0x1) {
8360a96ca24SDaniel Henrique Barboza         /* Vital product data */
8370a96ca24SDaniel Henrique Barboza         return scsi_disk_emulate_vpd_page(req, outbuf);
8380a96ca24SDaniel Henrique Barboza     }
8390a96ca24SDaniel Henrique Barboza 
84049ab747fSPaolo Bonzini     /* Standard INQUIRY data */
84149ab747fSPaolo Bonzini     if (req->cmd.buf[2] != 0) {
84249ab747fSPaolo Bonzini         return -1;
84349ab747fSPaolo Bonzini     }
84449ab747fSPaolo Bonzini 
84549ab747fSPaolo Bonzini     /* PAGE CODE == 0 */
84649ab747fSPaolo Bonzini     buflen = req->cmd.xfer;
84749ab747fSPaolo Bonzini     if (buflen > SCSI_MAX_INQUIRY_LEN) {
84849ab747fSPaolo Bonzini         buflen = SCSI_MAX_INQUIRY_LEN;
84949ab747fSPaolo Bonzini     }
85049ab747fSPaolo Bonzini 
85149ab747fSPaolo Bonzini     outbuf[0] = s->qdev.type & 0x1f;
85249ab747fSPaolo Bonzini     outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0;
85349ab747fSPaolo Bonzini 
85449ab747fSPaolo Bonzini     strpadcpy((char *) &outbuf[16], 16, s->product, ' ');
85549ab747fSPaolo Bonzini     strpadcpy((char *) &outbuf[8], 8, s->vendor, ' ');
85649ab747fSPaolo Bonzini 
85749ab747fSPaolo Bonzini     memset(&outbuf[32], 0, 4);
85849ab747fSPaolo Bonzini     memcpy(&outbuf[32], s->version, MIN(4, strlen(s->version)));
85949ab747fSPaolo Bonzini     /*
86049ab747fSPaolo Bonzini      * We claim conformance to SPC-3, which is required for guests
86149ab747fSPaolo Bonzini      * to ask for modern features like READ CAPACITY(16) or the
86249ab747fSPaolo Bonzini      * block characteristics VPD page by default.  Not all of SPC-3
86349ab747fSPaolo Bonzini      * is actually implemented, but we're good enough.
86449ab747fSPaolo Bonzini      */
8652343be0dSPaolo Bonzini     outbuf[2] = s->qdev.default_scsi_version;
86649ab747fSPaolo Bonzini     outbuf[3] = 2 | 0x10; /* Format 2, HiSup */
86749ab747fSPaolo Bonzini 
86849ab747fSPaolo Bonzini     if (buflen > 36) {
86949ab747fSPaolo Bonzini         outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
87049ab747fSPaolo Bonzini     } else {
87149ab747fSPaolo Bonzini         /* If the allocation length of CDB is too small,
87249ab747fSPaolo Bonzini                the additional length is not adjusted */
87349ab747fSPaolo Bonzini         outbuf[4] = 36 - 5;
87449ab747fSPaolo Bonzini     }
87549ab747fSPaolo Bonzini 
87649ab747fSPaolo Bonzini     /* Sync data transfer and TCQ.  */
87749ab747fSPaolo Bonzini     outbuf[7] = 0x10 | (req->bus->info->tcq ? 0x02 : 0);
87849ab747fSPaolo Bonzini     return buflen;
87949ab747fSPaolo Bonzini }
88049ab747fSPaolo Bonzini 
media_is_dvd(SCSIDiskState * s)88149ab747fSPaolo Bonzini static inline bool media_is_dvd(SCSIDiskState *s)
88249ab747fSPaolo Bonzini {
88349ab747fSPaolo Bonzini     uint64_t nb_sectors;
88449ab747fSPaolo Bonzini     if (s->qdev.type != TYPE_ROM) {
88549ab747fSPaolo Bonzini         return false;
88649ab747fSPaolo Bonzini     }
887cd723b85SFam Zheng     if (!blk_is_available(s->qdev.conf.blk)) {
8887d99f4c1SMatthew Rosato         return false;
8897d99f4c1SMatthew Rosato     }
8904be74634SMarkus Armbruster     blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
89149ab747fSPaolo Bonzini     return nb_sectors > CD_MAX_SECTORS;
89249ab747fSPaolo Bonzini }
89349ab747fSPaolo Bonzini 
media_is_cd(SCSIDiskState * s)89449ab747fSPaolo Bonzini static inline bool media_is_cd(SCSIDiskState *s)
89549ab747fSPaolo Bonzini {
89649ab747fSPaolo Bonzini     uint64_t nb_sectors;
89749ab747fSPaolo Bonzini     if (s->qdev.type != TYPE_ROM) {
89849ab747fSPaolo Bonzini         return false;
89949ab747fSPaolo Bonzini     }
900cd723b85SFam Zheng     if (!blk_is_available(s->qdev.conf.blk)) {
9017d99f4c1SMatthew Rosato         return false;
9027d99f4c1SMatthew Rosato     }
9034be74634SMarkus Armbruster     blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
90449ab747fSPaolo Bonzini     return nb_sectors <= CD_MAX_SECTORS;
90549ab747fSPaolo Bonzini }
90649ab747fSPaolo Bonzini 
scsi_read_disc_information(SCSIDiskState * s,SCSIDiskReq * r,uint8_t * outbuf)90749ab747fSPaolo Bonzini static int scsi_read_disc_information(SCSIDiskState *s, SCSIDiskReq *r,
90849ab747fSPaolo Bonzini                                       uint8_t *outbuf)
90949ab747fSPaolo Bonzini {
91049ab747fSPaolo Bonzini     uint8_t type = r->req.cmd.buf[1] & 7;
91149ab747fSPaolo Bonzini 
91249ab747fSPaolo Bonzini     if (s->qdev.type != TYPE_ROM) {
91349ab747fSPaolo Bonzini         return -1;
91449ab747fSPaolo Bonzini     }
91549ab747fSPaolo Bonzini 
91649ab747fSPaolo Bonzini     /* Types 1/2 are only defined for Blu-Ray.  */
91749ab747fSPaolo Bonzini     if (type != 0) {
91849ab747fSPaolo Bonzini         scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
91949ab747fSPaolo Bonzini         return -1;
92049ab747fSPaolo Bonzini     }
92149ab747fSPaolo Bonzini 
92249ab747fSPaolo Bonzini     memset(outbuf, 0, 34);
92349ab747fSPaolo Bonzini     outbuf[1] = 32;
92449ab747fSPaolo Bonzini     outbuf[2] = 0xe; /* last session complete, disc finalized */
92549ab747fSPaolo Bonzini     outbuf[3] = 1;   /* first track on disc */
92649ab747fSPaolo Bonzini     outbuf[4] = 1;   /* # of sessions */
92749ab747fSPaolo Bonzini     outbuf[5] = 1;   /* first track of last session */
92849ab747fSPaolo Bonzini     outbuf[6] = 1;   /* last track of last session */
92949ab747fSPaolo Bonzini     outbuf[7] = 0x20; /* unrestricted use */
93049ab747fSPaolo Bonzini     outbuf[8] = 0x00; /* CD-ROM or DVD-ROM */
93149ab747fSPaolo Bonzini     /* 9-10-11: most significant byte corresponding bytes 4-5-6 */
93249ab747fSPaolo Bonzini     /* 12-23: not meaningful for CD-ROM or DVD-ROM */
93349ab747fSPaolo Bonzini     /* 24-31: disc bar code */
93449ab747fSPaolo Bonzini     /* 32: disc application code */
93549ab747fSPaolo Bonzini     /* 33: number of OPC tables */
93649ab747fSPaolo Bonzini 
93749ab747fSPaolo Bonzini     return 34;
93849ab747fSPaolo Bonzini }
93949ab747fSPaolo Bonzini 
scsi_read_dvd_structure(SCSIDiskState * s,SCSIDiskReq * r,uint8_t * outbuf)94049ab747fSPaolo Bonzini static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
94149ab747fSPaolo Bonzini                                    uint8_t *outbuf)
94249ab747fSPaolo Bonzini {
94349ab747fSPaolo Bonzini     static const int rds_caps_size[5] = {
94449ab747fSPaolo Bonzini         [0] = 2048 + 4,
94549ab747fSPaolo Bonzini         [1] = 4 + 4,
94649ab747fSPaolo Bonzini         [3] = 188 + 4,
94749ab747fSPaolo Bonzini         [4] = 2048 + 4,
94849ab747fSPaolo Bonzini     };
94949ab747fSPaolo Bonzini 
95049ab747fSPaolo Bonzini     uint8_t media = r->req.cmd.buf[1];
95149ab747fSPaolo Bonzini     uint8_t layer = r->req.cmd.buf[6];
95249ab747fSPaolo Bonzini     uint8_t format = r->req.cmd.buf[7];
95349ab747fSPaolo Bonzini     int size = -1;
95449ab747fSPaolo Bonzini 
95549ab747fSPaolo Bonzini     if (s->qdev.type != TYPE_ROM) {
95649ab747fSPaolo Bonzini         return -1;
95749ab747fSPaolo Bonzini     }
95849ab747fSPaolo Bonzini     if (media != 0) {
95949ab747fSPaolo Bonzini         scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
96049ab747fSPaolo Bonzini         return -1;
96149ab747fSPaolo Bonzini     }
96249ab747fSPaolo Bonzini 
96349ab747fSPaolo Bonzini     if (format != 0xff) {
964cd723b85SFam Zheng         if (!blk_is_available(s->qdev.conf.blk)) {
96549ab747fSPaolo Bonzini             scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
96649ab747fSPaolo Bonzini             return -1;
96749ab747fSPaolo Bonzini         }
96849ab747fSPaolo Bonzini         if (media_is_cd(s)) {
96949ab747fSPaolo Bonzini             scsi_check_condition(r, SENSE_CODE(INCOMPATIBLE_FORMAT));
97049ab747fSPaolo Bonzini             return -1;
97149ab747fSPaolo Bonzini         }
97249ab747fSPaolo Bonzini         if (format >= ARRAY_SIZE(rds_caps_size)) {
97349ab747fSPaolo Bonzini             return -1;
97449ab747fSPaolo Bonzini         }
97549ab747fSPaolo Bonzini         size = rds_caps_size[format];
97649ab747fSPaolo Bonzini         memset(outbuf, 0, size);
97749ab747fSPaolo Bonzini     }
97849ab747fSPaolo Bonzini 
97949ab747fSPaolo Bonzini     switch (format) {
98049ab747fSPaolo Bonzini     case 0x00: {
98149ab747fSPaolo Bonzini         /* Physical format information */
98249ab747fSPaolo Bonzini         uint64_t nb_sectors;
98349ab747fSPaolo Bonzini         if (layer != 0) {
98449ab747fSPaolo Bonzini             goto fail;
98549ab747fSPaolo Bonzini         }
9864be74634SMarkus Armbruster         blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
98749ab747fSPaolo Bonzini 
98849ab747fSPaolo Bonzini         outbuf[4] = 1;   /* DVD-ROM, part version 1 */
98949ab747fSPaolo Bonzini         outbuf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
99049ab747fSPaolo Bonzini         outbuf[6] = 1;   /* one layer, read-only (per MMC-2 spec) */
99149ab747fSPaolo Bonzini         outbuf[7] = 0;   /* default densities */
99249ab747fSPaolo Bonzini 
99349ab747fSPaolo Bonzini         stl_be_p(&outbuf[12], (nb_sectors >> 2) - 1); /* end sector */
99449ab747fSPaolo Bonzini         stl_be_p(&outbuf[16], (nb_sectors >> 2) - 1); /* l0 end sector */
99549ab747fSPaolo Bonzini         break;
99649ab747fSPaolo Bonzini     }
99749ab747fSPaolo Bonzini 
99849ab747fSPaolo Bonzini     case 0x01: /* DVD copyright information, all zeros */
99949ab747fSPaolo Bonzini         break;
100049ab747fSPaolo Bonzini 
100149ab747fSPaolo Bonzini     case 0x03: /* BCA information - invalid field for no BCA info */
100249ab747fSPaolo Bonzini         return -1;
100349ab747fSPaolo Bonzini 
100449ab747fSPaolo Bonzini     case 0x04: /* DVD disc manufacturing information, all zeros */
100549ab747fSPaolo Bonzini         break;
100649ab747fSPaolo Bonzini 
100749ab747fSPaolo Bonzini     case 0xff: { /* List capabilities */
100849ab747fSPaolo Bonzini         int i;
100949ab747fSPaolo Bonzini         size = 4;
101049ab747fSPaolo Bonzini         for (i = 0; i < ARRAY_SIZE(rds_caps_size); i++) {
101149ab747fSPaolo Bonzini             if (!rds_caps_size[i]) {
101249ab747fSPaolo Bonzini                 continue;
101349ab747fSPaolo Bonzini             }
101449ab747fSPaolo Bonzini             outbuf[size] = i;
101549ab747fSPaolo Bonzini             outbuf[size + 1] = 0x40; /* Not writable, readable */
101649ab747fSPaolo Bonzini             stw_be_p(&outbuf[size + 2], rds_caps_size[i]);
101749ab747fSPaolo Bonzini             size += 4;
101849ab747fSPaolo Bonzini         }
101949ab747fSPaolo Bonzini         break;
102049ab747fSPaolo Bonzini      }
102149ab747fSPaolo Bonzini 
102249ab747fSPaolo Bonzini     default:
102349ab747fSPaolo Bonzini         return -1;
102449ab747fSPaolo Bonzini     }
102549ab747fSPaolo Bonzini 
102649ab747fSPaolo Bonzini     /* Size of buffer, not including 2 byte size field */
102749ab747fSPaolo Bonzini     stw_be_p(outbuf, size - 2);
102849ab747fSPaolo Bonzini     return size;
102949ab747fSPaolo Bonzini 
103049ab747fSPaolo Bonzini fail:
103149ab747fSPaolo Bonzini     return -1;
103249ab747fSPaolo Bonzini }
103349ab747fSPaolo Bonzini 
scsi_event_status_media(SCSIDiskState * s,uint8_t * outbuf)103449ab747fSPaolo Bonzini static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
103549ab747fSPaolo Bonzini {
103649ab747fSPaolo Bonzini     uint8_t event_code, media_status;
103749ab747fSPaolo Bonzini 
103849ab747fSPaolo Bonzini     media_status = 0;
103949ab747fSPaolo Bonzini     if (s->tray_open) {
104049ab747fSPaolo Bonzini         media_status = MS_TRAY_OPEN;
10414be74634SMarkus Armbruster     } else if (blk_is_inserted(s->qdev.conf.blk)) {
104249ab747fSPaolo Bonzini         media_status = MS_MEDIA_PRESENT;
104349ab747fSPaolo Bonzini     }
104449ab747fSPaolo Bonzini 
104549ab747fSPaolo Bonzini     /* Event notification descriptor */
104649ab747fSPaolo Bonzini     event_code = MEC_NO_CHANGE;
104749ab747fSPaolo Bonzini     if (media_status != MS_TRAY_OPEN) {
104849ab747fSPaolo Bonzini         if (s->media_event) {
104949ab747fSPaolo Bonzini             event_code = MEC_NEW_MEDIA;
105049ab747fSPaolo Bonzini             s->media_event = false;
105149ab747fSPaolo Bonzini         } else if (s->eject_request) {
105249ab747fSPaolo Bonzini             event_code = MEC_EJECT_REQUESTED;
105349ab747fSPaolo Bonzini             s->eject_request = false;
105449ab747fSPaolo Bonzini         }
105549ab747fSPaolo Bonzini     }
105649ab747fSPaolo Bonzini 
105749ab747fSPaolo Bonzini     outbuf[0] = event_code;
105849ab747fSPaolo Bonzini     outbuf[1] = media_status;
105949ab747fSPaolo Bonzini 
106049ab747fSPaolo Bonzini     /* These fields are reserved, just clear them. */
106149ab747fSPaolo Bonzini     outbuf[2] = 0;
106249ab747fSPaolo Bonzini     outbuf[3] = 0;
106349ab747fSPaolo Bonzini     return 4;
106449ab747fSPaolo Bonzini }
106549ab747fSPaolo Bonzini 
scsi_get_event_status_notification(SCSIDiskState * s,SCSIDiskReq * r,uint8_t * outbuf)106649ab747fSPaolo Bonzini static int scsi_get_event_status_notification(SCSIDiskState *s, SCSIDiskReq *r,
106749ab747fSPaolo Bonzini                                               uint8_t *outbuf)
106849ab747fSPaolo Bonzini {
106949ab747fSPaolo Bonzini     int size;
107049ab747fSPaolo Bonzini     uint8_t *buf = r->req.cmd.buf;
107149ab747fSPaolo Bonzini     uint8_t notification_class_request = buf[4];
107249ab747fSPaolo Bonzini     if (s->qdev.type != TYPE_ROM) {
107349ab747fSPaolo Bonzini         return -1;
107449ab747fSPaolo Bonzini     }
107549ab747fSPaolo Bonzini     if ((buf[1] & 1) == 0) {
107649ab747fSPaolo Bonzini         /* asynchronous */
107749ab747fSPaolo Bonzini         return -1;
107849ab747fSPaolo Bonzini     }
107949ab747fSPaolo Bonzini 
108049ab747fSPaolo Bonzini     size = 4;
108149ab747fSPaolo Bonzini     outbuf[0] = outbuf[1] = 0;
108249ab747fSPaolo Bonzini     outbuf[3] = 1 << GESN_MEDIA; /* supported events */
108349ab747fSPaolo Bonzini     if (notification_class_request & (1 << GESN_MEDIA)) {
108449ab747fSPaolo Bonzini         outbuf[2] = GESN_MEDIA;
108549ab747fSPaolo Bonzini         size += scsi_event_status_media(s, &outbuf[size]);
108649ab747fSPaolo Bonzini     } else {
108749ab747fSPaolo Bonzini         outbuf[2] = 0x80;
108849ab747fSPaolo Bonzini     }
108949ab747fSPaolo Bonzini     stw_be_p(outbuf, size - 4);
109049ab747fSPaolo Bonzini     return size;
109149ab747fSPaolo Bonzini }
109249ab747fSPaolo Bonzini 
scsi_get_configuration(SCSIDiskState * s,uint8_t * outbuf)109349ab747fSPaolo Bonzini static int scsi_get_configuration(SCSIDiskState *s, uint8_t *outbuf)
109449ab747fSPaolo Bonzini {
109549ab747fSPaolo Bonzini     int current;
109649ab747fSPaolo Bonzini 
109749ab747fSPaolo Bonzini     if (s->qdev.type != TYPE_ROM) {
109849ab747fSPaolo Bonzini         return -1;
109949ab747fSPaolo Bonzini     }
11007d99f4c1SMatthew Rosato 
11017d99f4c1SMatthew Rosato     if (media_is_dvd(s)) {
11027d99f4c1SMatthew Rosato         current = MMC_PROFILE_DVD_ROM;
11037d99f4c1SMatthew Rosato     } else if (media_is_cd(s)) {
11047d99f4c1SMatthew Rosato         current = MMC_PROFILE_CD_ROM;
11057d99f4c1SMatthew Rosato     } else {
11067d99f4c1SMatthew Rosato         current = MMC_PROFILE_NONE;
11077d99f4c1SMatthew Rosato     }
11087d99f4c1SMatthew Rosato 
110949ab747fSPaolo Bonzini     memset(outbuf, 0, 40);
111049ab747fSPaolo Bonzini     stl_be_p(&outbuf[0], 36); /* Bytes after the data length field */
111149ab747fSPaolo Bonzini     stw_be_p(&outbuf[6], current);
111249ab747fSPaolo Bonzini     /* outbuf[8] - outbuf[19]: Feature 0 - Profile list */
111349ab747fSPaolo Bonzini     outbuf[10] = 0x03; /* persistent, current */
111449ab747fSPaolo Bonzini     outbuf[11] = 8; /* two profiles */
111549ab747fSPaolo Bonzini     stw_be_p(&outbuf[12], MMC_PROFILE_DVD_ROM);
111649ab747fSPaolo Bonzini     outbuf[14] = (current == MMC_PROFILE_DVD_ROM);
111749ab747fSPaolo Bonzini     stw_be_p(&outbuf[16], MMC_PROFILE_CD_ROM);
111849ab747fSPaolo Bonzini     outbuf[18] = (current == MMC_PROFILE_CD_ROM);
111949ab747fSPaolo Bonzini     /* outbuf[20] - outbuf[31]: Feature 1 - Core feature */
112049ab747fSPaolo Bonzini     stw_be_p(&outbuf[20], 1);
112149ab747fSPaolo Bonzini     outbuf[22] = 0x08 | 0x03; /* version 2, persistent, current */
112249ab747fSPaolo Bonzini     outbuf[23] = 8;
112349ab747fSPaolo Bonzini     stl_be_p(&outbuf[24], 1); /* SCSI */
112449ab747fSPaolo Bonzini     outbuf[28] = 1; /* DBE = 1, mandatory */
112549ab747fSPaolo Bonzini     /* outbuf[32] - outbuf[39]: Feature 3 - Removable media feature */
112649ab747fSPaolo Bonzini     stw_be_p(&outbuf[32], 3);
112749ab747fSPaolo Bonzini     outbuf[34] = 0x08 | 0x03; /* version 2, persistent, current */
112849ab747fSPaolo Bonzini     outbuf[35] = 4;
112949ab747fSPaolo Bonzini     outbuf[36] = 0x39; /* tray, load=1, eject=1, unlocked at powerup, lock=1 */
113049ab747fSPaolo Bonzini     /* TODO: Random readable, CD read, DVD read, drive serial number,
113149ab747fSPaolo Bonzini        power management */
113249ab747fSPaolo Bonzini     return 40;
113349ab747fSPaolo Bonzini }
113449ab747fSPaolo Bonzini 
scsi_emulate_mechanism_status(SCSIDiskState * s,uint8_t * outbuf)113549ab747fSPaolo Bonzini static int scsi_emulate_mechanism_status(SCSIDiskState *s, uint8_t *outbuf)
113649ab747fSPaolo Bonzini {
113749ab747fSPaolo Bonzini     if (s->qdev.type != TYPE_ROM) {
113849ab747fSPaolo Bonzini         return -1;
113949ab747fSPaolo Bonzini     }
114049ab747fSPaolo Bonzini     memset(outbuf, 0, 8);
114149ab747fSPaolo Bonzini     outbuf[5] = 1; /* CD-ROM */
114249ab747fSPaolo Bonzini     return 8;
114349ab747fSPaolo Bonzini }
114449ab747fSPaolo Bonzini 
mode_sense_page(SCSIDiskState * s,int page,uint8_t ** p_outbuf,int page_control)114549ab747fSPaolo Bonzini static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
114649ab747fSPaolo Bonzini                            int page_control)
114749ab747fSPaolo Bonzini {
114849ab747fSPaolo Bonzini     static const int mode_sense_valid[0x3f] = {
114909274de1SMark Cave-Ayland         [MODE_PAGE_VENDOR_SPECIFIC]        = (1 << TYPE_DISK) | (1 << TYPE_ROM),
115049ab747fSPaolo Bonzini         [MODE_PAGE_HD_GEOMETRY]            = (1 << TYPE_DISK),
115149ab747fSPaolo Bonzini         [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK),
115249ab747fSPaolo Bonzini         [MODE_PAGE_CACHING]                = (1 << TYPE_DISK) | (1 << TYPE_ROM),
115349ab747fSPaolo Bonzini         [MODE_PAGE_R_W_ERROR]              = (1 << TYPE_DISK) | (1 << TYPE_ROM),
115449ab747fSPaolo Bonzini         [MODE_PAGE_AUDIO_CTL]              = (1 << TYPE_ROM),
115549ab747fSPaolo Bonzini         [MODE_PAGE_CAPABILITIES]           = (1 << TYPE_ROM),
115609d37867SMark Cave-Ayland         [MODE_PAGE_APPLE_VENDOR]           = (1 << TYPE_ROM),
115749ab747fSPaolo Bonzini     };
115849ab747fSPaolo Bonzini 
115949ab747fSPaolo Bonzini     uint8_t *p = *p_outbuf + 2;
116049ab747fSPaolo Bonzini     int length;
116149ab747fSPaolo Bonzini 
1162b3af7fdfSMauro Matteo Cascella     assert(page < ARRAY_SIZE(mode_sense_valid));
116349ab747fSPaolo Bonzini     if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) {
116449ab747fSPaolo Bonzini         return -1;
116549ab747fSPaolo Bonzini     }
116649ab747fSPaolo Bonzini 
116749ab747fSPaolo Bonzini     /*
116849ab747fSPaolo Bonzini      * If Changeable Values are requested, a mask denoting those mode parameters
116949ab747fSPaolo Bonzini      * that are changeable shall be returned. As we currently don't support
117049ab747fSPaolo Bonzini      * parameter changes via MODE_SELECT all bits are returned set to zero.
117149ab747fSPaolo Bonzini      * The buffer was already menset to zero by the caller of this function.
117249ab747fSPaolo Bonzini      *
117349ab747fSPaolo Bonzini      * The offsets here are off by two compared to the descriptions in the
117449ab747fSPaolo Bonzini      * SCSI specs, because those include a 2-byte header.  This is unfortunate,
117549ab747fSPaolo Bonzini      * but it is done so that offsets are consistent within our implementation
117649ab747fSPaolo Bonzini      * of MODE SENSE and MODE SELECT.  MODE SELECT has to deal with both
117749ab747fSPaolo Bonzini      * 2-byte and 4-byte headers.
117849ab747fSPaolo Bonzini      */
117949ab747fSPaolo Bonzini     switch (page) {
118049ab747fSPaolo Bonzini     case MODE_PAGE_HD_GEOMETRY:
118149ab747fSPaolo Bonzini         length = 0x16;
118249ab747fSPaolo Bonzini         if (page_control == 1) { /* Changeable Values */
118349ab747fSPaolo Bonzini             break;
118449ab747fSPaolo Bonzini         }
118549ab747fSPaolo Bonzini         /* if a geometry hint is available, use it */
118649ab747fSPaolo Bonzini         p[0] = (s->qdev.conf.cyls >> 16) & 0xff;
118749ab747fSPaolo Bonzini         p[1] = (s->qdev.conf.cyls >> 8) & 0xff;
118849ab747fSPaolo Bonzini         p[2] = s->qdev.conf.cyls & 0xff;
118949ab747fSPaolo Bonzini         p[3] = s->qdev.conf.heads & 0xff;
119049ab747fSPaolo Bonzini         /* Write precomp start cylinder, disabled */
119149ab747fSPaolo Bonzini         p[4] = (s->qdev.conf.cyls >> 16) & 0xff;
119249ab747fSPaolo Bonzini         p[5] = (s->qdev.conf.cyls >> 8) & 0xff;
119349ab747fSPaolo Bonzini         p[6] = s->qdev.conf.cyls & 0xff;
119449ab747fSPaolo Bonzini         /* Reduced current start cylinder, disabled */
119549ab747fSPaolo Bonzini         p[7] = (s->qdev.conf.cyls >> 16) & 0xff;
119649ab747fSPaolo Bonzini         p[8] = (s->qdev.conf.cyls >> 8) & 0xff;
119749ab747fSPaolo Bonzini         p[9] = s->qdev.conf.cyls & 0xff;
119849ab747fSPaolo Bonzini         /* Device step rate [ns], 200ns */
119949ab747fSPaolo Bonzini         p[10] = 0;
120049ab747fSPaolo Bonzini         p[11] = 200;
120149ab747fSPaolo Bonzini         /* Landing zone cylinder */
120249ab747fSPaolo Bonzini         p[12] = 0xff;
120349ab747fSPaolo Bonzini         p[13] =  0xff;
120449ab747fSPaolo Bonzini         p[14] = 0xff;
120549ab747fSPaolo Bonzini         /* Medium rotation rate [rpm], 5400 rpm */
120649ab747fSPaolo Bonzini         p[18] = (5400 >> 8) & 0xff;
120749ab747fSPaolo Bonzini         p[19] = 5400 & 0xff;
120849ab747fSPaolo Bonzini         break;
120949ab747fSPaolo Bonzini 
121049ab747fSPaolo Bonzini     case MODE_PAGE_FLEXIBLE_DISK_GEOMETRY:
121149ab747fSPaolo Bonzini         length = 0x1e;
121249ab747fSPaolo Bonzini         if (page_control == 1) { /* Changeable Values */
121349ab747fSPaolo Bonzini             break;
121449ab747fSPaolo Bonzini         }
121549ab747fSPaolo Bonzini         /* Transfer rate [kbit/s], 5Mbit/s */
121649ab747fSPaolo Bonzini         p[0] = 5000 >> 8;
121749ab747fSPaolo Bonzini         p[1] = 5000 & 0xff;
121849ab747fSPaolo Bonzini         /* if a geometry hint is available, use it */
121949ab747fSPaolo Bonzini         p[2] = s->qdev.conf.heads & 0xff;
122049ab747fSPaolo Bonzini         p[3] = s->qdev.conf.secs & 0xff;
122149ab747fSPaolo Bonzini         p[4] = s->qdev.blocksize >> 8;
122249ab747fSPaolo Bonzini         p[6] = (s->qdev.conf.cyls >> 8) & 0xff;
122349ab747fSPaolo Bonzini         p[7] = s->qdev.conf.cyls & 0xff;
122449ab747fSPaolo Bonzini         /* Write precomp start cylinder, disabled */
122549ab747fSPaolo Bonzini         p[8] = (s->qdev.conf.cyls >> 8) & 0xff;
122649ab747fSPaolo Bonzini         p[9] = s->qdev.conf.cyls & 0xff;
122749ab747fSPaolo Bonzini         /* Reduced current start cylinder, disabled */
122849ab747fSPaolo Bonzini         p[10] = (s->qdev.conf.cyls >> 8) & 0xff;
122949ab747fSPaolo Bonzini         p[11] = s->qdev.conf.cyls & 0xff;
123049ab747fSPaolo Bonzini         /* Device step rate [100us], 100us */
123149ab747fSPaolo Bonzini         p[12] = 0;
123249ab747fSPaolo Bonzini         p[13] = 1;
123349ab747fSPaolo Bonzini         /* Device step pulse width [us], 1us */
123449ab747fSPaolo Bonzini         p[14] = 1;
123549ab747fSPaolo Bonzini         /* Device head settle delay [100us], 100us */
123649ab747fSPaolo Bonzini         p[15] = 0;
123749ab747fSPaolo Bonzini         p[16] = 1;
123849ab747fSPaolo Bonzini         /* Motor on delay [0.1s], 0.1s */
123949ab747fSPaolo Bonzini         p[17] = 1;
124049ab747fSPaolo Bonzini         /* Motor off delay [0.1s], 0.1s */
124149ab747fSPaolo Bonzini         p[18] = 1;
124249ab747fSPaolo Bonzini         /* Medium rotation rate [rpm], 5400 rpm */
124349ab747fSPaolo Bonzini         p[26] = (5400 >> 8) & 0xff;
124449ab747fSPaolo Bonzini         p[27] = 5400 & 0xff;
124549ab747fSPaolo Bonzini         break;
124649ab747fSPaolo Bonzini 
124749ab747fSPaolo Bonzini     case MODE_PAGE_CACHING:
124849ab747fSPaolo Bonzini         length = 0x12;
124949ab747fSPaolo Bonzini         if (page_control == 1 || /* Changeable Values */
12504be74634SMarkus Armbruster             blk_enable_write_cache(s->qdev.conf.blk)) {
125149ab747fSPaolo Bonzini             p[0] = 4; /* WCE */
125249ab747fSPaolo Bonzini         }
125349ab747fSPaolo Bonzini         break;
125449ab747fSPaolo Bonzini 
125549ab747fSPaolo Bonzini     case MODE_PAGE_R_W_ERROR:
125649ab747fSPaolo Bonzini         length = 10;
125749ab747fSPaolo Bonzini         if (page_control == 1) { /* Changeable Values */
12584536fba0SMark Cave-Ayland             if (s->qdev.type == TYPE_ROM) {
12594536fba0SMark Cave-Ayland                 /* Automatic Write Reallocation Enabled */
12604536fba0SMark Cave-Ayland                 p[0] = 0x80;
12614536fba0SMark Cave-Ayland             }
126249ab747fSPaolo Bonzini             break;
126349ab747fSPaolo Bonzini         }
126449ab747fSPaolo Bonzini         p[0] = 0x80; /* Automatic Write Reallocation Enabled */
126549ab747fSPaolo Bonzini         if (s->qdev.type == TYPE_ROM) {
126649ab747fSPaolo Bonzini             p[1] = 0x20; /* Read Retry Count */
126749ab747fSPaolo Bonzini         }
126849ab747fSPaolo Bonzini         break;
126949ab747fSPaolo Bonzini 
127049ab747fSPaolo Bonzini     case MODE_PAGE_AUDIO_CTL:
127149ab747fSPaolo Bonzini         length = 14;
127249ab747fSPaolo Bonzini         break;
127349ab747fSPaolo Bonzini 
127449ab747fSPaolo Bonzini     case MODE_PAGE_CAPABILITIES:
127549ab747fSPaolo Bonzini         length = 0x14;
127649ab747fSPaolo Bonzini         if (page_control == 1) { /* Changeable Values */
127749ab747fSPaolo Bonzini             break;
127849ab747fSPaolo Bonzini         }
127949ab747fSPaolo Bonzini 
128049ab747fSPaolo Bonzini         p[0] = 0x3b; /* CD-R & CD-RW read */
128149ab747fSPaolo Bonzini         p[1] = 0; /* Writing not supported */
128249ab747fSPaolo Bonzini         p[2] = 0x7f; /* Audio, composite, digital out,
128349ab747fSPaolo Bonzini                         mode 2 form 1&2, multi session */
128449ab747fSPaolo Bonzini         p[3] = 0xff; /* CD DA, DA accurate, RW supported,
128549ab747fSPaolo Bonzini                         RW corrected, C2 errors, ISRC,
128649ab747fSPaolo Bonzini                         UPC, Bar code */
128749ab747fSPaolo Bonzini         p[4] = 0x2d | (s->tray_locked ? 2 : 0);
128849ab747fSPaolo Bonzini         /* Locking supported, jumper present, eject, tray */
128949ab747fSPaolo Bonzini         p[5] = 0; /* no volume & mute control, no
129049ab747fSPaolo Bonzini                      changer */
129149ab747fSPaolo Bonzini         p[6] = (50 * 176) >> 8; /* 50x read speed */
129249ab747fSPaolo Bonzini         p[7] = (50 * 176) & 0xff;
129349ab747fSPaolo Bonzini         p[8] = 2 >> 8; /* Two volume levels */
129449ab747fSPaolo Bonzini         p[9] = 2 & 0xff;
129549ab747fSPaolo Bonzini         p[10] = 2048 >> 8; /* 2M buffer */
129649ab747fSPaolo Bonzini         p[11] = 2048 & 0xff;
129749ab747fSPaolo Bonzini         p[12] = (16 * 176) >> 8; /* 16x read speed current */
129849ab747fSPaolo Bonzini         p[13] = (16 * 176) & 0xff;
129949ab747fSPaolo Bonzini         p[16] = (16 * 176) >> 8; /* 16x write speed */
130049ab747fSPaolo Bonzini         p[17] = (16 * 176) & 0xff;
130149ab747fSPaolo Bonzini         p[18] = (16 * 176) >> 8; /* 16x write speed current */
130249ab747fSPaolo Bonzini         p[19] = (16 * 176) & 0xff;
130349ab747fSPaolo Bonzini         break;
130449ab747fSPaolo Bonzini 
130509d37867SMark Cave-Ayland      case MODE_PAGE_APPLE_VENDOR:
130609d37867SMark Cave-Ayland         if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR)) {
130709d37867SMark Cave-Ayland             length = 0x1e;
130809d37867SMark Cave-Ayland             if (page_control == 1) { /* Changeable Values */
130909d37867SMark Cave-Ayland                 break;
131009d37867SMark Cave-Ayland             }
131109d37867SMark Cave-Ayland 
131209d37867SMark Cave-Ayland             memset(p, 0, length);
131309d37867SMark Cave-Ayland             strcpy((char *)p + 8, "APPLE COMPUTER, INC   ");
131409d37867SMark Cave-Ayland             break;
131509d37867SMark Cave-Ayland         } else {
131609d37867SMark Cave-Ayland             return -1;
131709d37867SMark Cave-Ayland         }
131809d37867SMark Cave-Ayland 
131909274de1SMark Cave-Ayland     case MODE_PAGE_VENDOR_SPECIFIC:
132009274de1SMark Cave-Ayland         if (s->qdev.type == TYPE_DISK && (s->quirks &
132109274de1SMark Cave-Ayland             (1 << SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE))) {
132209274de1SMark Cave-Ayland             length = 0x2;
132309274de1SMark Cave-Ayland             if (page_control == 1) { /* Changeable Values */
132409274de1SMark Cave-Ayland                 p[0] = 0xff;
132509274de1SMark Cave-Ayland                 p[1] = 0xff;
132609274de1SMark Cave-Ayland                 break;
132709274de1SMark Cave-Ayland             }
132809274de1SMark Cave-Ayland             p[0] = 0;
132909274de1SMark Cave-Ayland             p[1] = 0;
133009274de1SMark Cave-Ayland             break;
133109274de1SMark Cave-Ayland         } else {
133209274de1SMark Cave-Ayland             return -1;
133309274de1SMark Cave-Ayland         }
133409274de1SMark Cave-Ayland 
133549ab747fSPaolo Bonzini     default:
133649ab747fSPaolo Bonzini         return -1;
133749ab747fSPaolo Bonzini     }
133849ab747fSPaolo Bonzini 
133949ab747fSPaolo Bonzini     assert(length < 256);
134049ab747fSPaolo Bonzini     (*p_outbuf)[0] = page;
134149ab747fSPaolo Bonzini     (*p_outbuf)[1] = length;
134249ab747fSPaolo Bonzini     *p_outbuf += length + 2;
134349ab747fSPaolo Bonzini     return length + 2;
134449ab747fSPaolo Bonzini }
134549ab747fSPaolo Bonzini 
scsi_disk_emulate_mode_sense(SCSIDiskReq * r,uint8_t * outbuf)134649ab747fSPaolo Bonzini static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
134749ab747fSPaolo Bonzini {
134849ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
134949ab747fSPaolo Bonzini     uint64_t nb_sectors;
135049ab747fSPaolo Bonzini     bool dbd;
135149ab747fSPaolo Bonzini     int page, buflen, ret, page_control;
135249ab747fSPaolo Bonzini     uint8_t *p;
135349ab747fSPaolo Bonzini     uint8_t dev_specific_param;
135449ab747fSPaolo Bonzini 
135549ab747fSPaolo Bonzini     dbd = (r->req.cmd.buf[1] & 0x8) != 0;
135649ab747fSPaolo Bonzini     page = r->req.cmd.buf[2] & 0x3f;
135749ab747fSPaolo Bonzini     page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
135859ee9500SLaurent Vivier 
135959ee9500SLaurent Vivier     trace_scsi_disk_emulate_mode_sense((r->req.cmd.buf[0] == MODE_SENSE) ? 6 :
136059ee9500SLaurent Vivier                                        10, page, r->req.cmd.xfer, page_control);
136149ab747fSPaolo Bonzini     memset(outbuf, 0, r->req.cmd.xfer);
136249ab747fSPaolo Bonzini     p = outbuf;
136349ab747fSPaolo Bonzini 
136449ab747fSPaolo Bonzini     if (s->qdev.type == TYPE_DISK) {
136549ab747fSPaolo Bonzini         dev_specific_param = s->features & (1 << SCSI_DISK_F_DPOFUA) ? 0x10 : 0;
136686b1cf32SKevin Wolf         if (!blk_is_writable(s->qdev.conf.blk)) {
136749ab747fSPaolo Bonzini             dev_specific_param |= 0x80; /* Readonly.  */
136849ab747fSPaolo Bonzini         }
136949ab747fSPaolo Bonzini     } else {
1370f43c2b94SMark Cave-Ayland         if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD)) {
1371f43c2b94SMark Cave-Ayland             /* Use DBD from the request... */
1372f43c2b94SMark Cave-Ayland             dev_specific_param = 0x00;
1373f43c2b94SMark Cave-Ayland 
1374f43c2b94SMark Cave-Ayland             /*
1375f43c2b94SMark Cave-Ayland              * ... unless we receive a request for MODE_PAGE_APPLE_VENDOR
1376f43c2b94SMark Cave-Ayland              * which should never return a block descriptor even though DBD is
1377f43c2b94SMark Cave-Ayland              * not set, otherwise CDROM detection fails in MacOS
1378f43c2b94SMark Cave-Ayland              */
1379f43c2b94SMark Cave-Ayland             if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR) &&
1380f43c2b94SMark Cave-Ayland                 page == MODE_PAGE_APPLE_VENDOR) {
1381f43c2b94SMark Cave-Ayland                 dbd = true;
1382f43c2b94SMark Cave-Ayland             }
1383f43c2b94SMark Cave-Ayland         } else {
1384f43c2b94SMark Cave-Ayland             /*
1385f43c2b94SMark Cave-Ayland              * MMC prescribes that CD/DVD drives have no block descriptors,
1386f43c2b94SMark Cave-Ayland              * and defines no device-specific parameter.
1387f43c2b94SMark Cave-Ayland              */
138849ab747fSPaolo Bonzini             dev_specific_param = 0x00;
138949ab747fSPaolo Bonzini             dbd = true;
139049ab747fSPaolo Bonzini         }
1391f43c2b94SMark Cave-Ayland     }
139249ab747fSPaolo Bonzini 
139349ab747fSPaolo Bonzini     if (r->req.cmd.buf[0] == MODE_SENSE) {
139449ab747fSPaolo Bonzini         p[1] = 0; /* Default media type.  */
139549ab747fSPaolo Bonzini         p[2] = dev_specific_param;
139649ab747fSPaolo Bonzini         p[3] = 0; /* Block descriptor length.  */
139749ab747fSPaolo Bonzini         p += 4;
139849ab747fSPaolo Bonzini     } else { /* MODE_SENSE_10 */
139949ab747fSPaolo Bonzini         p[2] = 0; /* Default media type.  */
140049ab747fSPaolo Bonzini         p[3] = dev_specific_param;
140149ab747fSPaolo Bonzini         p[6] = p[7] = 0; /* Block descriptor length.  */
140249ab747fSPaolo Bonzini         p += 8;
140349ab747fSPaolo Bonzini     }
140449ab747fSPaolo Bonzini 
14054be74634SMarkus Armbruster     blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
140649ab747fSPaolo Bonzini     if (!dbd && nb_sectors) {
140749ab747fSPaolo Bonzini         if (r->req.cmd.buf[0] == MODE_SENSE) {
140849ab747fSPaolo Bonzini             outbuf[3] = 8; /* Block descriptor length  */
140949ab747fSPaolo Bonzini         } else { /* MODE_SENSE_10 */
141049ab747fSPaolo Bonzini             outbuf[7] = 8; /* Block descriptor length  */
141149ab747fSPaolo Bonzini         }
14123dc516bfSPhilippe Mathieu-Daudé         nb_sectors /= (s->qdev.blocksize / BDRV_SECTOR_SIZE);
141349ab747fSPaolo Bonzini         if (nb_sectors > 0xffffff) {
141449ab747fSPaolo Bonzini             nb_sectors = 0;
141549ab747fSPaolo Bonzini         }
141649ab747fSPaolo Bonzini         p[0] = 0; /* media density code */
141749ab747fSPaolo Bonzini         p[1] = (nb_sectors >> 16) & 0xff;
141849ab747fSPaolo Bonzini         p[2] = (nb_sectors >> 8) & 0xff;
141949ab747fSPaolo Bonzini         p[3] = nb_sectors & 0xff;
142049ab747fSPaolo Bonzini         p[4] = 0; /* reserved */
142149ab747fSPaolo Bonzini         p[5] = 0; /* bytes 5-7 are the sector size in bytes */
142249ab747fSPaolo Bonzini         p[6] = s->qdev.blocksize >> 8;
142349ab747fSPaolo Bonzini         p[7] = 0;
142449ab747fSPaolo Bonzini         p += 8;
142549ab747fSPaolo Bonzini     }
142649ab747fSPaolo Bonzini 
142749ab747fSPaolo Bonzini     if (page_control == 3) {
142849ab747fSPaolo Bonzini         /* Saved Values */
142949ab747fSPaolo Bonzini         scsi_check_condition(r, SENSE_CODE(SAVING_PARAMS_NOT_SUPPORTED));
143049ab747fSPaolo Bonzini         return -1;
143149ab747fSPaolo Bonzini     }
143249ab747fSPaolo Bonzini 
143349ab747fSPaolo Bonzini     if (page == 0x3f) {
143449ab747fSPaolo Bonzini         for (page = 0; page <= 0x3e; page++) {
143549ab747fSPaolo Bonzini             mode_sense_page(s, page, &p, page_control);
143649ab747fSPaolo Bonzini         }
143749ab747fSPaolo Bonzini     } else {
143849ab747fSPaolo Bonzini         ret = mode_sense_page(s, page, &p, page_control);
143949ab747fSPaolo Bonzini         if (ret == -1) {
144049ab747fSPaolo Bonzini             return -1;
144149ab747fSPaolo Bonzini         }
144249ab747fSPaolo Bonzini     }
144349ab747fSPaolo Bonzini 
144449ab747fSPaolo Bonzini     buflen = p - outbuf;
144549ab747fSPaolo Bonzini     /*
144649ab747fSPaolo Bonzini      * The mode data length field specifies the length in bytes of the
144749ab747fSPaolo Bonzini      * following data that is available to be transferred. The mode data
144849ab747fSPaolo Bonzini      * length does not include itself.
144949ab747fSPaolo Bonzini      */
145049ab747fSPaolo Bonzini     if (r->req.cmd.buf[0] == MODE_SENSE) {
145149ab747fSPaolo Bonzini         outbuf[0] = buflen - 1;
145249ab747fSPaolo Bonzini     } else { /* MODE_SENSE_10 */
145349ab747fSPaolo Bonzini         outbuf[0] = ((buflen - 2) >> 8) & 0xff;
145449ab747fSPaolo Bonzini         outbuf[1] = (buflen - 2) & 0xff;
145549ab747fSPaolo Bonzini     }
145649ab747fSPaolo Bonzini     return buflen;
145749ab747fSPaolo Bonzini }
145849ab747fSPaolo Bonzini 
scsi_disk_emulate_read_toc(SCSIRequest * req,uint8_t * outbuf)145949ab747fSPaolo Bonzini static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
146049ab747fSPaolo Bonzini {
146149ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
146249ab747fSPaolo Bonzini     int start_track, format, msf, toclen;
146349ab747fSPaolo Bonzini     uint64_t nb_sectors;
146449ab747fSPaolo Bonzini 
146549ab747fSPaolo Bonzini     msf = req->cmd.buf[1] & 2;
146649ab747fSPaolo Bonzini     format = req->cmd.buf[2] & 0xf;
146749ab747fSPaolo Bonzini     start_track = req->cmd.buf[6];
14684be74634SMarkus Armbruster     blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
146959ee9500SLaurent Vivier     trace_scsi_disk_emulate_read_toc(start_track, format, msf >> 1);
14703dc516bfSPhilippe Mathieu-Daudé     nb_sectors /= s->qdev.blocksize / BDRV_SECTOR_SIZE;
147149ab747fSPaolo Bonzini     switch (format) {
147249ab747fSPaolo Bonzini     case 0:
147349ab747fSPaolo Bonzini         toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
147449ab747fSPaolo Bonzini         break;
147549ab747fSPaolo Bonzini     case 1:
147649ab747fSPaolo Bonzini         /* multi session : only a single session defined */
147749ab747fSPaolo Bonzini         toclen = 12;
147849ab747fSPaolo Bonzini         memset(outbuf, 0, 12);
147949ab747fSPaolo Bonzini         outbuf[1] = 0x0a;
148049ab747fSPaolo Bonzini         outbuf[2] = 0x01;
148149ab747fSPaolo Bonzini         outbuf[3] = 0x01;
148249ab747fSPaolo Bonzini         break;
148349ab747fSPaolo Bonzini     case 2:
148449ab747fSPaolo Bonzini         toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track);
148549ab747fSPaolo Bonzini         break;
148649ab747fSPaolo Bonzini     default:
148749ab747fSPaolo Bonzini         return -1;
148849ab747fSPaolo Bonzini     }
148949ab747fSPaolo Bonzini     return toclen;
149049ab747fSPaolo Bonzini }
149149ab747fSPaolo Bonzini 
scsi_disk_emulate_start_stop(SCSIDiskReq * r)149249ab747fSPaolo Bonzini static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
149349ab747fSPaolo Bonzini {
149449ab747fSPaolo Bonzini     SCSIRequest *req = &r->req;
149549ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
149649ab747fSPaolo Bonzini     bool start = req->cmd.buf[4] & 1;
149749ab747fSPaolo Bonzini     bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
149849ab747fSPaolo Bonzini     int pwrcnd = req->cmd.buf[4] & 0xf0;
149949ab747fSPaolo Bonzini 
150049ab747fSPaolo Bonzini     if (pwrcnd) {
150149ab747fSPaolo Bonzini         /* eject/load only happens for power condition == 0 */
150249ab747fSPaolo Bonzini         return 0;
150349ab747fSPaolo Bonzini     }
150449ab747fSPaolo Bonzini 
150549ab747fSPaolo Bonzini     if ((s->features & (1 << SCSI_DISK_F_REMOVABLE)) && loej) {
150649ab747fSPaolo Bonzini         if (!start && !s->tray_open && s->tray_locked) {
150749ab747fSPaolo Bonzini             scsi_check_condition(r,
15084be74634SMarkus Armbruster                                  blk_is_inserted(s->qdev.conf.blk)
150949ab747fSPaolo Bonzini                                  ? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED)
151049ab747fSPaolo Bonzini                                  : SENSE_CODE(NOT_READY_REMOVAL_PREVENTED));
151149ab747fSPaolo Bonzini             return -1;
151249ab747fSPaolo Bonzini         }
151349ab747fSPaolo Bonzini 
151449ab747fSPaolo Bonzini         if (s->tray_open != !start) {
15154be74634SMarkus Armbruster             blk_eject(s->qdev.conf.blk, !start);
151649ab747fSPaolo Bonzini             s->tray_open = !start;
151749ab747fSPaolo Bonzini         }
151849ab747fSPaolo Bonzini     }
151949ab747fSPaolo Bonzini     return 0;
152049ab747fSPaolo Bonzini }
152149ab747fSPaolo Bonzini 
scsi_disk_emulate_read_data(SCSIRequest * req)152249ab747fSPaolo Bonzini static void scsi_disk_emulate_read_data(SCSIRequest *req)
152349ab747fSPaolo Bonzini {
152449ab747fSPaolo Bonzini     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
152549ab747fSPaolo Bonzini     int buflen = r->iov.iov_len;
152649ab747fSPaolo Bonzini 
152749ab747fSPaolo Bonzini     if (buflen) {
152859ee9500SLaurent Vivier         trace_scsi_disk_emulate_read_data(buflen);
152949ab747fSPaolo Bonzini         r->iov.iov_len = 0;
153049ab747fSPaolo Bonzini         r->started = true;
153149ab747fSPaolo Bonzini         scsi_req_data(&r->req, buflen);
153249ab747fSPaolo Bonzini         return;
153349ab747fSPaolo Bonzini     }
153449ab747fSPaolo Bonzini 
153549ab747fSPaolo Bonzini     /* This also clears the sense buffer for REQUEST SENSE.  */
153649ab747fSPaolo Bonzini     scsi_req_complete(&r->req, GOOD);
153749ab747fSPaolo Bonzini }
153849ab747fSPaolo Bonzini 
scsi_disk_check_mode_select(SCSIDiskState * s,int page,uint8_t * inbuf,int inlen)153949ab747fSPaolo Bonzini static int scsi_disk_check_mode_select(SCSIDiskState *s, int page,
154049ab747fSPaolo Bonzini                                        uint8_t *inbuf, int inlen)
154149ab747fSPaolo Bonzini {
154249ab747fSPaolo Bonzini     uint8_t mode_current[SCSI_MAX_MODE_LEN];
154349ab747fSPaolo Bonzini     uint8_t mode_changeable[SCSI_MAX_MODE_LEN];
154449ab747fSPaolo Bonzini     uint8_t *p;
154549ab747fSPaolo Bonzini     int len, expected_len, changeable_len, i;
154649ab747fSPaolo Bonzini 
154749ab747fSPaolo Bonzini     /* The input buffer does not include the page header, so it is
154849ab747fSPaolo Bonzini      * off by 2 bytes.
154949ab747fSPaolo Bonzini      */
155049ab747fSPaolo Bonzini     expected_len = inlen + 2;
155149ab747fSPaolo Bonzini     if (expected_len > SCSI_MAX_MODE_LEN) {
155249ab747fSPaolo Bonzini         return -1;
155349ab747fSPaolo Bonzini     }
155449ab747fSPaolo Bonzini 
1555b3af7fdfSMauro Matteo Cascella     /* MODE_PAGE_ALLS is only valid for MODE SENSE commands */
1556b3af7fdfSMauro Matteo Cascella     if (page == MODE_PAGE_ALLS) {
1557b3af7fdfSMauro Matteo Cascella         return -1;
1558b3af7fdfSMauro Matteo Cascella     }
1559b3af7fdfSMauro Matteo Cascella 
156049ab747fSPaolo Bonzini     p = mode_current;
156149ab747fSPaolo Bonzini     memset(mode_current, 0, inlen + 2);
156249ab747fSPaolo Bonzini     len = mode_sense_page(s, page, &p, 0);
156349ab747fSPaolo Bonzini     if (len < 0 || len != expected_len) {
156449ab747fSPaolo Bonzini         return -1;
156549ab747fSPaolo Bonzini     }
156649ab747fSPaolo Bonzini 
156749ab747fSPaolo Bonzini     p = mode_changeable;
156849ab747fSPaolo Bonzini     memset(mode_changeable, 0, inlen + 2);
156949ab747fSPaolo Bonzini     changeable_len = mode_sense_page(s, page, &p, 1);
157049ab747fSPaolo Bonzini     assert(changeable_len == len);
157149ab747fSPaolo Bonzini 
157249ab747fSPaolo Bonzini     /* Check that unchangeable bits are the same as what MODE SENSE
157349ab747fSPaolo Bonzini      * would return.
157449ab747fSPaolo Bonzini      */
157549ab747fSPaolo Bonzini     for (i = 2; i < len; i++) {
157649ab747fSPaolo Bonzini         if (((mode_current[i] ^ inbuf[i - 2]) & ~mode_changeable[i]) != 0) {
157749ab747fSPaolo Bonzini             return -1;
157849ab747fSPaolo Bonzini         }
157949ab747fSPaolo Bonzini     }
158049ab747fSPaolo Bonzini     return 0;
158149ab747fSPaolo Bonzini }
158249ab747fSPaolo Bonzini 
scsi_disk_apply_mode_select(SCSIDiskState * s,int page,uint8_t * p)158349ab747fSPaolo Bonzini static void scsi_disk_apply_mode_select(SCSIDiskState *s, int page, uint8_t *p)
158449ab747fSPaolo Bonzini {
158549ab747fSPaolo Bonzini     switch (page) {
158649ab747fSPaolo Bonzini     case MODE_PAGE_CACHING:
15874be74634SMarkus Armbruster         blk_set_enable_write_cache(s->qdev.conf.blk, (p[0] & 4) != 0);
158849ab747fSPaolo Bonzini         break;
158949ab747fSPaolo Bonzini 
159049ab747fSPaolo Bonzini     default:
159149ab747fSPaolo Bonzini         break;
159249ab747fSPaolo Bonzini     }
159349ab747fSPaolo Bonzini }
159449ab747fSPaolo Bonzini 
mode_select_pages(SCSIDiskReq * r,uint8_t * p,int len,bool change)159549ab747fSPaolo Bonzini static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change)
159649ab747fSPaolo Bonzini {
159749ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
159849ab747fSPaolo Bonzini 
159949ab747fSPaolo Bonzini     while (len > 0) {
160049ab747fSPaolo Bonzini         int page, subpage, page_len;
160149ab747fSPaolo Bonzini 
160249ab747fSPaolo Bonzini         /* Parse both possible formats for the mode page headers.  */
160349ab747fSPaolo Bonzini         page = p[0] & 0x3f;
160449ab747fSPaolo Bonzini         if (p[0] & 0x40) {
160549ab747fSPaolo Bonzini             if (len < 4) {
160649ab747fSPaolo Bonzini                 goto invalid_param_len;
160749ab747fSPaolo Bonzini             }
160849ab747fSPaolo Bonzini             subpage = p[1];
160949ab747fSPaolo Bonzini             page_len = lduw_be_p(&p[2]);
161049ab747fSPaolo Bonzini             p += 4;
161149ab747fSPaolo Bonzini             len -= 4;
161249ab747fSPaolo Bonzini         } else {
161349ab747fSPaolo Bonzini             if (len < 2) {
161449ab747fSPaolo Bonzini                 goto invalid_param_len;
161549ab747fSPaolo Bonzini             }
161649ab747fSPaolo Bonzini             subpage = 0;
161749ab747fSPaolo Bonzini             page_len = p[1];
161849ab747fSPaolo Bonzini             p += 2;
161949ab747fSPaolo Bonzini             len -= 2;
162049ab747fSPaolo Bonzini         }
162149ab747fSPaolo Bonzini 
162249ab747fSPaolo Bonzini         if (subpage) {
162349ab747fSPaolo Bonzini             goto invalid_param;
162449ab747fSPaolo Bonzini         }
162549ab747fSPaolo Bonzini         if (page_len > len) {
1626389e18ebSMark Cave-Ayland             if (!(s->quirks & SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED)) {
162749ab747fSPaolo Bonzini                 goto invalid_param_len;
162849ab747fSPaolo Bonzini             }
1629389e18ebSMark Cave-Ayland             trace_scsi_disk_mode_select_page_truncated(page, page_len, len);
1630389e18ebSMark Cave-Ayland         }
163149ab747fSPaolo Bonzini 
163249ab747fSPaolo Bonzini         if (!change) {
163349ab747fSPaolo Bonzini             if (scsi_disk_check_mode_select(s, page, p, page_len) < 0) {
163449ab747fSPaolo Bonzini                 goto invalid_param;
163549ab747fSPaolo Bonzini             }
163649ab747fSPaolo Bonzini         } else {
163749ab747fSPaolo Bonzini             scsi_disk_apply_mode_select(s, page, p);
163849ab747fSPaolo Bonzini         }
163949ab747fSPaolo Bonzini 
164049ab747fSPaolo Bonzini         p += page_len;
164149ab747fSPaolo Bonzini         len -= page_len;
164249ab747fSPaolo Bonzini     }
164349ab747fSPaolo Bonzini     return 0;
164449ab747fSPaolo Bonzini 
164549ab747fSPaolo Bonzini invalid_param:
164649ab747fSPaolo Bonzini     scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
164749ab747fSPaolo Bonzini     return -1;
164849ab747fSPaolo Bonzini 
164949ab747fSPaolo Bonzini invalid_param_len:
165049ab747fSPaolo Bonzini     scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
165149ab747fSPaolo Bonzini     return -1;
165249ab747fSPaolo Bonzini }
165349ab747fSPaolo Bonzini 
scsi_disk_emulate_mode_select(SCSIDiskReq * r,uint8_t * inbuf)165449ab747fSPaolo Bonzini static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
165549ab747fSPaolo Bonzini {
165649ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
165749ab747fSPaolo Bonzini     uint8_t *p = inbuf;
165849ab747fSPaolo Bonzini     int cmd = r->req.cmd.buf[0];
165949ab747fSPaolo Bonzini     int len = r->req.cmd.xfer;
166049ab747fSPaolo Bonzini     int hdr_len = (cmd == MODE_SELECT ? 4 : 8);
166155794c90SMark Cave-Ayland     int bd_len, bs;
166249ab747fSPaolo Bonzini     int pass;
166349ab747fSPaolo Bonzini 
166449ab747fSPaolo Bonzini     if ((r->req.cmd.buf[1] & 0x11) != 0x10) {
166509274de1SMark Cave-Ayland         if (!(s->quirks &
166609274de1SMark Cave-Ayland             (1 << SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE))) {
166709274de1SMark Cave-Ayland             /* We only support PF=1, SP=0.  */
166849ab747fSPaolo Bonzini             goto invalid_field;
166949ab747fSPaolo Bonzini         }
167009274de1SMark Cave-Ayland     }
167149ab747fSPaolo Bonzini 
167249ab747fSPaolo Bonzini     if (len < hdr_len) {
167349ab747fSPaolo Bonzini         goto invalid_param_len;
167449ab747fSPaolo Bonzini     }
167549ab747fSPaolo Bonzini 
167649ab747fSPaolo Bonzini     bd_len = (cmd == MODE_SELECT ? p[3] : lduw_be_p(&p[6]));
167749ab747fSPaolo Bonzini     len -= hdr_len;
167849ab747fSPaolo Bonzini     p += hdr_len;
167949ab747fSPaolo Bonzini     if (len < bd_len) {
168049ab747fSPaolo Bonzini         goto invalid_param_len;
168149ab747fSPaolo Bonzini     }
168249ab747fSPaolo Bonzini     if (bd_len != 0 && bd_len != 8) {
168349ab747fSPaolo Bonzini         goto invalid_param;
168449ab747fSPaolo Bonzini     }
168549ab747fSPaolo Bonzini 
1686356c4c44SMark Cave-Ayland     /* Allow changing the block size */
168755794c90SMark Cave-Ayland     if (bd_len) {
168855794c90SMark Cave-Ayland         bs = p[5] << 16 | p[6] << 8 | p[7];
168955794c90SMark Cave-Ayland 
169055794c90SMark Cave-Ayland         /*
169155794c90SMark Cave-Ayland          * Since the existing code only checks/updates bits 8-15 of the block
169255794c90SMark Cave-Ayland          * size, restrict ourselves to the same requirement for now to ensure
169355794c90SMark Cave-Ayland          * that a block size set by a block descriptor and then read back by
16947cfcc79bSThomas Huth          * a subsequent SCSI command will be the same. Also disallow a block
16957cfcc79bSThomas Huth          * size of 256 since we cannot handle anything below BDRV_SECTOR_SIZE.
169655794c90SMark Cave-Ayland          */
16977cfcc79bSThomas Huth         if (bs && !(bs & ~0xfe00) && bs != s->qdev.blocksize) {
169855794c90SMark Cave-Ayland             s->qdev.blocksize = bs;
1699356c4c44SMark Cave-Ayland             trace_scsi_disk_mode_select_set_blocksize(s->qdev.blocksize);
1700356c4c44SMark Cave-Ayland         }
170155794c90SMark Cave-Ayland     }
1702356c4c44SMark Cave-Ayland 
170349ab747fSPaolo Bonzini     len -= bd_len;
170449ab747fSPaolo Bonzini     p += bd_len;
170549ab747fSPaolo Bonzini 
170649ab747fSPaolo Bonzini     /* Ensure no change is made if there is an error!  */
170749ab747fSPaolo Bonzini     for (pass = 0; pass < 2; pass++) {
170849ab747fSPaolo Bonzini         if (mode_select_pages(r, p, len, pass == 1) < 0) {
170949ab747fSPaolo Bonzini             assert(pass == 0);
171049ab747fSPaolo Bonzini             return;
171149ab747fSPaolo Bonzini         }
171249ab747fSPaolo Bonzini     }
17134be74634SMarkus Armbruster     if (!blk_enable_write_cache(s->qdev.conf.blk)) {
171449ab747fSPaolo Bonzini         /* The request is used as the AIO opaque value, so add a ref.  */
171549ab747fSPaolo Bonzini         scsi_req_ref(&r->req);
17164be74634SMarkus Armbruster         block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
17175366d0c8SBenoît Canet                          BLOCK_ACCT_FLUSH);
17184be74634SMarkus Armbruster         r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r);
171949ab747fSPaolo Bonzini         return;
172049ab747fSPaolo Bonzini     }
172149ab747fSPaolo Bonzini 
172249ab747fSPaolo Bonzini     scsi_req_complete(&r->req, GOOD);
172349ab747fSPaolo Bonzini     return;
172449ab747fSPaolo Bonzini 
172549ab747fSPaolo Bonzini invalid_param:
172649ab747fSPaolo Bonzini     scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
172749ab747fSPaolo Bonzini     return;
172849ab747fSPaolo Bonzini 
172949ab747fSPaolo Bonzini invalid_param_len:
173049ab747fSPaolo Bonzini     scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
173149ab747fSPaolo Bonzini     return;
173249ab747fSPaolo Bonzini 
173349ab747fSPaolo Bonzini invalid_field:
173449ab747fSPaolo Bonzini     scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
173549ab747fSPaolo Bonzini }
173649ab747fSPaolo Bonzini 
1737b802d14dSKit Westneat /* sector_num and nb_sectors expected to be in qdev blocksize */
check_lba_range(SCSIDiskState * s,uint64_t sector_num,uint32_t nb_sectors)173849ab747fSPaolo Bonzini static inline bool check_lba_range(SCSIDiskState *s,
173949ab747fSPaolo Bonzini                                    uint64_t sector_num, uint32_t nb_sectors)
174049ab747fSPaolo Bonzini {
174149ab747fSPaolo Bonzini     /*
174249ab747fSPaolo Bonzini      * The first line tests that no overflow happens when computing the last
174349ab747fSPaolo Bonzini      * sector.  The second line tests that the last accessed sector is in
174449ab747fSPaolo Bonzini      * range.
174549ab747fSPaolo Bonzini      *
174649ab747fSPaolo Bonzini      * Careful, the computations should not underflow for nb_sectors == 0,
174749ab747fSPaolo Bonzini      * and a 0-block read to the first LBA beyond the end of device is
174849ab747fSPaolo Bonzini      * valid.
174949ab747fSPaolo Bonzini      */
175049ab747fSPaolo Bonzini     return (sector_num <= sector_num + nb_sectors &&
175149ab747fSPaolo Bonzini             sector_num + nb_sectors <= s->qdev.max_lba + 1);
175249ab747fSPaolo Bonzini }
175349ab747fSPaolo Bonzini 
175449ab747fSPaolo Bonzini typedef struct UnmapCBData {
175549ab747fSPaolo Bonzini     SCSIDiskReq *r;
175649ab747fSPaolo Bonzini     uint8_t *inbuf;
175749ab747fSPaolo Bonzini     int count;
175849ab747fSPaolo Bonzini } UnmapCBData;
175949ab747fSPaolo Bonzini 
17605fd2b563SPaolo Bonzini static void scsi_unmap_complete(void *opaque, int ret);
17615fd2b563SPaolo Bonzini 
scsi_unmap_complete_noio(UnmapCBData * data,int ret)17625fd2b563SPaolo Bonzini static void scsi_unmap_complete_noio(UnmapCBData *data, int ret)
176349ab747fSPaolo Bonzini {
176449ab747fSPaolo Bonzini     SCSIDiskReq *r = data->r;
176549ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
176649ab747fSPaolo Bonzini 
17675fd2b563SPaolo Bonzini     assert(r->req.aiocb == NULL);
176849ab747fSPaolo Bonzini 
176949ab747fSPaolo Bonzini     if (data->count > 0) {
1770b802d14dSKit Westneat         uint64_t sector_num = ldq_be_p(&data->inbuf[0]);
1771b802d14dSKit Westneat         uint32_t nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
1772b802d14dSKit Westneat         r->sector = sector_num * (s->qdev.blocksize / BDRV_SECTOR_SIZE);
1773b802d14dSKit Westneat         r->sector_count = nb_sectors * (s->qdev.blocksize / BDRV_SECTOR_SIZE);
1774b802d14dSKit Westneat 
1775b802d14dSKit Westneat         if (!check_lba_range(s, sector_num, nb_sectors)) {
17764989ef57SAnton Nefedov             block_acct_invalid(blk_get_stats(s->qdev.conf.blk),
17774989ef57SAnton Nefedov                                BLOCK_ACCT_UNMAP);
177849ab747fSPaolo Bonzini             scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
177949ab747fSPaolo Bonzini             goto done;
178049ab747fSPaolo Bonzini         }
178149ab747fSPaolo Bonzini 
17824989ef57SAnton Nefedov         block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
17834989ef57SAnton Nefedov                          r->sector_count * BDRV_SECTOR_SIZE,
17844989ef57SAnton Nefedov                          BLOCK_ACCT_UNMAP);
17854989ef57SAnton Nefedov 
17861c6c4bb7SEric Blake         r->req.aiocb = blk_aio_pdiscard(s->qdev.conf.blk,
17876d068082SAnton Nefedov                                         r->sector * BDRV_SECTOR_SIZE,
17886d068082SAnton Nefedov                                         r->sector_count * BDRV_SECTOR_SIZE,
178949ab747fSPaolo Bonzini                                         scsi_unmap_complete, data);
179049ab747fSPaolo Bonzini         data->count--;
179149ab747fSPaolo Bonzini         data->inbuf += 16;
179249ab747fSPaolo Bonzini         return;
179349ab747fSPaolo Bonzini     }
179449ab747fSPaolo Bonzini 
179549ab747fSPaolo Bonzini     scsi_req_complete(&r->req, GOOD);
179649ab747fSPaolo Bonzini 
179749ab747fSPaolo Bonzini done:
179849ab747fSPaolo Bonzini     scsi_req_unref(&r->req);
179949ab747fSPaolo Bonzini     g_free(data);
180049ab747fSPaolo Bonzini }
180149ab747fSPaolo Bonzini 
scsi_unmap_complete(void * opaque,int ret)18025fd2b563SPaolo Bonzini static void scsi_unmap_complete(void *opaque, int ret)
18035fd2b563SPaolo Bonzini {
18045fd2b563SPaolo Bonzini     UnmapCBData *data = opaque;
18055fd2b563SPaolo Bonzini     SCSIDiskReq *r = data->r;
1806b9e413ddSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
18075fd2b563SPaolo Bonzini 
18085fd2b563SPaolo Bonzini     assert(r->req.aiocb != NULL);
18095fd2b563SPaolo Bonzini     r->req.aiocb = NULL;
18105fd2b563SPaolo Bonzini 
18114989ef57SAnton Nefedov     if (scsi_disk_req_check_error(r, ret, true)) {
181290ebf843SAnton Nefedov         scsi_req_unref(&r->req);
181390ebf843SAnton Nefedov         g_free(data);
181490ebf843SAnton Nefedov     } else {
18154989ef57SAnton Nefedov         block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
18165fd2b563SPaolo Bonzini         scsi_unmap_complete_noio(data, ret);
181790ebf843SAnton Nefedov     }
18185fd2b563SPaolo Bonzini }
18195fd2b563SPaolo Bonzini 
scsi_disk_emulate_unmap(SCSIDiskReq * r,uint8_t * inbuf)182049ab747fSPaolo Bonzini static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
182149ab747fSPaolo Bonzini {
1822c5fd1fb0SPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
182349ab747fSPaolo Bonzini     uint8_t *p = inbuf;
182449ab747fSPaolo Bonzini     int len = r->req.cmd.xfer;
182549ab747fSPaolo Bonzini     UnmapCBData *data;
182649ab747fSPaolo Bonzini 
1827823bd739SPaolo Bonzini     /* Reject ANCHOR=1.  */
1828823bd739SPaolo Bonzini     if (r->req.cmd.buf[1] & 0x1) {
1829823bd739SPaolo Bonzini         goto invalid_field;
1830823bd739SPaolo Bonzini     }
1831823bd739SPaolo Bonzini 
183249ab747fSPaolo Bonzini     if (len < 8) {
183349ab747fSPaolo Bonzini         goto invalid_param_len;
183449ab747fSPaolo Bonzini     }
183549ab747fSPaolo Bonzini     if (len < lduw_be_p(&p[0]) + 2) {
183649ab747fSPaolo Bonzini         goto invalid_param_len;
183749ab747fSPaolo Bonzini     }
183849ab747fSPaolo Bonzini     if (len < lduw_be_p(&p[2]) + 8) {
183949ab747fSPaolo Bonzini         goto invalid_param_len;
184049ab747fSPaolo Bonzini     }
184149ab747fSPaolo Bonzini     if (lduw_be_p(&p[2]) & 15) {
184249ab747fSPaolo Bonzini         goto invalid_param_len;
184349ab747fSPaolo Bonzini     }
184449ab747fSPaolo Bonzini 
184586b1cf32SKevin Wolf     if (!blk_is_writable(s->qdev.conf.blk)) {
18464989ef57SAnton Nefedov         block_acct_invalid(blk_get_stats(s->qdev.conf.blk), BLOCK_ACCT_UNMAP);
1847c5fd1fb0SPaolo Bonzini         scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
1848c5fd1fb0SPaolo Bonzini         return;
1849c5fd1fb0SPaolo Bonzini     }
1850c5fd1fb0SPaolo Bonzini 
185149ab747fSPaolo Bonzini     data = g_new0(UnmapCBData, 1);
185249ab747fSPaolo Bonzini     data->r = r;
185349ab747fSPaolo Bonzini     data->inbuf = &p[8];
185449ab747fSPaolo Bonzini     data->count = lduw_be_p(&p[2]) >> 4;
185549ab747fSPaolo Bonzini 
185649ab747fSPaolo Bonzini     /* The matching unref is in scsi_unmap_complete, before data is freed.  */
185749ab747fSPaolo Bonzini     scsi_req_ref(&r->req);
18585fd2b563SPaolo Bonzini     scsi_unmap_complete_noio(data, 0);
185949ab747fSPaolo Bonzini     return;
186049ab747fSPaolo Bonzini 
186149ab747fSPaolo Bonzini invalid_param_len:
18624989ef57SAnton Nefedov     block_acct_invalid(blk_get_stats(s->qdev.conf.blk), BLOCK_ACCT_UNMAP);
186349ab747fSPaolo Bonzini     scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
1864823bd739SPaolo Bonzini     return;
1865823bd739SPaolo Bonzini 
1866823bd739SPaolo Bonzini invalid_field:
18674989ef57SAnton Nefedov     block_acct_invalid(blk_get_stats(s->qdev.conf.blk), BLOCK_ACCT_UNMAP);
1868823bd739SPaolo Bonzini     scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
186949ab747fSPaolo Bonzini }
187049ab747fSPaolo Bonzini 
187184f94a9aSPaolo Bonzini typedef struct WriteSameCBData {
187284f94a9aSPaolo Bonzini     SCSIDiskReq *r;
187384f94a9aSPaolo Bonzini     int64_t sector;
187484f94a9aSPaolo Bonzini     int nb_sectors;
187584f94a9aSPaolo Bonzini     QEMUIOVector qiov;
187684f94a9aSPaolo Bonzini     struct iovec iov;
187784f94a9aSPaolo Bonzini } WriteSameCBData;
187884f94a9aSPaolo Bonzini 
scsi_write_same_complete(void * opaque,int ret)187984f94a9aSPaolo Bonzini static void scsi_write_same_complete(void *opaque, int ret)
188084f94a9aSPaolo Bonzini {
188184f94a9aSPaolo Bonzini     WriteSameCBData *data = opaque;
188284f94a9aSPaolo Bonzini     SCSIDiskReq *r = data->r;
188384f94a9aSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
188484f94a9aSPaolo Bonzini 
188584f94a9aSPaolo Bonzini     assert(r->req.aiocb != NULL);
188684f94a9aSPaolo Bonzini     r->req.aiocb = NULL;
18877b7fc3d0SStefan Hajnoczi 
18885b956f41SPaolo Bonzini     if (scsi_disk_req_check_error(r, ret, true)) {
188984f94a9aSPaolo Bonzini         goto done;
189084f94a9aSPaolo Bonzini     }
189184f94a9aSPaolo Bonzini 
1892d7628080SAlberto Garcia     block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
1893d7628080SAlberto Garcia 
18943dc516bfSPhilippe Mathieu-Daudé     data->nb_sectors -= data->iov.iov_len / BDRV_SECTOR_SIZE;
18953dc516bfSPhilippe Mathieu-Daudé     data->sector += data->iov.iov_len / BDRV_SECTOR_SIZE;
18963dc516bfSPhilippe Mathieu-Daudé     data->iov.iov_len = MIN(data->nb_sectors * BDRV_SECTOR_SIZE,
18973dc516bfSPhilippe Mathieu-Daudé                             data->iov.iov_len);
189884f94a9aSPaolo Bonzini     if (data->iov.iov_len) {
18994be74634SMarkus Armbruster         block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
19005366d0c8SBenoît Canet                          data->iov.iov_len, BLOCK_ACCT_WRITE);
190103c90063SEric Blake         /* Reinitialize qiov, to handle unaligned WRITE SAME request
190203c90063SEric Blake          * where final qiov may need smaller size */
1903a56537a1SFam Zheng         qemu_iovec_init_external(&data->qiov, &data->iov, 1);
190403c90063SEric Blake         r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk,
190503c90063SEric Blake                                        data->sector << BDRV_SECTOR_BITS,
190603c90063SEric Blake                                        &data->qiov, 0,
190798e33f1bSPaolo Bonzini                                        scsi_write_same_complete, data);
190884f94a9aSPaolo Bonzini         return;
190984f94a9aSPaolo Bonzini     }
191084f94a9aSPaolo Bonzini 
191184f94a9aSPaolo Bonzini     scsi_req_complete(&r->req, GOOD);
191284f94a9aSPaolo Bonzini 
191384f94a9aSPaolo Bonzini done:
191484f94a9aSPaolo Bonzini     scsi_req_unref(&r->req);
191584f94a9aSPaolo Bonzini     qemu_vfree(data->iov.iov_base);
191684f94a9aSPaolo Bonzini     g_free(data);
191784f94a9aSPaolo Bonzini }
191884f94a9aSPaolo Bonzini 
scsi_disk_emulate_write_same(SCSIDiskReq * r,uint8_t * inbuf)191984f94a9aSPaolo Bonzini static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
192084f94a9aSPaolo Bonzini {
192184f94a9aSPaolo Bonzini     SCSIRequest *req = &r->req;
192284f94a9aSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
19231894df02SHannes Reinecke     uint32_t nb_sectors = scsi_data_cdb_xfer(r->req.cmd.buf);
192484f94a9aSPaolo Bonzini     WriteSameCBData *data;
192584f94a9aSPaolo Bonzini     uint8_t *buf;
192654a53a00SMark Cave-Ayland     int i, l;
192784f94a9aSPaolo Bonzini 
192884f94a9aSPaolo Bonzini     /* Fail if PBDATA=1 or LBDATA=1 or ANCHOR=1.  */
192984f94a9aSPaolo Bonzini     if (nb_sectors == 0 || (req->cmd.buf[1] & 0x16)) {
193084f94a9aSPaolo Bonzini         scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
193184f94a9aSPaolo Bonzini         return;
193284f94a9aSPaolo Bonzini     }
193384f94a9aSPaolo Bonzini 
193486b1cf32SKevin Wolf     if (!blk_is_writable(s->qdev.conf.blk)) {
193584f94a9aSPaolo Bonzini         scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
193684f94a9aSPaolo Bonzini         return;
193784f94a9aSPaolo Bonzini     }
193884f94a9aSPaolo Bonzini     if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
193984f94a9aSPaolo Bonzini         scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
194084f94a9aSPaolo Bonzini         return;
194184f94a9aSPaolo Bonzini     }
194284f94a9aSPaolo Bonzini 
19434397a018SPaolo Bonzini     if ((req->cmd.buf[1] & 0x1) || buffer_is_zero(inbuf, s->qdev.blocksize)) {
194484f94a9aSPaolo Bonzini         int flags = (req->cmd.buf[1] & 0x8) ? BDRV_REQ_MAY_UNMAP : 0;
194584f94a9aSPaolo Bonzini 
194684f94a9aSPaolo Bonzini         /* The request is used as the AIO opaque value, so add a ref.  */
194784f94a9aSPaolo Bonzini         scsi_req_ref(&r->req);
19484be74634SMarkus Armbruster         block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
19495366d0c8SBenoît Canet                          nb_sectors * s->qdev.blocksize,
19505366d0c8SBenoît Canet                         BLOCK_ACCT_WRITE);
1951d004bd52SEric Blake         r->req.aiocb = blk_aio_pwrite_zeroes(s->qdev.conf.blk,
1952983a1600SEric Blake                                 r->req.cmd.lba * s->qdev.blocksize,
1953983a1600SEric Blake                                 nb_sectors * s->qdev.blocksize,
195484f94a9aSPaolo Bonzini                                 flags, scsi_aio_complete, r);
195584f94a9aSPaolo Bonzini         return;
195684f94a9aSPaolo Bonzini     }
195784f94a9aSPaolo Bonzini 
195884f94a9aSPaolo Bonzini     data = g_new0(WriteSameCBData, 1);
195984f94a9aSPaolo Bonzini     data->r = r;
19603dc516bfSPhilippe Mathieu-Daudé     data->sector = r->req.cmd.lba * (s->qdev.blocksize / BDRV_SECTOR_SIZE);
19613dc516bfSPhilippe Mathieu-Daudé     data->nb_sectors = nb_sectors * (s->qdev.blocksize / BDRV_SECTOR_SIZE);
19623dc516bfSPhilippe Mathieu-Daudé     data->iov.iov_len = MIN(data->nb_sectors * BDRV_SECTOR_SIZE,
19633dc516bfSPhilippe Mathieu-Daudé                             SCSI_WRITE_SAME_MAX);
19644be74634SMarkus Armbruster     data->iov.iov_base = buf = blk_blockalign(s->qdev.conf.blk,
19654be74634SMarkus Armbruster                                               data->iov.iov_len);
196684f94a9aSPaolo Bonzini     qemu_iovec_init_external(&data->qiov, &data->iov, 1);
196784f94a9aSPaolo Bonzini 
196854a53a00SMark Cave-Ayland     for (i = 0; i < data->iov.iov_len; i += l) {
196954a53a00SMark Cave-Ayland         l = MIN(s->qdev.blocksize, data->iov.iov_len - i);
197054a53a00SMark Cave-Ayland         memcpy(&buf[i], inbuf, l);
197184f94a9aSPaolo Bonzini     }
197284f94a9aSPaolo Bonzini 
197384f94a9aSPaolo Bonzini     scsi_req_ref(&r->req);
19744be74634SMarkus Armbruster     block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
19755366d0c8SBenoît Canet                      data->iov.iov_len, BLOCK_ACCT_WRITE);
197603c90063SEric Blake     r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk,
197703c90063SEric Blake                                    data->sector << BDRV_SECTOR_BITS,
197803c90063SEric Blake                                    &data->qiov, 0,
197984f94a9aSPaolo Bonzini                                    scsi_write_same_complete, data);
198084f94a9aSPaolo Bonzini }
198184f94a9aSPaolo Bonzini 
scsi_disk_emulate_write_data(SCSIRequest * req)198249ab747fSPaolo Bonzini static void scsi_disk_emulate_write_data(SCSIRequest *req)
198349ab747fSPaolo Bonzini {
198449ab747fSPaolo Bonzini     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
198549ab747fSPaolo Bonzini 
198649ab747fSPaolo Bonzini     if (r->iov.iov_len) {
198749ab747fSPaolo Bonzini         int buflen = r->iov.iov_len;
198859ee9500SLaurent Vivier         trace_scsi_disk_emulate_write_data(buflen);
198949ab747fSPaolo Bonzini         r->iov.iov_len = 0;
199049ab747fSPaolo Bonzini         scsi_req_data(&r->req, buflen);
199149ab747fSPaolo Bonzini         return;
199249ab747fSPaolo Bonzini     }
199349ab747fSPaolo Bonzini 
199449ab747fSPaolo Bonzini     switch (req->cmd.buf[0]) {
199549ab747fSPaolo Bonzini     case MODE_SELECT:
199649ab747fSPaolo Bonzini     case MODE_SELECT_10:
199749ab747fSPaolo Bonzini         /* This also clears the sense buffer for REQUEST SENSE.  */
199849ab747fSPaolo Bonzini         scsi_disk_emulate_mode_select(r, r->iov.iov_base);
199949ab747fSPaolo Bonzini         break;
200049ab747fSPaolo Bonzini 
200149ab747fSPaolo Bonzini     case UNMAP:
200249ab747fSPaolo Bonzini         scsi_disk_emulate_unmap(r, r->iov.iov_base);
200349ab747fSPaolo Bonzini         break;
200449ab747fSPaolo Bonzini 
2005d97e7730SPaolo Bonzini     case VERIFY_10:
2006d97e7730SPaolo Bonzini     case VERIFY_12:
2007d97e7730SPaolo Bonzini     case VERIFY_16:
2008d97e7730SPaolo Bonzini         if (r->req.status == -1) {
2009d97e7730SPaolo Bonzini             scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
2010d97e7730SPaolo Bonzini         }
2011d97e7730SPaolo Bonzini         break;
2012d97e7730SPaolo Bonzini 
201384f94a9aSPaolo Bonzini     case WRITE_SAME_10:
201484f94a9aSPaolo Bonzini     case WRITE_SAME_16:
201584f94a9aSPaolo Bonzini         scsi_disk_emulate_write_same(r, r->iov.iov_base);
201684f94a9aSPaolo Bonzini         break;
2017d97e7730SPaolo Bonzini 
2018be2b619aSMark Cave-Ayland     case FORMAT_UNIT:
2019be2b619aSMark Cave-Ayland         scsi_req_complete(&r->req, GOOD);
2020be2b619aSMark Cave-Ayland         break;
2021be2b619aSMark Cave-Ayland 
202249ab747fSPaolo Bonzini     default:
202349ab747fSPaolo Bonzini         abort();
202449ab747fSPaolo Bonzini     }
202549ab747fSPaolo Bonzini }
202649ab747fSPaolo Bonzini 
scsi_disk_emulate_command(SCSIRequest * req,uint8_t * buf)202749ab747fSPaolo Bonzini static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
202849ab747fSPaolo Bonzini {
202949ab747fSPaolo Bonzini     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
203049ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
203149ab747fSPaolo Bonzini     uint64_t nb_sectors;
203249ab747fSPaolo Bonzini     uint8_t *outbuf;
203349ab747fSPaolo Bonzini     int buflen;
203449ab747fSPaolo Bonzini 
203549ab747fSPaolo Bonzini     switch (req->cmd.buf[0]) {
203649ab747fSPaolo Bonzini     case INQUIRY:
203749ab747fSPaolo Bonzini     case MODE_SENSE:
203849ab747fSPaolo Bonzini     case MODE_SENSE_10:
203949ab747fSPaolo Bonzini     case RESERVE:
204049ab747fSPaolo Bonzini     case RESERVE_10:
204149ab747fSPaolo Bonzini     case RELEASE:
204249ab747fSPaolo Bonzini     case RELEASE_10:
204349ab747fSPaolo Bonzini     case START_STOP:
204449ab747fSPaolo Bonzini     case ALLOW_MEDIUM_REMOVAL:
204549ab747fSPaolo Bonzini     case GET_CONFIGURATION:
204649ab747fSPaolo Bonzini     case GET_EVENT_STATUS_NOTIFICATION:
204749ab747fSPaolo Bonzini     case MECHANISM_STATUS:
204849ab747fSPaolo Bonzini     case REQUEST_SENSE:
204949ab747fSPaolo Bonzini         break;
205049ab747fSPaolo Bonzini 
205149ab747fSPaolo Bonzini     default:
2052cd723b85SFam Zheng         if (!blk_is_available(s->qdev.conf.blk)) {
205349ab747fSPaolo Bonzini             scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
205449ab747fSPaolo Bonzini             return 0;
205549ab747fSPaolo Bonzini         }
205649ab747fSPaolo Bonzini         break;
205749ab747fSPaolo Bonzini     }
205849ab747fSPaolo Bonzini 
205949ab747fSPaolo Bonzini     /*
206049ab747fSPaolo Bonzini      * FIXME: we shouldn't return anything bigger than 4k, but the code
206149ab747fSPaolo Bonzini      * requires the buffer to be as big as req->cmd.xfer in several
206249ab747fSPaolo Bonzini      * places.  So, do not allow CDBs with a very large ALLOCATION
206349ab747fSPaolo Bonzini      * LENGTH.  The real fix would be to modify scsi_read_data and
206449ab747fSPaolo Bonzini      * dma_buf_read, so that they return data beyond the buflen
206549ab747fSPaolo Bonzini      * as all zeros.
206649ab747fSPaolo Bonzini      */
206749ab747fSPaolo Bonzini     if (req->cmd.xfer > 65536) {
206849ab747fSPaolo Bonzini         goto illegal_request;
206949ab747fSPaolo Bonzini     }
207049ab747fSPaolo Bonzini     r->buflen = MAX(4096, req->cmd.xfer);
207149ab747fSPaolo Bonzini 
207249ab747fSPaolo Bonzini     if (!r->iov.iov_base) {
20734be74634SMarkus Armbruster         r->iov.iov_base = blk_blockalign(s->qdev.conf.blk, r->buflen);
207449ab747fSPaolo Bonzini     }
207549ab747fSPaolo Bonzini 
207649ab747fSPaolo Bonzini     outbuf = r->iov.iov_base;
207749ab747fSPaolo Bonzini     memset(outbuf, 0, r->buflen);
207849ab747fSPaolo Bonzini     switch (req->cmd.buf[0]) {
207949ab747fSPaolo Bonzini     case TEST_UNIT_READY:
2080cd723b85SFam Zheng         assert(blk_is_available(s->qdev.conf.blk));
208149ab747fSPaolo Bonzini         break;
208249ab747fSPaolo Bonzini     case INQUIRY:
208349ab747fSPaolo Bonzini         buflen = scsi_disk_emulate_inquiry(req, outbuf);
208449ab747fSPaolo Bonzini         if (buflen < 0) {
208549ab747fSPaolo Bonzini             goto illegal_request;
208649ab747fSPaolo Bonzini         }
208749ab747fSPaolo Bonzini         break;
208849ab747fSPaolo Bonzini     case MODE_SENSE:
208949ab747fSPaolo Bonzini     case MODE_SENSE_10:
209049ab747fSPaolo Bonzini         buflen = scsi_disk_emulate_mode_sense(r, outbuf);
209149ab747fSPaolo Bonzini         if (buflen < 0) {
209249ab747fSPaolo Bonzini             goto illegal_request;
209349ab747fSPaolo Bonzini         }
209449ab747fSPaolo Bonzini         break;
209549ab747fSPaolo Bonzini     case READ_TOC:
209649ab747fSPaolo Bonzini         buflen = scsi_disk_emulate_read_toc(req, outbuf);
209749ab747fSPaolo Bonzini         if (buflen < 0) {
209849ab747fSPaolo Bonzini             goto illegal_request;
209949ab747fSPaolo Bonzini         }
210049ab747fSPaolo Bonzini         break;
210149ab747fSPaolo Bonzini     case RESERVE:
210249ab747fSPaolo Bonzini         if (req->cmd.buf[1] & 1) {
210349ab747fSPaolo Bonzini             goto illegal_request;
210449ab747fSPaolo Bonzini         }
210549ab747fSPaolo Bonzini         break;
210649ab747fSPaolo Bonzini     case RESERVE_10:
210749ab747fSPaolo Bonzini         if (req->cmd.buf[1] & 3) {
210849ab747fSPaolo Bonzini             goto illegal_request;
210949ab747fSPaolo Bonzini         }
211049ab747fSPaolo Bonzini         break;
211149ab747fSPaolo Bonzini     case RELEASE:
211249ab747fSPaolo Bonzini         if (req->cmd.buf[1] & 1) {
211349ab747fSPaolo Bonzini             goto illegal_request;
211449ab747fSPaolo Bonzini         }
211549ab747fSPaolo Bonzini         break;
211649ab747fSPaolo Bonzini     case RELEASE_10:
211749ab747fSPaolo Bonzini         if (req->cmd.buf[1] & 3) {
211849ab747fSPaolo Bonzini             goto illegal_request;
211949ab747fSPaolo Bonzini         }
212049ab747fSPaolo Bonzini         break;
212149ab747fSPaolo Bonzini     case START_STOP:
212249ab747fSPaolo Bonzini         if (scsi_disk_emulate_start_stop(r) < 0) {
212349ab747fSPaolo Bonzini             return 0;
212449ab747fSPaolo Bonzini         }
212549ab747fSPaolo Bonzini         break;
212649ab747fSPaolo Bonzini     case ALLOW_MEDIUM_REMOVAL:
212749ab747fSPaolo Bonzini         s->tray_locked = req->cmd.buf[4] & 1;
21284be74634SMarkus Armbruster         blk_lock_medium(s->qdev.conf.blk, req->cmd.buf[4] & 1);
212949ab747fSPaolo Bonzini         break;
213049ab747fSPaolo Bonzini     case READ_CAPACITY_10:
213149ab747fSPaolo Bonzini         /* The normal LEN field for this command is zero.  */
213249ab747fSPaolo Bonzini         memset(outbuf, 0, 8);
21334be74634SMarkus Armbruster         blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
213449ab747fSPaolo Bonzini         if (!nb_sectors) {
213549ab747fSPaolo Bonzini             scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
213649ab747fSPaolo Bonzini             return 0;
213749ab747fSPaolo Bonzini         }
213849ab747fSPaolo Bonzini         if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
213949ab747fSPaolo Bonzini             goto illegal_request;
214049ab747fSPaolo Bonzini         }
21413dc516bfSPhilippe Mathieu-Daudé         nb_sectors /= s->qdev.blocksize / BDRV_SECTOR_SIZE;
214249ab747fSPaolo Bonzini         /* Returned value is the address of the last sector.  */
214349ab747fSPaolo Bonzini         nb_sectors--;
214449ab747fSPaolo Bonzini         /* Remember the new size for read/write sanity checking. */
214549ab747fSPaolo Bonzini         s->qdev.max_lba = nb_sectors;
214649ab747fSPaolo Bonzini         /* Clip to 2TB, instead of returning capacity modulo 2TB. */
214749ab747fSPaolo Bonzini         if (nb_sectors > UINT32_MAX) {
214849ab747fSPaolo Bonzini             nb_sectors = UINT32_MAX;
214949ab747fSPaolo Bonzini         }
215049ab747fSPaolo Bonzini         outbuf[0] = (nb_sectors >> 24) & 0xff;
215149ab747fSPaolo Bonzini         outbuf[1] = (nb_sectors >> 16) & 0xff;
215249ab747fSPaolo Bonzini         outbuf[2] = (nb_sectors >> 8) & 0xff;
215349ab747fSPaolo Bonzini         outbuf[3] = nb_sectors & 0xff;
215449ab747fSPaolo Bonzini         outbuf[4] = 0;
215549ab747fSPaolo Bonzini         outbuf[5] = 0;
215649ab747fSPaolo Bonzini         outbuf[6] = s->qdev.blocksize >> 8;
215749ab747fSPaolo Bonzini         outbuf[7] = 0;
215849ab747fSPaolo Bonzini         break;
215949ab747fSPaolo Bonzini     case REQUEST_SENSE:
216049ab747fSPaolo Bonzini         /* Just return "NO SENSE".  */
216137b6045cSPaolo Bonzini         buflen = scsi_convert_sense(NULL, 0, outbuf, r->buflen,
216249ab747fSPaolo Bonzini                                     (req->cmd.buf[1] & 1) == 0);
216349ab747fSPaolo Bonzini         if (buflen < 0) {
216449ab747fSPaolo Bonzini             goto illegal_request;
216549ab747fSPaolo Bonzini         }
216649ab747fSPaolo Bonzini         break;
216749ab747fSPaolo Bonzini     case MECHANISM_STATUS:
216849ab747fSPaolo Bonzini         buflen = scsi_emulate_mechanism_status(s, outbuf);
216949ab747fSPaolo Bonzini         if (buflen < 0) {
217049ab747fSPaolo Bonzini             goto illegal_request;
217149ab747fSPaolo Bonzini         }
217249ab747fSPaolo Bonzini         break;
217349ab747fSPaolo Bonzini     case GET_CONFIGURATION:
217449ab747fSPaolo Bonzini         buflen = scsi_get_configuration(s, outbuf);
217549ab747fSPaolo Bonzini         if (buflen < 0) {
217649ab747fSPaolo Bonzini             goto illegal_request;
217749ab747fSPaolo Bonzini         }
217849ab747fSPaolo Bonzini         break;
217949ab747fSPaolo Bonzini     case GET_EVENT_STATUS_NOTIFICATION:
218049ab747fSPaolo Bonzini         buflen = scsi_get_event_status_notification(s, r, outbuf);
218149ab747fSPaolo Bonzini         if (buflen < 0) {
218249ab747fSPaolo Bonzini             goto illegal_request;
218349ab747fSPaolo Bonzini         }
218449ab747fSPaolo Bonzini         break;
218549ab747fSPaolo Bonzini     case READ_DISC_INFORMATION:
218649ab747fSPaolo Bonzini         buflen = scsi_read_disc_information(s, r, outbuf);
218749ab747fSPaolo Bonzini         if (buflen < 0) {
218849ab747fSPaolo Bonzini             goto illegal_request;
218949ab747fSPaolo Bonzini         }
219049ab747fSPaolo Bonzini         break;
219149ab747fSPaolo Bonzini     case READ_DVD_STRUCTURE:
219249ab747fSPaolo Bonzini         buflen = scsi_read_dvd_structure(s, r, outbuf);
219349ab747fSPaolo Bonzini         if (buflen < 0) {
219449ab747fSPaolo Bonzini             goto illegal_request;
219549ab747fSPaolo Bonzini         }
219649ab747fSPaolo Bonzini         break;
219749ab747fSPaolo Bonzini     case SERVICE_ACTION_IN_16:
219849ab747fSPaolo Bonzini         /* Service Action In subcommands. */
219949ab747fSPaolo Bonzini         if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
220059ee9500SLaurent Vivier             trace_scsi_disk_emulate_command_SAI_16();
220149ab747fSPaolo Bonzini             memset(outbuf, 0, req->cmd.xfer);
22024be74634SMarkus Armbruster             blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
220349ab747fSPaolo Bonzini             if (!nb_sectors) {
220449ab747fSPaolo Bonzini                 scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
220549ab747fSPaolo Bonzini                 return 0;
220649ab747fSPaolo Bonzini             }
220749ab747fSPaolo Bonzini             if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
220849ab747fSPaolo Bonzini                 goto illegal_request;
220949ab747fSPaolo Bonzini             }
22103dc516bfSPhilippe Mathieu-Daudé             nb_sectors /= s->qdev.blocksize / BDRV_SECTOR_SIZE;
221149ab747fSPaolo Bonzini             /* Returned value is the address of the last sector.  */
221249ab747fSPaolo Bonzini             nb_sectors--;
221349ab747fSPaolo Bonzini             /* Remember the new size for read/write sanity checking. */
221449ab747fSPaolo Bonzini             s->qdev.max_lba = nb_sectors;
221549ab747fSPaolo Bonzini             outbuf[0] = (nb_sectors >> 56) & 0xff;
221649ab747fSPaolo Bonzini             outbuf[1] = (nb_sectors >> 48) & 0xff;
221749ab747fSPaolo Bonzini             outbuf[2] = (nb_sectors >> 40) & 0xff;
221849ab747fSPaolo Bonzini             outbuf[3] = (nb_sectors >> 32) & 0xff;
221949ab747fSPaolo Bonzini             outbuf[4] = (nb_sectors >> 24) & 0xff;
222049ab747fSPaolo Bonzini             outbuf[5] = (nb_sectors >> 16) & 0xff;
222149ab747fSPaolo Bonzini             outbuf[6] = (nb_sectors >> 8) & 0xff;
222249ab747fSPaolo Bonzini             outbuf[7] = nb_sectors & 0xff;
222349ab747fSPaolo Bonzini             outbuf[8] = 0;
222449ab747fSPaolo Bonzini             outbuf[9] = 0;
222549ab747fSPaolo Bonzini             outbuf[10] = s->qdev.blocksize >> 8;
222649ab747fSPaolo Bonzini             outbuf[11] = 0;
222749ab747fSPaolo Bonzini             outbuf[12] = 0;
222849ab747fSPaolo Bonzini             outbuf[13] = get_physical_block_exp(&s->qdev.conf);
222949ab747fSPaolo Bonzini 
223049ab747fSPaolo Bonzini             /* set TPE bit if the format supports discard */
223149ab747fSPaolo Bonzini             if (s->qdev.conf.discard_granularity) {
223249ab747fSPaolo Bonzini                 outbuf[14] = 0x80;
223349ab747fSPaolo Bonzini             }
223449ab747fSPaolo Bonzini 
223549ab747fSPaolo Bonzini             /* Protection, exponent and lowest lba field left blank. */
223649ab747fSPaolo Bonzini             break;
223749ab747fSPaolo Bonzini         }
223859ee9500SLaurent Vivier         trace_scsi_disk_emulate_command_SAI_unsupported();
223949ab747fSPaolo Bonzini         goto illegal_request;
224049ab747fSPaolo Bonzini     case SYNCHRONIZE_CACHE:
224149ab747fSPaolo Bonzini         /* The request is used as the AIO opaque value, so add a ref.  */
224249ab747fSPaolo Bonzini         scsi_req_ref(&r->req);
22434be74634SMarkus Armbruster         block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
22445366d0c8SBenoît Canet                          BLOCK_ACCT_FLUSH);
22454be74634SMarkus Armbruster         r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r);
224649ab747fSPaolo Bonzini         return 0;
224749ab747fSPaolo Bonzini     case SEEK_10:
224859ee9500SLaurent Vivier         trace_scsi_disk_emulate_command_SEEK_10(r->req.cmd.lba);
224949ab747fSPaolo Bonzini         if (r->req.cmd.lba > s->qdev.max_lba) {
225049ab747fSPaolo Bonzini             goto illegal_lba;
225149ab747fSPaolo Bonzini         }
225249ab747fSPaolo Bonzini         break;
225349ab747fSPaolo Bonzini     case MODE_SELECT:
225459ee9500SLaurent Vivier         trace_scsi_disk_emulate_command_MODE_SELECT(r->req.cmd.xfer);
225549ab747fSPaolo Bonzini         break;
225649ab747fSPaolo Bonzini     case MODE_SELECT_10:
225759ee9500SLaurent Vivier         trace_scsi_disk_emulate_command_MODE_SELECT_10(r->req.cmd.xfer);
225849ab747fSPaolo Bonzini         break;
225949ab747fSPaolo Bonzini     case UNMAP:
226059ee9500SLaurent Vivier         trace_scsi_disk_emulate_command_UNMAP(r->req.cmd.xfer);
226149ab747fSPaolo Bonzini         break;
2262d97e7730SPaolo Bonzini     case VERIFY_10:
2263d97e7730SPaolo Bonzini     case VERIFY_12:
2264d97e7730SPaolo Bonzini     case VERIFY_16:
226559ee9500SLaurent Vivier         trace_scsi_disk_emulate_command_VERIFY((req->cmd.buf[1] >> 1) & 3);
2266d97e7730SPaolo Bonzini         if (req->cmd.buf[1] & 6) {
2267d97e7730SPaolo Bonzini             goto illegal_request;
2268d97e7730SPaolo Bonzini         }
2269d97e7730SPaolo Bonzini         break;
227049ab747fSPaolo Bonzini     case WRITE_SAME_10:
227149ab747fSPaolo Bonzini     case WRITE_SAME_16:
227259ee9500SLaurent Vivier         trace_scsi_disk_emulate_command_WRITE_SAME(
227359ee9500SLaurent Vivier                 req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16, r->req.cmd.xfer);
227484f94a9aSPaolo Bonzini         break;
22756ab71761SMark Cave-Ayland     case FORMAT_UNIT:
22766ab71761SMark Cave-Ayland         trace_scsi_disk_emulate_command_FORMAT_UNIT(r->req.cmd.xfer);
22776ab71761SMark Cave-Ayland         break;
227849ab747fSPaolo Bonzini     default:
227959ee9500SLaurent Vivier         trace_scsi_disk_emulate_command_UNKNOWN(buf[0],
2280b9e77bc7SAlexey Kardashevskiy                                                 scsi_command_name(buf[0]));
228149ab747fSPaolo Bonzini         scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
228249ab747fSPaolo Bonzini         return 0;
228349ab747fSPaolo Bonzini     }
228449ab747fSPaolo Bonzini     assert(!r->req.aiocb);
228549ab747fSPaolo Bonzini     r->iov.iov_len = MIN(r->buflen, req->cmd.xfer);
228649ab747fSPaolo Bonzini     if (r->iov.iov_len == 0) {
228749ab747fSPaolo Bonzini         scsi_req_complete(&r->req, GOOD);
228849ab747fSPaolo Bonzini     }
228949ab747fSPaolo Bonzini     if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
229049ab747fSPaolo Bonzini         assert(r->iov.iov_len == req->cmd.xfer);
229149ab747fSPaolo Bonzini         return -r->iov.iov_len;
229249ab747fSPaolo Bonzini     } else {
229349ab747fSPaolo Bonzini         return r->iov.iov_len;
229449ab747fSPaolo Bonzini     }
229549ab747fSPaolo Bonzini 
229649ab747fSPaolo Bonzini illegal_request:
229749ab747fSPaolo Bonzini     if (r->req.status == -1) {
229849ab747fSPaolo Bonzini         scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
229949ab747fSPaolo Bonzini     }
230049ab747fSPaolo Bonzini     return 0;
230149ab747fSPaolo Bonzini 
230249ab747fSPaolo Bonzini illegal_lba:
230349ab747fSPaolo Bonzini     scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
230449ab747fSPaolo Bonzini     return 0;
230549ab747fSPaolo Bonzini }
230649ab747fSPaolo Bonzini 
230749ab747fSPaolo Bonzini /* Execute a scsi command.  Returns the length of the data expected by the
230849ab747fSPaolo Bonzini    command.  This will be Positive for data transfers from the device
230949ab747fSPaolo Bonzini    (eg. disk reads), negative for transfers to the device (eg. disk writes),
231049ab747fSPaolo Bonzini    and zero if the command does not transfer any data.  */
231149ab747fSPaolo Bonzini 
scsi_disk_dma_command(SCSIRequest * req,uint8_t * buf)231249ab747fSPaolo Bonzini static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
231349ab747fSPaolo Bonzini {
231449ab747fSPaolo Bonzini     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
231549ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
231694f8ba11SPaolo Bonzini     SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
231749ab747fSPaolo Bonzini     uint32_t len;
231849ab747fSPaolo Bonzini     uint8_t command;
231949ab747fSPaolo Bonzini 
232049ab747fSPaolo Bonzini     command = buf[0];
232149ab747fSPaolo Bonzini 
2322cd723b85SFam Zheng     if (!blk_is_available(s->qdev.conf.blk)) {
232349ab747fSPaolo Bonzini         scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
232449ab747fSPaolo Bonzini         return 0;
232549ab747fSPaolo Bonzini     }
232649ab747fSPaolo Bonzini 
23271894df02SHannes Reinecke     len = scsi_data_cdb_xfer(r->req.cmd.buf);
232849ab747fSPaolo Bonzini     switch (command) {
232949ab747fSPaolo Bonzini     case READ_6:
233049ab747fSPaolo Bonzini     case READ_10:
233149ab747fSPaolo Bonzini     case READ_12:
233249ab747fSPaolo Bonzini     case READ_16:
233359ee9500SLaurent Vivier         trace_scsi_disk_dma_command_READ(r->req.cmd.lba, len);
23342343be0dSPaolo Bonzini         /* Protection information is not supported.  For SCSI versions 2 and
23352343be0dSPaolo Bonzini          * older (as determined by snooping the guest's INQUIRY commands),
23362343be0dSPaolo Bonzini          * there is no RD/WR/VRPROTECT, so skip this check in these versions.
23372343be0dSPaolo Bonzini          */
23382343be0dSPaolo Bonzini         if (s->qdev.scsi_version > 2 && (r->req.cmd.buf[1] & 0xe0)) {
233949ab747fSPaolo Bonzini             goto illegal_request;
234049ab747fSPaolo Bonzini         }
234149ab747fSPaolo Bonzini         if (!check_lba_range(s, r->req.cmd.lba, len)) {
234249ab747fSPaolo Bonzini             goto illegal_lba;
234349ab747fSPaolo Bonzini         }
23443dc516bfSPhilippe Mathieu-Daudé         r->sector = r->req.cmd.lba * (s->qdev.blocksize / BDRV_SECTOR_SIZE);
23453dc516bfSPhilippe Mathieu-Daudé         r->sector_count = len * (s->qdev.blocksize / BDRV_SECTOR_SIZE);
234649ab747fSPaolo Bonzini         break;
234749ab747fSPaolo Bonzini     case WRITE_6:
234849ab747fSPaolo Bonzini     case WRITE_10:
234949ab747fSPaolo Bonzini     case WRITE_12:
235049ab747fSPaolo Bonzini     case WRITE_16:
235149ab747fSPaolo Bonzini     case WRITE_VERIFY_10:
235249ab747fSPaolo Bonzini     case WRITE_VERIFY_12:
235349ab747fSPaolo Bonzini     case WRITE_VERIFY_16:
235486b1cf32SKevin Wolf         if (!blk_is_writable(s->qdev.conf.blk)) {
235549ab747fSPaolo Bonzini             scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
235649ab747fSPaolo Bonzini             return 0;
235749ab747fSPaolo Bonzini         }
235859ee9500SLaurent Vivier         trace_scsi_disk_dma_command_WRITE(
235949ab747fSPaolo Bonzini                 (command & 0xe) == 0xe ? "And Verify " : "",
236049ab747fSPaolo Bonzini                 r->req.cmd.lba, len);
23614f04560bSPeter Maydell         /* fall through */
2362166dbda7SPaolo Bonzini     case VERIFY_10:
2363166dbda7SPaolo Bonzini     case VERIFY_12:
2364166dbda7SPaolo Bonzini     case VERIFY_16:
2365166dbda7SPaolo Bonzini         /* We get here only for BYTCHK == 0x01 and only for scsi-block.
2366166dbda7SPaolo Bonzini          * As far as DMA is concerned, we can treat it the same as a write;
2367166dbda7SPaolo Bonzini          * scsi_block_do_sgio will send VERIFY commands.
2368166dbda7SPaolo Bonzini          */
23692343be0dSPaolo Bonzini         if (s->qdev.scsi_version > 2 && (r->req.cmd.buf[1] & 0xe0)) {
237049ab747fSPaolo Bonzini             goto illegal_request;
237149ab747fSPaolo Bonzini         }
237249ab747fSPaolo Bonzini         if (!check_lba_range(s, r->req.cmd.lba, len)) {
237349ab747fSPaolo Bonzini             goto illegal_lba;
237449ab747fSPaolo Bonzini         }
23753dc516bfSPhilippe Mathieu-Daudé         r->sector = r->req.cmd.lba * (s->qdev.blocksize / BDRV_SECTOR_SIZE);
23763dc516bfSPhilippe Mathieu-Daudé         r->sector_count = len * (s->qdev.blocksize / BDRV_SECTOR_SIZE);
237749ab747fSPaolo Bonzini         break;
237849ab747fSPaolo Bonzini     default:
237949ab747fSPaolo Bonzini         abort();
238049ab747fSPaolo Bonzini     illegal_request:
238149ab747fSPaolo Bonzini         scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
238249ab747fSPaolo Bonzini         return 0;
238349ab747fSPaolo Bonzini     illegal_lba:
238449ab747fSPaolo Bonzini         scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
238549ab747fSPaolo Bonzini         return 0;
238649ab747fSPaolo Bonzini     }
238794f8ba11SPaolo Bonzini     r->need_fua_emulation = sdc->need_fua_emulation(&r->req.cmd);
238849ab747fSPaolo Bonzini     if (r->sector_count == 0) {
238949ab747fSPaolo Bonzini         scsi_req_complete(&r->req, GOOD);
239049ab747fSPaolo Bonzini     }
239149ab747fSPaolo Bonzini     assert(r->iov.iov_len == 0);
239249ab747fSPaolo Bonzini     if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
23933dc516bfSPhilippe Mathieu-Daudé         return -r->sector_count * BDRV_SECTOR_SIZE;
239449ab747fSPaolo Bonzini     } else {
23953dc516bfSPhilippe Mathieu-Daudé         return r->sector_count * BDRV_SECTOR_SIZE;
239649ab747fSPaolo Bonzini     }
239749ab747fSPaolo Bonzini }
239849ab747fSPaolo Bonzini 
scsi_disk_reset(DeviceState * dev)239949ab747fSPaolo Bonzini static void scsi_disk_reset(DeviceState *dev)
240049ab747fSPaolo Bonzini {
240149ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
240249ab747fSPaolo Bonzini     uint64_t nb_sectors;
240349ab747fSPaolo Bonzini 
240449ab747fSPaolo Bonzini     scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
240549ab747fSPaolo Bonzini 
24064be74634SMarkus Armbruster     blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
2407c86422c5SEmanuele Giuseppe Esposito 
24083dc516bfSPhilippe Mathieu-Daudé     nb_sectors /= s->qdev.blocksize / BDRV_SECTOR_SIZE;
240949ab747fSPaolo Bonzini     if (nb_sectors) {
241049ab747fSPaolo Bonzini         nb_sectors--;
241149ab747fSPaolo Bonzini     }
241249ab747fSPaolo Bonzini     s->qdev.max_lba = nb_sectors;
24137721c7f7SPavel Hrdina     /* reset tray statuses */
24147721c7f7SPavel Hrdina     s->tray_locked = 0;
24157721c7f7SPavel Hrdina     s->tray_open = 0;
24162343be0dSPaolo Bonzini 
24172343be0dSPaolo Bonzini     s->qdev.scsi_version = s->qdev.default_scsi_version;
241849ab747fSPaolo Bonzini }
241949ab747fSPaolo Bonzini 
scsi_disk_drained_begin(void * opaque)2420766aa2deSStefan Hajnoczi static void scsi_disk_drained_begin(void *opaque)
2421766aa2deSStefan Hajnoczi {
2422766aa2deSStefan Hajnoczi     SCSIDiskState *s = opaque;
2423766aa2deSStefan Hajnoczi 
2424766aa2deSStefan Hajnoczi     scsi_device_drained_begin(&s->qdev);
2425766aa2deSStefan Hajnoczi }
2426766aa2deSStefan Hajnoczi 
scsi_disk_drained_end(void * opaque)2427766aa2deSStefan Hajnoczi static void scsi_disk_drained_end(void *opaque)
2428766aa2deSStefan Hajnoczi {
2429766aa2deSStefan Hajnoczi     SCSIDiskState *s = opaque;
2430766aa2deSStefan Hajnoczi 
2431766aa2deSStefan Hajnoczi     scsi_device_drained_end(&s->qdev);
2432766aa2deSStefan Hajnoczi }
2433766aa2deSStefan Hajnoczi 
scsi_disk_resize_cb(void * opaque)243449ab747fSPaolo Bonzini static void scsi_disk_resize_cb(void *opaque)
243549ab747fSPaolo Bonzini {
243649ab747fSPaolo Bonzini     SCSIDiskState *s = opaque;
243749ab747fSPaolo Bonzini 
243849ab747fSPaolo Bonzini     /* SPC lists this sense code as available only for
243949ab747fSPaolo Bonzini      * direct-access devices.
244049ab747fSPaolo Bonzini      */
244149ab747fSPaolo Bonzini     if (s->qdev.type == TYPE_DISK) {
244249ab747fSPaolo Bonzini         scsi_device_report_change(&s->qdev, SENSE_CODE(CAPACITY_CHANGED));
244349ab747fSPaolo Bonzini     }
244449ab747fSPaolo Bonzini }
244549ab747fSPaolo Bonzini 
scsi_cd_change_media_cb(void * opaque,bool load,Error ** errp)244639829a01SKevin Wolf static void scsi_cd_change_media_cb(void *opaque, bool load, Error **errp)
244749ab747fSPaolo Bonzini {
244849ab747fSPaolo Bonzini     SCSIDiskState *s = opaque;
244949ab747fSPaolo Bonzini 
245049ab747fSPaolo Bonzini     /*
245149ab747fSPaolo Bonzini      * When a CD gets changed, we have to report an ejected state and
245249ab747fSPaolo Bonzini      * then a loaded state to guests so that they detect tray
245349ab747fSPaolo Bonzini      * open/close and media change events.  Guests that do not use
245449ab747fSPaolo Bonzini      * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
245549ab747fSPaolo Bonzini      * states rely on this behavior.
245649ab747fSPaolo Bonzini      *
245749ab747fSPaolo Bonzini      * media_changed governs the state machine used for unit attention
245849ab747fSPaolo Bonzini      * report.  media_event is used by GET EVENT STATUS NOTIFICATION.
245949ab747fSPaolo Bonzini      */
246049ab747fSPaolo Bonzini     s->media_changed = load;
246149ab747fSPaolo Bonzini     s->tray_open = !load;
246249ab747fSPaolo Bonzini     scsi_device_set_ua(&s->qdev, SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM));
246349ab747fSPaolo Bonzini     s->media_event = true;
246449ab747fSPaolo Bonzini     s->eject_request = false;
246549ab747fSPaolo Bonzini }
246649ab747fSPaolo Bonzini 
scsi_cd_eject_request_cb(void * opaque,bool force)246749ab747fSPaolo Bonzini static void scsi_cd_eject_request_cb(void *opaque, bool force)
246849ab747fSPaolo Bonzini {
246949ab747fSPaolo Bonzini     SCSIDiskState *s = opaque;
247049ab747fSPaolo Bonzini 
247149ab747fSPaolo Bonzini     s->eject_request = true;
247249ab747fSPaolo Bonzini     if (force) {
247349ab747fSPaolo Bonzini         s->tray_locked = false;
247449ab747fSPaolo Bonzini     }
247549ab747fSPaolo Bonzini }
247649ab747fSPaolo Bonzini 
scsi_cd_is_tray_open(void * opaque)247749ab747fSPaolo Bonzini static bool scsi_cd_is_tray_open(void *opaque)
247849ab747fSPaolo Bonzini {
247949ab747fSPaolo Bonzini     return ((SCSIDiskState *)opaque)->tray_open;
248049ab747fSPaolo Bonzini }
248149ab747fSPaolo Bonzini 
scsi_cd_is_medium_locked(void * opaque)248249ab747fSPaolo Bonzini static bool scsi_cd_is_medium_locked(void *opaque)
248349ab747fSPaolo Bonzini {
248449ab747fSPaolo Bonzini     return ((SCSIDiskState *)opaque)->tray_locked;
248549ab747fSPaolo Bonzini }
248649ab747fSPaolo Bonzini 
248749ab747fSPaolo Bonzini static const BlockDevOps scsi_disk_removable_block_ops = {
248849ab747fSPaolo Bonzini     .change_media_cb  = scsi_cd_change_media_cb,
2489766aa2deSStefan Hajnoczi     .drained_begin    = scsi_disk_drained_begin,
2490766aa2deSStefan Hajnoczi     .drained_end      = scsi_disk_drained_end,
249149ab747fSPaolo Bonzini     .eject_request_cb = scsi_cd_eject_request_cb,
249249ab747fSPaolo Bonzini     .is_medium_locked = scsi_cd_is_medium_locked,
2493766aa2deSStefan Hajnoczi     .is_tray_open     = scsi_cd_is_tray_open,
249449ab747fSPaolo Bonzini     .resize_cb        = scsi_disk_resize_cb,
249549ab747fSPaolo Bonzini };
249649ab747fSPaolo Bonzini 
249749ab747fSPaolo Bonzini static const BlockDevOps scsi_disk_block_ops = {
2498766aa2deSStefan Hajnoczi     .drained_begin = scsi_disk_drained_begin,
2499766aa2deSStefan Hajnoczi     .drained_end   = scsi_disk_drained_end,
250049ab747fSPaolo Bonzini     .resize_cb     = scsi_disk_resize_cb,
250149ab747fSPaolo Bonzini };
250249ab747fSPaolo Bonzini 
scsi_disk_unit_attention_reported(SCSIDevice * dev)250349ab747fSPaolo Bonzini static void scsi_disk_unit_attention_reported(SCSIDevice *dev)
250449ab747fSPaolo Bonzini {
250549ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
250649ab747fSPaolo Bonzini     if (s->media_changed) {
250749ab747fSPaolo Bonzini         s->media_changed = false;
250849ab747fSPaolo Bonzini         scsi_device_set_ua(&s->qdev, SENSE_CODE(MEDIUM_CHANGED));
250949ab747fSPaolo Bonzini     }
251049ab747fSPaolo Bonzini }
251149ab747fSPaolo Bonzini 
scsi_realize(SCSIDevice * dev,Error ** errp)2512a818a4b6SFam Zheng static void scsi_realize(SCSIDevice *dev, Error **errp)
251349ab747fSPaolo Bonzini {
251449ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
25157cef3d12SKevin Wolf     bool read_only;
251649ab747fSPaolo Bonzini 
25174be74634SMarkus Armbruster     if (!s->qdev.conf.blk) {
2518a818a4b6SFam Zheng         error_setg(errp, "drive property not set");
2519a818a4b6SFam Zheng         return;
252049ab747fSPaolo Bonzini     }
252149ab747fSPaolo Bonzini 
252249ab747fSPaolo Bonzini     if (!(s->features & (1 << SCSI_DISK_F_REMOVABLE)) &&
25234be74634SMarkus Armbruster         !blk_is_inserted(s->qdev.conf.blk)) {
2524a818a4b6SFam Zheng         error_setg(errp, "Device needs media, but drive is empty");
2525a818a4b6SFam Zheng         return;
252649ab747fSPaolo Bonzini     }
252749ab747fSPaolo Bonzini 
2528c56ee92fSRoman Kagan     if (!blkconf_blocksizes(&s->qdev.conf, errp)) {
25293da023b5SMark Kanda         return;
25303da023b5SMark Kanda     }
25313da023b5SMark Kanda 
25324f71fb43SKevin Wolf     if (blk_get_aio_context(s->qdev.conf.blk) != qemu_get_aio_context() &&
25334f71fb43SKevin Wolf         !s->qdev.hba_supports_iothread)
25344f71fb43SKevin Wolf     {
25354f71fb43SKevin Wolf         error_setg(errp, "HBA does not support iothreads");
25364f71fb43SKevin Wolf         return;
25374f71fb43SKevin Wolf     }
25384f71fb43SKevin Wolf 
25395ff5efb4SFam Zheng     if (dev->type == TYPE_DISK) {
2540ceff3e1fSMao Zhongyi         if (!blkconf_geometry(&dev->conf, NULL, 65535, 255, 255, errp)) {
2541a818a4b6SFam Zheng             return;
254249ab747fSPaolo Bonzini         }
25435ff5efb4SFam Zheng     }
25447cef3d12SKevin Wolf 
254586b1cf32SKevin Wolf     read_only = !blk_supports_write_perm(s->qdev.conf.blk);
25467cef3d12SKevin Wolf     if (dev->type == TYPE_ROM) {
25477cef3d12SKevin Wolf         read_only = true;
25487cef3d12SKevin Wolf     }
25497cef3d12SKevin Wolf 
25507cef3d12SKevin Wolf     if (!blkconf_apply_backend_options(&dev->conf, read_only,
2551ceff3e1fSMao Zhongyi                                        dev->type == TYPE_DISK, errp)) {
2552a17c17a2SKevin Wolf         return;
2553a17c17a2SKevin Wolf     }
255449ab747fSPaolo Bonzini 
255549ab747fSPaolo Bonzini     if (s->qdev.conf.discard_granularity == -1) {
255649ab747fSPaolo Bonzini         s->qdev.conf.discard_granularity =
255749ab747fSPaolo Bonzini             MAX(s->qdev.conf.logical_block_size, DEFAULT_DISCARD_GRANULARITY);
255849ab747fSPaolo Bonzini     }
255949ab747fSPaolo Bonzini 
256049ab747fSPaolo Bonzini     if (!s->version) {
256135c2c8dcSEduardo Habkost         s->version = g_strdup(qemu_hw_version());
256249ab747fSPaolo Bonzini     }
256349ab747fSPaolo Bonzini     if (!s->vendor) {
256449ab747fSPaolo Bonzini         s->vendor = g_strdup("QEMU");
256549ab747fSPaolo Bonzini     }
256675997e18SKevin Wolf     if (s->serial && strlen(s->serial) > MAX_SERIAL_LEN) {
256775997e18SKevin Wolf         error_setg(errp, "The serial number can't be longer than %d characters",
256875997e18SKevin Wolf                    MAX_SERIAL_LEN);
256975997e18SKevin Wolf         return;
257075997e18SKevin Wolf     }
25717471a649SKevin Wolf     if (!s->device_id) {
25727471a649SKevin Wolf         if (s->serial) {
257375997e18SKevin Wolf             if (strlen(s->serial) > MAX_SERIAL_LEN_FOR_DEVID) {
257475997e18SKevin Wolf                 error_setg(errp, "The serial number can't be longer than %d "
257575997e18SKevin Wolf                            "characters when it is also used as the default for "
257675997e18SKevin Wolf                            "device_id", MAX_SERIAL_LEN_FOR_DEVID);
257775997e18SKevin Wolf                 return;
257875997e18SKevin Wolf             }
257975997e18SKevin Wolf             s->device_id = g_strdup(s->serial);
25807471a649SKevin Wolf         } else {
25817471a649SKevin Wolf             const char *str = blk_name(s->qdev.conf.blk);
25827471a649SKevin Wolf             if (str && *str) {
25837471a649SKevin Wolf                 s->device_id = g_strdup(str);
25847471a649SKevin Wolf             }
25857471a649SKevin Wolf         }
25867471a649SKevin Wolf     }
258749ab747fSPaolo Bonzini 
25884be74634SMarkus Armbruster     if (blk_is_sg(s->qdev.conf.blk)) {
2589a818a4b6SFam Zheng         error_setg(errp, "unwanted /dev/sg*");
2590a818a4b6SFam Zheng         return;
259149ab747fSPaolo Bonzini     }
259249ab747fSPaolo Bonzini 
259318e673b8SPavel Hrdina     if ((s->features & (1 << SCSI_DISK_F_REMOVABLE)) &&
259418e673b8SPavel Hrdina             !(s->features & (1 << SCSI_DISK_F_NO_REMOVABLE_DEVOPS))) {
25954be74634SMarkus Armbruster         blk_set_dev_ops(s->qdev.conf.blk, &scsi_disk_removable_block_ops, s);
259649ab747fSPaolo Bonzini     } else {
25974be74634SMarkus Armbruster         blk_set_dev_ops(s->qdev.conf.blk, &scsi_disk_block_ops, s);
259849ab747fSPaolo Bonzini     }
259949ab747fSPaolo Bonzini 
26004be74634SMarkus Armbruster     blk_iostatus_enable(s->qdev.conf.blk);
260171f571a2SSam Eiderman 
260271f571a2SSam Eiderman     add_boot_device_lchs(&dev->qdev, NULL,
260371f571a2SSam Eiderman                          dev->conf.lcyls,
260471f571a2SSam Eiderman                          dev->conf.lheads,
260571f571a2SSam Eiderman                          dev->conf.lsecs);
260671f571a2SSam Eiderman }
260771f571a2SSam Eiderman 
scsi_unrealize(SCSIDevice * dev)2608b69c3c21SMarkus Armbruster static void scsi_unrealize(SCSIDevice *dev)
260971f571a2SSam Eiderman {
261071f571a2SSam Eiderman     del_boot_device_lchs(&dev->qdev, NULL);
261149ab747fSPaolo Bonzini }
261249ab747fSPaolo Bonzini 
scsi_hd_realize(SCSIDevice * dev,Error ** errp)2613a818a4b6SFam Zheng static void scsi_hd_realize(SCSIDevice *dev, Error **errp)
261449ab747fSPaolo Bonzini {
261549ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
26164f36b138SStefan Hajnoczi 
2617df1d4c34SEkaterina Tumanova     /* can happen for devices without drive. The error message for missing
2618df1d4c34SEkaterina Tumanova      * backend will be issued in scsi_realize
2619df1d4c34SEkaterina Tumanova      */
2620df1d4c34SEkaterina Tumanova     if (s->qdev.conf.blk) {
2621c56ee92fSRoman Kagan         if (!blkconf_blocksizes(&s->qdev.conf, errp)) {
26224f36b138SStefan Hajnoczi             return;
2623c56ee92fSRoman Kagan         }
2624df1d4c34SEkaterina Tumanova     }
262549ab747fSPaolo Bonzini     s->qdev.blocksize = s->qdev.conf.logical_block_size;
262649ab747fSPaolo Bonzini     s->qdev.type = TYPE_DISK;
262749ab747fSPaolo Bonzini     if (!s->product) {
262849ab747fSPaolo Bonzini         s->product = g_strdup("QEMU HARDDISK");
262949ab747fSPaolo Bonzini     }
2630a818a4b6SFam Zheng     scsi_realize(&s->qdev, errp);
263149ab747fSPaolo Bonzini }
263249ab747fSPaolo Bonzini 
scsi_cd_realize(SCSIDevice * dev,Error ** errp)2633a818a4b6SFam Zheng static void scsi_cd_realize(SCSIDevice *dev, Error **errp)
263449ab747fSPaolo Bonzini {
263549ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
263683b4fe0eSKevin Wolf     int ret;
2637298c31deSJohn Millikin     uint32_t blocksize = 2048;
26389ef6e505SKevin Wolf 
26399ef6e505SKevin Wolf     if (!dev->conf.blk) {
264083b4fe0eSKevin Wolf         /* Anonymous BlockBackend for an empty drive. As we put it into
264183b4fe0eSKevin Wolf          * dev->conf, qdev takes care of detaching on unplug. */
2642d861ab3aSKevin Wolf         dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
264383b4fe0eSKevin Wolf         ret = blk_attach_dev(dev->conf.blk, &dev->qdev);
264483b4fe0eSKevin Wolf         assert(ret == 0);
26459ef6e505SKevin Wolf     }
26469ef6e505SKevin Wolf 
2647298c31deSJohn Millikin     if (dev->conf.physical_block_size != 0) {
2648298c31deSJohn Millikin         blocksize = dev->conf.physical_block_size;
2649298c31deSJohn Millikin     }
2650298c31deSJohn Millikin 
2651298c31deSJohn Millikin     s->qdev.blocksize = blocksize;
265249ab747fSPaolo Bonzini     s->qdev.type = TYPE_ROM;
265349ab747fSPaolo Bonzini     s->features |= 1 << SCSI_DISK_F_REMOVABLE;
265449ab747fSPaolo Bonzini     if (!s->product) {
265549ab747fSPaolo Bonzini         s->product = g_strdup("QEMU CD-ROM");
265649ab747fSPaolo Bonzini     }
2657a818a4b6SFam Zheng     scsi_realize(&s->qdev, errp);
265849ab747fSPaolo Bonzini }
265949ab747fSPaolo Bonzini 
266049ab747fSPaolo Bonzini 
266149ab747fSPaolo Bonzini static const SCSIReqOps scsi_disk_emulate_reqops = {
266249ab747fSPaolo Bonzini     .size         = sizeof(SCSIDiskReq),
266349ab747fSPaolo Bonzini     .free_req     = scsi_free_request,
266449ab747fSPaolo Bonzini     .send_command = scsi_disk_emulate_command,
266549ab747fSPaolo Bonzini     .read_data    = scsi_disk_emulate_read_data,
266649ab747fSPaolo Bonzini     .write_data   = scsi_disk_emulate_write_data,
266749ab747fSPaolo Bonzini     .get_buf      = scsi_get_buf,
2668b4912afaSHyman Huang     .load_request = scsi_disk_emulate_load_request,
2669b4912afaSHyman Huang     .save_request = scsi_disk_emulate_save_request,
267049ab747fSPaolo Bonzini };
267149ab747fSPaolo Bonzini 
267249ab747fSPaolo Bonzini static const SCSIReqOps scsi_disk_dma_reqops = {
267349ab747fSPaolo Bonzini     .size         = sizeof(SCSIDiskReq),
267449ab747fSPaolo Bonzini     .free_req     = scsi_free_request,
267549ab747fSPaolo Bonzini     .send_command = scsi_disk_dma_command,
267649ab747fSPaolo Bonzini     .read_data    = scsi_read_data,
267749ab747fSPaolo Bonzini     .write_data   = scsi_write_data,
267849ab747fSPaolo Bonzini     .get_buf      = scsi_get_buf,
267949ab747fSPaolo Bonzini     .load_request = scsi_disk_load_request,
268049ab747fSPaolo Bonzini     .save_request = scsi_disk_save_request,
268149ab747fSPaolo Bonzini };
268249ab747fSPaolo Bonzini 
268349ab747fSPaolo Bonzini static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
268449ab747fSPaolo Bonzini     [TEST_UNIT_READY]                 = &scsi_disk_emulate_reqops,
268549ab747fSPaolo Bonzini     [INQUIRY]                         = &scsi_disk_emulate_reqops,
268649ab747fSPaolo Bonzini     [MODE_SENSE]                      = &scsi_disk_emulate_reqops,
268749ab747fSPaolo Bonzini     [MODE_SENSE_10]                   = &scsi_disk_emulate_reqops,
268849ab747fSPaolo Bonzini     [START_STOP]                      = &scsi_disk_emulate_reqops,
268949ab747fSPaolo Bonzini     [ALLOW_MEDIUM_REMOVAL]            = &scsi_disk_emulate_reqops,
269049ab747fSPaolo Bonzini     [READ_CAPACITY_10]                = &scsi_disk_emulate_reqops,
269149ab747fSPaolo Bonzini     [READ_TOC]                        = &scsi_disk_emulate_reqops,
269249ab747fSPaolo Bonzini     [READ_DVD_STRUCTURE]              = &scsi_disk_emulate_reqops,
269349ab747fSPaolo Bonzini     [READ_DISC_INFORMATION]           = &scsi_disk_emulate_reqops,
269449ab747fSPaolo Bonzini     [GET_CONFIGURATION]               = &scsi_disk_emulate_reqops,
269549ab747fSPaolo Bonzini     [GET_EVENT_STATUS_NOTIFICATION]   = &scsi_disk_emulate_reqops,
269649ab747fSPaolo Bonzini     [MECHANISM_STATUS]                = &scsi_disk_emulate_reqops,
269749ab747fSPaolo Bonzini     [SERVICE_ACTION_IN_16]            = &scsi_disk_emulate_reqops,
269849ab747fSPaolo Bonzini     [REQUEST_SENSE]                   = &scsi_disk_emulate_reqops,
269949ab747fSPaolo Bonzini     [SYNCHRONIZE_CACHE]               = &scsi_disk_emulate_reqops,
270049ab747fSPaolo Bonzini     [SEEK_10]                         = &scsi_disk_emulate_reqops,
270149ab747fSPaolo Bonzini     [MODE_SELECT]                     = &scsi_disk_emulate_reqops,
270249ab747fSPaolo Bonzini     [MODE_SELECT_10]                  = &scsi_disk_emulate_reqops,
270349ab747fSPaolo Bonzini     [UNMAP]                           = &scsi_disk_emulate_reqops,
270449ab747fSPaolo Bonzini     [WRITE_SAME_10]                   = &scsi_disk_emulate_reqops,
270549ab747fSPaolo Bonzini     [WRITE_SAME_16]                   = &scsi_disk_emulate_reqops,
2706d97e7730SPaolo Bonzini     [VERIFY_10]                       = &scsi_disk_emulate_reqops,
2707d97e7730SPaolo Bonzini     [VERIFY_12]                       = &scsi_disk_emulate_reqops,
2708d97e7730SPaolo Bonzini     [VERIFY_16]                       = &scsi_disk_emulate_reqops,
27096ab71761SMark Cave-Ayland     [FORMAT_UNIT]                     = &scsi_disk_emulate_reqops,
271049ab747fSPaolo Bonzini 
271149ab747fSPaolo Bonzini     [READ_6]                          = &scsi_disk_dma_reqops,
271249ab747fSPaolo Bonzini     [READ_10]                         = &scsi_disk_dma_reqops,
271349ab747fSPaolo Bonzini     [READ_12]                         = &scsi_disk_dma_reqops,
271449ab747fSPaolo Bonzini     [READ_16]                         = &scsi_disk_dma_reqops,
271549ab747fSPaolo Bonzini     [WRITE_6]                         = &scsi_disk_dma_reqops,
271649ab747fSPaolo Bonzini     [WRITE_10]                        = &scsi_disk_dma_reqops,
271749ab747fSPaolo Bonzini     [WRITE_12]                        = &scsi_disk_dma_reqops,
271849ab747fSPaolo Bonzini     [WRITE_16]                        = &scsi_disk_dma_reqops,
271949ab747fSPaolo Bonzini     [WRITE_VERIFY_10]                 = &scsi_disk_dma_reqops,
272049ab747fSPaolo Bonzini     [WRITE_VERIFY_12]                 = &scsi_disk_dma_reqops,
272149ab747fSPaolo Bonzini     [WRITE_VERIFY_16]                 = &scsi_disk_dma_reqops,
272249ab747fSPaolo Bonzini };
272349ab747fSPaolo Bonzini 
scsi_disk_new_request_dump(uint32_t lun,uint32_t tag,uint8_t * buf)272459ee9500SLaurent Vivier static void scsi_disk_new_request_dump(uint32_t lun, uint32_t tag, uint8_t *buf)
272559ee9500SLaurent Vivier {
272659ee9500SLaurent Vivier     int len = scsi_cdb_length(buf);
272700a17d80SPhilippe Mathieu-Daudé     g_autoptr(GString) str = NULL;
272859ee9500SLaurent Vivier 
2729e91bae8eSEric Blake     assert(len > 0 && len <= 16);
273000a17d80SPhilippe Mathieu-Daudé     str = qemu_hexdump_line(NULL, buf, len, 1, 0);
273100a17d80SPhilippe Mathieu-Daudé     trace_scsi_disk_new_request(lun, tag, str->str);
273259ee9500SLaurent Vivier }
273359ee9500SLaurent Vivier 
scsi_new_request(SCSIDevice * d,uint32_t tag,uint32_t lun,uint8_t * buf,void * hba_private)273449ab747fSPaolo Bonzini static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
273549ab747fSPaolo Bonzini                                      uint8_t *buf, void *hba_private)
273649ab747fSPaolo Bonzini {
273749ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
273849ab747fSPaolo Bonzini     SCSIRequest *req;
273949ab747fSPaolo Bonzini     const SCSIReqOps *ops;
274049ab747fSPaolo Bonzini     uint8_t command;
274149ab747fSPaolo Bonzini 
274249ab747fSPaolo Bonzini     command = buf[0];
274349ab747fSPaolo Bonzini     ops = scsi_disk_reqops_dispatch[command];
274449ab747fSPaolo Bonzini     if (!ops) {
274549ab747fSPaolo Bonzini         ops = &scsi_disk_emulate_reqops;
274649ab747fSPaolo Bonzini     }
274749ab747fSPaolo Bonzini     req = scsi_req_alloc(ops, &s->qdev, tag, lun, hba_private);
274849ab747fSPaolo Bonzini 
274959ee9500SLaurent Vivier     if (trace_event_get_state_backends(TRACE_SCSI_DISK_NEW_REQUEST)) {
275059ee9500SLaurent Vivier         scsi_disk_new_request_dump(lun, tag, buf);
275149ab747fSPaolo Bonzini     }
275249ab747fSPaolo Bonzini 
275349ab747fSPaolo Bonzini     return req;
275449ab747fSPaolo Bonzini }
275549ab747fSPaolo Bonzini 
275649ab747fSPaolo Bonzini #ifdef __linux__
get_device_type(SCSIDiskState * s)275749ab747fSPaolo Bonzini static int get_device_type(SCSIDiskState *s)
275849ab747fSPaolo Bonzini {
275949ab747fSPaolo Bonzini     uint8_t cmd[16];
276049ab747fSPaolo Bonzini     uint8_t buf[36];
276149ab747fSPaolo Bonzini     int ret;
276249ab747fSPaolo Bonzini 
276349ab747fSPaolo Bonzini     memset(cmd, 0, sizeof(cmd));
276449ab747fSPaolo Bonzini     memset(buf, 0, sizeof(buf));
276549ab747fSPaolo Bonzini     cmd[0] = INQUIRY;
276649ab747fSPaolo Bonzini     cmd[4] = sizeof(buf);
276749ab747fSPaolo Bonzini 
2768a0c7e35bSDaniel Henrique Barboza     ret = scsi_SG_IO_FROM_DEV(s->qdev.conf.blk, cmd, sizeof(cmd),
2769c9b6609bSHannes Reinecke                               buf, sizeof(buf), s->qdev.io_timeout);
2770a0c7e35bSDaniel Henrique Barboza     if (ret < 0) {
277149ab747fSPaolo Bonzini         return -1;
277249ab747fSPaolo Bonzini     }
277349ab747fSPaolo Bonzini     s->qdev.type = buf[0];
277449ab747fSPaolo Bonzini     if (buf[1] & 0x80) {
277549ab747fSPaolo Bonzini         s->features |= 1 << SCSI_DISK_F_REMOVABLE;
277649ab747fSPaolo Bonzini     }
277749ab747fSPaolo Bonzini     return 0;
277849ab747fSPaolo Bonzini }
277949ab747fSPaolo Bonzini 
scsi_block_realize(SCSIDevice * dev,Error ** errp)2780a818a4b6SFam Zheng static void scsi_block_realize(SCSIDevice *dev, Error **errp)
278149ab747fSPaolo Bonzini {
278249ab747fSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
278349ab747fSPaolo Bonzini     int sg_version;
278449ab747fSPaolo Bonzini     int rc;
278549ab747fSPaolo Bonzini 
27864be74634SMarkus Armbruster     if (!s->qdev.conf.blk) {
2787a818a4b6SFam Zheng         error_setg(errp, "drive property not set");
2788a818a4b6SFam Zheng         return;
278949ab747fSPaolo Bonzini     }
279049ab747fSPaolo Bonzini 
279151f43d57SFam Zheng     if (s->rotation_rate) {
279251f43d57SFam Zheng         error_report_once("rotation_rate is specified for scsi-block but is "
279351f43d57SFam Zheng                           "not implemented. This option is deprecated and will "
279451f43d57SFam Zheng                           "be removed in a future version");
279551f43d57SFam Zheng     }
279651f43d57SFam Zheng 
279749ab747fSPaolo Bonzini     /* check we are using a driver managing SG_IO (version 3 and after) */
27984be74634SMarkus Armbruster     rc = blk_ioctl(s->qdev.conf.blk, SG_GET_VERSION_NUM, &sg_version);
27994bbeb8b1SFam Zheng     if (rc < 0) {
280009c2c6ffSPaolo Bonzini         error_setg_errno(errp, -rc, "cannot get SG_IO version number");
280109c2c6ffSPaolo Bonzini         if (rc != -EPERM) {
280209c2c6ffSPaolo Bonzini             error_append_hint(errp, "Is this a SCSI device?\n");
280309c2c6ffSPaolo Bonzini         }
28044f36b138SStefan Hajnoczi         return;
28054bbeb8b1SFam Zheng     }
28064bbeb8b1SFam Zheng     if (sg_version < 30000) {
2807a818a4b6SFam Zheng         error_setg(errp, "scsi generic interface too old");
28084f36b138SStefan Hajnoczi         return;
280949ab747fSPaolo Bonzini     }
281049ab747fSPaolo Bonzini 
281149ab747fSPaolo Bonzini     /* get device type from INQUIRY data */
281249ab747fSPaolo Bonzini     rc = get_device_type(s);
281349ab747fSPaolo Bonzini     if (rc < 0) {
2814a818a4b6SFam Zheng         error_setg(errp, "INQUIRY failed");
28154f36b138SStefan Hajnoczi         return;
281649ab747fSPaolo Bonzini     }
281749ab747fSPaolo Bonzini 
281849ab747fSPaolo Bonzini     /* Make a guess for the block size, we'll fix it when the guest sends.
281949ab747fSPaolo Bonzini      * READ CAPACITY.  If they don't, they likely would assume these sizes
282049ab747fSPaolo Bonzini      * anyway. (TODO: check in /sys).
282149ab747fSPaolo Bonzini      */
282249ab747fSPaolo Bonzini     if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM) {
282349ab747fSPaolo Bonzini         s->qdev.blocksize = 2048;
282449ab747fSPaolo Bonzini     } else {
282549ab747fSPaolo Bonzini         s->qdev.blocksize = 512;
282649ab747fSPaolo Bonzini     }
282718e673b8SPavel Hrdina 
282818e673b8SPavel Hrdina     /* Makes the scsi-block device not removable by using HMP and QMP eject
282918e673b8SPavel Hrdina      * command.
283018e673b8SPavel Hrdina      */
283118e673b8SPavel Hrdina     s->features |= (1 << SCSI_DISK_F_NO_REMOVABLE_DEVOPS);
283218e673b8SPavel Hrdina 
2833a818a4b6SFam Zheng     scsi_realize(&s->qdev, errp);
2834a71c775bSDaniel Henrique Barboza     scsi_generic_read_device_inquiry(&s->qdev);
283549ab747fSPaolo Bonzini }
283649ab747fSPaolo Bonzini 
28378fdc7839SPaolo Bonzini typedef struct SCSIBlockReq {
28388fdc7839SPaolo Bonzini     SCSIDiskReq req;
28398fdc7839SPaolo Bonzini     sg_io_hdr_t io_header;
28408fdc7839SPaolo Bonzini 
28418fdc7839SPaolo Bonzini     /* Selected bytes of the original CDB, copied into our own CDB.  */
28428fdc7839SPaolo Bonzini     uint8_t cmd, cdb1, group_number;
28438fdc7839SPaolo Bonzini 
28448fdc7839SPaolo Bonzini     /* CDB passed to SG_IO.  */
28458fdc7839SPaolo Bonzini     uint8_t cdb[16];
2846a108557bSHannes Reinecke     BlockCompletionFunc *cb;
2847a108557bSHannes Reinecke     void *cb_opaque;
28488fdc7839SPaolo Bonzini } SCSIBlockReq;
28498fdc7839SPaolo Bonzini 
scsi_block_sgio_complete(void * opaque,int ret)2850a108557bSHannes Reinecke static void scsi_block_sgio_complete(void *opaque, int ret)
2851a108557bSHannes Reinecke {
2852a108557bSHannes Reinecke     SCSIBlockReq *req = (SCSIBlockReq *)opaque;
2853a108557bSHannes Reinecke     SCSIDiskReq *r = &req->req;
2854a108557bSHannes Reinecke     sg_io_hdr_t *io_hdr = &req->io_header;
2855a108557bSHannes Reinecke 
2856a108557bSHannes Reinecke     if (ret == 0) {
28578a049562SKevin Wolf         /* FIXME This skips calling req->cb() and any cleanup in it */
2858a108557bSHannes Reinecke         if (io_hdr->host_status != SCSI_HOST_OK) {
2859f3126d65SHannes Reinecke             scsi_req_complete_failed(&r->req, io_hdr->host_status);
2860f3126d65SHannes Reinecke             scsi_req_unref(&r->req);
2861f3126d65SHannes Reinecke             return;
2862a108557bSHannes Reinecke         }
2863f3126d65SHannes Reinecke 
2864f3126d65SHannes Reinecke         if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
2865a108557bSHannes Reinecke             ret = BUSY;
2866a108557bSHannes Reinecke         } else {
2867a108557bSHannes Reinecke             ret = io_hdr->status;
2868a108557bSHannes Reinecke         }
2869a108557bSHannes Reinecke     }
2870a108557bSHannes Reinecke 
2871a108557bSHannes Reinecke     req->cb(req->cb_opaque, ret);
2872a108557bSHannes Reinecke }
2873a108557bSHannes Reinecke 
scsi_block_do_sgio(SCSIBlockReq * req,int64_t offset,QEMUIOVector * iov,int direction,BlockCompletionFunc * cb,void * opaque)28748fdc7839SPaolo Bonzini static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
28758fdc7839SPaolo Bonzini                                       int64_t offset, QEMUIOVector *iov,
28768fdc7839SPaolo Bonzini                                       int direction,
28778fdc7839SPaolo Bonzini                                       BlockCompletionFunc *cb, void *opaque)
28788fdc7839SPaolo Bonzini {
28798fdc7839SPaolo Bonzini     sg_io_hdr_t *io_header = &req->io_header;
28808fdc7839SPaolo Bonzini     SCSIDiskReq *r = &req->req;
28818fdc7839SPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
28828fdc7839SPaolo Bonzini     int nb_logical_blocks;
28838fdc7839SPaolo Bonzini     uint64_t lba;
28848fdc7839SPaolo Bonzini     BlockAIOCB *aiocb;
28858fdc7839SPaolo Bonzini 
28868fdc7839SPaolo Bonzini     /* This is not supported yet.  It can only happen if the guest does
28878fdc7839SPaolo Bonzini      * reads and writes that are not aligned to one logical sectors
28888fdc7839SPaolo Bonzini      * _and_ cover multiple MemoryRegions.
28898fdc7839SPaolo Bonzini      */
28908fdc7839SPaolo Bonzini     assert(offset % s->qdev.blocksize == 0);
28918fdc7839SPaolo Bonzini     assert(iov->size % s->qdev.blocksize == 0);
28928fdc7839SPaolo Bonzini 
28938fdc7839SPaolo Bonzini     io_header->interface_id = 'S';
28948fdc7839SPaolo Bonzini 
28958fdc7839SPaolo Bonzini     /* The data transfer comes from the QEMUIOVector.  */
28968fdc7839SPaolo Bonzini     io_header->dxfer_direction = direction;
28978fdc7839SPaolo Bonzini     io_header->dxfer_len = iov->size;
28988fdc7839SPaolo Bonzini     io_header->dxferp = (void *)iov->iov;
28998fdc7839SPaolo Bonzini     io_header->iovec_count = iov->niov;
29008fdc7839SPaolo Bonzini     assert(io_header->iovec_count == iov->niov); /* no overflow! */
29018fdc7839SPaolo Bonzini 
29028fdc7839SPaolo Bonzini     /* Build a new CDB with the LBA and length patched in, in case
29038fdc7839SPaolo Bonzini      * DMA helpers split the transfer in multiple segments.  Do not
29048fdc7839SPaolo Bonzini      * build a CDB smaller than what the guest wanted, and only build
29058fdc7839SPaolo Bonzini      * a larger one if strictly necessary.
29068fdc7839SPaolo Bonzini      */
29078fdc7839SPaolo Bonzini     io_header->cmdp = req->cdb;
29088fdc7839SPaolo Bonzini     lba = offset / s->qdev.blocksize;
29098fdc7839SPaolo Bonzini     nb_logical_blocks = io_header->dxfer_len / s->qdev.blocksize;
29108fdc7839SPaolo Bonzini 
29118fdc7839SPaolo Bonzini     if ((req->cmd >> 5) == 0 && lba <= 0x1ffff) {
29128fdc7839SPaolo Bonzini         /* 6-byte CDB */
29138fdc7839SPaolo Bonzini         stl_be_p(&req->cdb[0], lba | (req->cmd << 24));
29148fdc7839SPaolo Bonzini         req->cdb[4] = nb_logical_blocks;
29158fdc7839SPaolo Bonzini         req->cdb[5] = 0;
29168fdc7839SPaolo Bonzini         io_header->cmd_len = 6;
29178fdc7839SPaolo Bonzini     } else if ((req->cmd >> 5) <= 1 && lba <= 0xffffffffULL) {
29188fdc7839SPaolo Bonzini         /* 10-byte CDB */
29198fdc7839SPaolo Bonzini         req->cdb[0] = (req->cmd & 0x1f) | 0x20;
29208fdc7839SPaolo Bonzini         req->cdb[1] = req->cdb1;
29218fdc7839SPaolo Bonzini         stl_be_p(&req->cdb[2], lba);
29228fdc7839SPaolo Bonzini         req->cdb[6] = req->group_number;
29238fdc7839SPaolo Bonzini         stw_be_p(&req->cdb[7], nb_logical_blocks);
29248fdc7839SPaolo Bonzini         req->cdb[9] = 0;
29258fdc7839SPaolo Bonzini         io_header->cmd_len = 10;
29268fdc7839SPaolo Bonzini     } else if ((req->cmd >> 5) != 4 && lba <= 0xffffffffULL) {
29278fdc7839SPaolo Bonzini         /* 12-byte CDB */
29288fdc7839SPaolo Bonzini         req->cdb[0] = (req->cmd & 0x1f) | 0xA0;
29298fdc7839SPaolo Bonzini         req->cdb[1] = req->cdb1;
29308fdc7839SPaolo Bonzini         stl_be_p(&req->cdb[2], lba);
29318fdc7839SPaolo Bonzini         stl_be_p(&req->cdb[6], nb_logical_blocks);
29328fdc7839SPaolo Bonzini         req->cdb[10] = req->group_number;
29338fdc7839SPaolo Bonzini         req->cdb[11] = 0;
29348fdc7839SPaolo Bonzini         io_header->cmd_len = 12;
29358fdc7839SPaolo Bonzini     } else {
29368fdc7839SPaolo Bonzini         /* 16-byte CDB */
29378fdc7839SPaolo Bonzini         req->cdb[0] = (req->cmd & 0x1f) | 0x80;
29388fdc7839SPaolo Bonzini         req->cdb[1] = req->cdb1;
29398fdc7839SPaolo Bonzini         stq_be_p(&req->cdb[2], lba);
29408fdc7839SPaolo Bonzini         stl_be_p(&req->cdb[10], nb_logical_blocks);
29418fdc7839SPaolo Bonzini         req->cdb[14] = req->group_number;
29428fdc7839SPaolo Bonzini         req->cdb[15] = 0;
29438fdc7839SPaolo Bonzini         io_header->cmd_len = 16;
29448fdc7839SPaolo Bonzini     }
29458fdc7839SPaolo Bonzini 
29468fdc7839SPaolo Bonzini     /* The rest is as in scsi-generic.c.  */
29478fdc7839SPaolo Bonzini     io_header->mx_sb_len = sizeof(r->req.sense);
29488fdc7839SPaolo Bonzini     io_header->sbp = r->req.sense;
2949c9b6609bSHannes Reinecke     io_header->timeout = s->qdev.io_timeout * 1000;
29508fdc7839SPaolo Bonzini     io_header->usr_ptr = r;
29518fdc7839SPaolo Bonzini     io_header->flags |= SG_FLAG_DIRECT_IO;
2952a108557bSHannes Reinecke     req->cb = cb;
2953a108557bSHannes Reinecke     req->cb_opaque = opaque;
2954b2d50a33SHannes Reinecke     trace_scsi_disk_aio_sgio_command(r->req.tag, req->cdb[0], lba,
2955b2d50a33SHannes Reinecke                                      nb_logical_blocks, io_header->timeout);
2956a108557bSHannes Reinecke     aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, scsi_block_sgio_complete, req);
29578fdc7839SPaolo Bonzini     assert(aiocb != NULL);
29588fdc7839SPaolo Bonzini     return aiocb;
29598fdc7839SPaolo Bonzini }
29608fdc7839SPaolo Bonzini 
scsi_block_no_fua(SCSICommand * cmd)29618fdc7839SPaolo Bonzini static bool scsi_block_no_fua(SCSICommand *cmd)
29628fdc7839SPaolo Bonzini {
29638fdc7839SPaolo Bonzini     return false;
29648fdc7839SPaolo Bonzini }
29658fdc7839SPaolo Bonzini 
scsi_block_dma_readv(int64_t offset,QEMUIOVector * iov,BlockCompletionFunc * cb,void * cb_opaque,void * opaque)29668fdc7839SPaolo Bonzini static BlockAIOCB *scsi_block_dma_readv(int64_t offset,
29678fdc7839SPaolo Bonzini                                         QEMUIOVector *iov,
29688fdc7839SPaolo Bonzini                                         BlockCompletionFunc *cb, void *cb_opaque,
29698fdc7839SPaolo Bonzini                                         void *opaque)
29708fdc7839SPaolo Bonzini {
29718fdc7839SPaolo Bonzini     SCSIBlockReq *r = opaque;
29728fdc7839SPaolo Bonzini     return scsi_block_do_sgio(r, offset, iov,
29738fdc7839SPaolo Bonzini                               SG_DXFER_FROM_DEV, cb, cb_opaque);
29748fdc7839SPaolo Bonzini }
29758fdc7839SPaolo Bonzini 
scsi_block_dma_writev(int64_t offset,QEMUIOVector * iov,BlockCompletionFunc * cb,void * cb_opaque,void * opaque)29768fdc7839SPaolo Bonzini static BlockAIOCB *scsi_block_dma_writev(int64_t offset,
29778fdc7839SPaolo Bonzini                                          QEMUIOVector *iov,
29788fdc7839SPaolo Bonzini                                          BlockCompletionFunc *cb, void *cb_opaque,
29798fdc7839SPaolo Bonzini                                          void *opaque)
29808fdc7839SPaolo Bonzini {
29818fdc7839SPaolo Bonzini     SCSIBlockReq *r = opaque;
29828fdc7839SPaolo Bonzini     return scsi_block_do_sgio(r, offset, iov,
29838fdc7839SPaolo Bonzini                               SG_DXFER_TO_DEV, cb, cb_opaque);
29848fdc7839SPaolo Bonzini }
29858fdc7839SPaolo Bonzini 
scsi_block_is_passthrough(SCSIDiskState * s,uint8_t * buf)2986592c3b28SPaolo Bonzini static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf)
298749ab747fSPaolo Bonzini {
298849ab747fSPaolo Bonzini     switch (buf[0]) {
29898fdc7839SPaolo Bonzini     case VERIFY_10:
29908fdc7839SPaolo Bonzini     case VERIFY_12:
29918fdc7839SPaolo Bonzini     case VERIFY_16:
29928fdc7839SPaolo Bonzini         /* Check if BYTCHK == 0x01 (data-out buffer contains data
29938fdc7839SPaolo Bonzini          * for the number of logical blocks specified in the length
29948fdc7839SPaolo Bonzini          * field).  For other modes, do not use scatter/gather operation.
29958fdc7839SPaolo Bonzini          */
29961f8af0d1SPaolo Bonzini         if ((buf[1] & 6) == 2) {
29978fdc7839SPaolo Bonzini             return false;
29988fdc7839SPaolo Bonzini         }
29998fdc7839SPaolo Bonzini         break;
30008fdc7839SPaolo Bonzini 
300149ab747fSPaolo Bonzini     case READ_6:
300249ab747fSPaolo Bonzini     case READ_10:
300349ab747fSPaolo Bonzini     case READ_12:
300449ab747fSPaolo Bonzini     case READ_16:
300549ab747fSPaolo Bonzini     case WRITE_6:
300649ab747fSPaolo Bonzini     case WRITE_10:
300749ab747fSPaolo Bonzini     case WRITE_12:
300849ab747fSPaolo Bonzini     case WRITE_16:
300949ab747fSPaolo Bonzini     case WRITE_VERIFY_10:
301049ab747fSPaolo Bonzini     case WRITE_VERIFY_12:
301149ab747fSPaolo Bonzini     case WRITE_VERIFY_16:
30128fdc7839SPaolo Bonzini         /* MMC writing cannot be done via DMA helpers, because it sometimes
301349ab747fSPaolo Bonzini          * involves writing beyond the maximum LBA or to negative LBA (lead-in).
3014166dbda7SPaolo Bonzini          * We might use scsi_block_dma_reqops as long as no writing commands are
301549ab747fSPaolo Bonzini          * seen, but performance usually isn't paramount on optical media.  So,
301649ab747fSPaolo Bonzini          * just make scsi-block operate the same as scsi-generic for them.
301749ab747fSPaolo Bonzini          */
301849ab747fSPaolo Bonzini         if (s->qdev.type != TYPE_ROM) {
3019592c3b28SPaolo Bonzini             return false;
3020592c3b28SPaolo Bonzini         }
3021592c3b28SPaolo Bonzini         break;
3022592c3b28SPaolo Bonzini 
3023592c3b28SPaolo Bonzini     default:
3024592c3b28SPaolo Bonzini         break;
3025592c3b28SPaolo Bonzini     }
3026592c3b28SPaolo Bonzini 
3027592c3b28SPaolo Bonzini     return true;
3028592c3b28SPaolo Bonzini }
3029592c3b28SPaolo Bonzini 
3030592c3b28SPaolo Bonzini 
scsi_block_dma_command(SCSIRequest * req,uint8_t * buf)30318fdc7839SPaolo Bonzini static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf)
30328fdc7839SPaolo Bonzini {
30338fdc7839SPaolo Bonzini     SCSIBlockReq *r = (SCSIBlockReq *)req;
30342343be0dSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
30352343be0dSPaolo Bonzini 
30368fdc7839SPaolo Bonzini     r->cmd = req->cmd.buf[0];
30378fdc7839SPaolo Bonzini     switch (r->cmd >> 5) {
30388fdc7839SPaolo Bonzini     case 0:
30398fdc7839SPaolo Bonzini         /* 6-byte CDB.  */
30408fdc7839SPaolo Bonzini         r->cdb1 = r->group_number = 0;
30418fdc7839SPaolo Bonzini         break;
30428fdc7839SPaolo Bonzini     case 1:
30438fdc7839SPaolo Bonzini         /* 10-byte CDB.  */
30448fdc7839SPaolo Bonzini         r->cdb1 = req->cmd.buf[1];
30458fdc7839SPaolo Bonzini         r->group_number = req->cmd.buf[6];
3046ed45cae3SPaolo Bonzini         break;
30478fdc7839SPaolo Bonzini     case 4:
30488fdc7839SPaolo Bonzini         /* 12-byte CDB.  */
30498fdc7839SPaolo Bonzini         r->cdb1 = req->cmd.buf[1];
30508fdc7839SPaolo Bonzini         r->group_number = req->cmd.buf[10];
30518fdc7839SPaolo Bonzini         break;
30528fdc7839SPaolo Bonzini     case 5:
30538fdc7839SPaolo Bonzini         /* 16-byte CDB.  */
30548fdc7839SPaolo Bonzini         r->cdb1 = req->cmd.buf[1];
30558fdc7839SPaolo Bonzini         r->group_number = req->cmd.buf[14];
30568fdc7839SPaolo Bonzini         break;
30578fdc7839SPaolo Bonzini     default:
30588fdc7839SPaolo Bonzini         abort();
30598fdc7839SPaolo Bonzini     }
30608fdc7839SPaolo Bonzini 
30612343be0dSPaolo Bonzini     /* Protection information is not supported.  For SCSI versions 2 and
30622343be0dSPaolo Bonzini      * older (as determined by snooping the guest's INQUIRY commands),
30632343be0dSPaolo Bonzini      * there is no RD/WR/VRPROTECT, so skip this check in these versions.
30642343be0dSPaolo Bonzini      */
30652343be0dSPaolo Bonzini     if (s->qdev.scsi_version > 2 && (req->cmd.buf[1] & 0xe0)) {
30668fdc7839SPaolo Bonzini         scsi_check_condition(&r->req, SENSE_CODE(INVALID_FIELD));
30678fdc7839SPaolo Bonzini         return 0;
30688fdc7839SPaolo Bonzini     }
30698fdc7839SPaolo Bonzini 
30708fdc7839SPaolo Bonzini     return scsi_disk_dma_command(req, buf);
30718fdc7839SPaolo Bonzini }
30728fdc7839SPaolo Bonzini 
30738fdc7839SPaolo Bonzini static const SCSIReqOps scsi_block_dma_reqops = {
30748fdc7839SPaolo Bonzini     .size         = sizeof(SCSIBlockReq),
30758fdc7839SPaolo Bonzini     .free_req     = scsi_free_request,
30768fdc7839SPaolo Bonzini     .send_command = scsi_block_dma_command,
30778fdc7839SPaolo Bonzini     .read_data    = scsi_read_data,
30788fdc7839SPaolo Bonzini     .write_data   = scsi_write_data,
30798fdc7839SPaolo Bonzini     .get_buf      = scsi_get_buf,
30808fdc7839SPaolo Bonzini     .load_request = scsi_disk_load_request,
30818fdc7839SPaolo Bonzini     .save_request = scsi_disk_save_request,
30828fdc7839SPaolo Bonzini };
30838fdc7839SPaolo Bonzini 
scsi_block_new_request(SCSIDevice * d,uint32_t tag,uint32_t lun,uint8_t * buf,void * hba_private)3084592c3b28SPaolo Bonzini static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
3085592c3b28SPaolo Bonzini                                            uint32_t lun, uint8_t *buf,
3086592c3b28SPaolo Bonzini                                            void *hba_private)
3087592c3b28SPaolo Bonzini {
3088592c3b28SPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
3089592c3b28SPaolo Bonzini 
3090592c3b28SPaolo Bonzini     if (scsi_block_is_passthrough(s, buf)) {
3091592c3b28SPaolo Bonzini         return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
3092592c3b28SPaolo Bonzini                               hba_private);
3093592c3b28SPaolo Bonzini     } else {
30948fdc7839SPaolo Bonzini         return scsi_req_alloc(&scsi_block_dma_reqops, &s->qdev, tag, lun,
309549ab747fSPaolo Bonzini                               hba_private);
309649ab747fSPaolo Bonzini     }
309749ab747fSPaolo Bonzini }
30983e7e180aSPaolo Bonzini 
scsi_block_parse_cdb(SCSIDevice * d,SCSICommand * cmd,uint8_t * buf,size_t buf_len,void * hba_private)30993e7e180aSPaolo Bonzini static int scsi_block_parse_cdb(SCSIDevice *d, SCSICommand *cmd,
3100fe9d8927SJohn Millikin                                   uint8_t *buf, size_t buf_len,
3101fe9d8927SJohn Millikin                                   void *hba_private)
31023e7e180aSPaolo Bonzini {
31033e7e180aSPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
31043e7e180aSPaolo Bonzini 
31053e7e180aSPaolo Bonzini     if (scsi_block_is_passthrough(s, buf)) {
3106fe9d8927SJohn Millikin         return scsi_bus_parse_cdb(&s->qdev, cmd, buf, buf_len, hba_private);
31073e7e180aSPaolo Bonzini     } else {
3108fe9d8927SJohn Millikin         return scsi_req_parse_cdb(&s->qdev, cmd, buf, buf_len);
31093e7e180aSPaolo Bonzini     }
31103e7e180aSPaolo Bonzini }
31113e7e180aSPaolo Bonzini 
scsi_block_update_sense(SCSIRequest * req)3112d31347f5SShinichiro Kawasaki static void scsi_block_update_sense(SCSIRequest *req)
3113d31347f5SShinichiro Kawasaki {
3114d31347f5SShinichiro Kawasaki     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
3115d31347f5SShinichiro Kawasaki     SCSIBlockReq *br = DO_UPCAST(SCSIBlockReq, req, r);
3116d31347f5SShinichiro Kawasaki     r->req.sense_len = MIN(br->io_header.sb_len_wr, sizeof(r->req.sense));
3117d31347f5SShinichiro Kawasaki }
311849ab747fSPaolo Bonzini #endif
311949ab747fSPaolo Bonzini 
3120fcaafb10SPaolo Bonzini static
scsi_dma_readv(int64_t offset,QEMUIOVector * iov,BlockCompletionFunc * cb,void * cb_opaque,void * opaque)3121fcaafb10SPaolo Bonzini BlockAIOCB *scsi_dma_readv(int64_t offset, QEMUIOVector *iov,
3122fcaafb10SPaolo Bonzini                            BlockCompletionFunc *cb, void *cb_opaque,
3123fcaafb10SPaolo Bonzini                            void *opaque)
3124fcaafb10SPaolo Bonzini {
3125fcaafb10SPaolo Bonzini     SCSIDiskReq *r = opaque;
3126fcaafb10SPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
3127fcaafb10SPaolo Bonzini     return blk_aio_preadv(s->qdev.conf.blk, offset, iov, 0, cb, cb_opaque);
3128fcaafb10SPaolo Bonzini }
3129fcaafb10SPaolo Bonzini 
3130fcaafb10SPaolo Bonzini static
scsi_dma_writev(int64_t offset,QEMUIOVector * iov,BlockCompletionFunc * cb,void * cb_opaque,void * opaque)3131fcaafb10SPaolo Bonzini BlockAIOCB *scsi_dma_writev(int64_t offset, QEMUIOVector *iov,
3132fcaafb10SPaolo Bonzini                             BlockCompletionFunc *cb, void *cb_opaque,
3133fcaafb10SPaolo Bonzini                             void *opaque)
3134fcaafb10SPaolo Bonzini {
3135fcaafb10SPaolo Bonzini     SCSIDiskReq *r = opaque;
3136fcaafb10SPaolo Bonzini     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
3137fcaafb10SPaolo Bonzini     return blk_aio_pwritev(s->qdev.conf.blk, offset, iov, 0, cb, cb_opaque);
3138fcaafb10SPaolo Bonzini }
3139fcaafb10SPaolo Bonzini 
scsi_property_get_loadparm(Object * obj,Error ** errp)3140429442e5SThomas Huth static char *scsi_property_get_loadparm(Object *obj, Error **errp)
3141429442e5SThomas Huth {
3142429442e5SThomas Huth     return g_strdup(SCSI_DISK_BASE(obj)->loadparm);
3143429442e5SThomas Huth }
3144429442e5SThomas Huth 
scsi_property_set_loadparm(Object * obj,const char * value,Error ** errp)3145429442e5SThomas Huth static void scsi_property_set_loadparm(Object *obj, const char *value,
3146429442e5SThomas Huth                                        Error **errp)
3147429442e5SThomas Huth {
3148429442e5SThomas Huth     void *lp_str;
3149429442e5SThomas Huth 
3150429442e5SThomas Huth     if (object_property_get_int(obj, "bootindex", NULL) < 0) {
3151429442e5SThomas Huth         error_setg(errp, "'loadparm' is only valid for boot devices");
3152429442e5SThomas Huth         return;
3153429442e5SThomas Huth     }
3154429442e5SThomas Huth 
3155*b73d7effSPaolo Bonzini     lp_str = g_malloc0(strlen(value) + 1);
3156429442e5SThomas Huth     if (!qdev_prop_sanitize_s390x_loadparm(lp_str, value, errp)) {
3157429442e5SThomas Huth         g_free(lp_str);
3158429442e5SThomas Huth         return;
3159429442e5SThomas Huth     }
3160429442e5SThomas Huth     SCSI_DISK_BASE(obj)->loadparm = lp_str;
3161429442e5SThomas Huth }
3162429442e5SThomas Huth 
scsi_property_add_specifics(DeviceClass * dc)3163429442e5SThomas Huth static void scsi_property_add_specifics(DeviceClass *dc)
3164429442e5SThomas Huth {
3165429442e5SThomas Huth     ObjectClass *oc = OBJECT_CLASS(dc);
3166429442e5SThomas Huth 
3167429442e5SThomas Huth     /* The loadparm property is only supported on s390x */
3168429442e5SThomas Huth     if (arch_type & QEMU_ARCH_S390X) {
3169429442e5SThomas Huth         object_class_property_add_str(oc, "loadparm",
3170429442e5SThomas Huth                                       scsi_property_get_loadparm,
3171429442e5SThomas Huth                                       scsi_property_set_loadparm);
3172429442e5SThomas Huth         object_class_property_set_description(oc, "loadparm",
3173429442e5SThomas Huth                                               "load parameter (s390x only)");
3174429442e5SThomas Huth     }
3175429442e5SThomas Huth }
3176429442e5SThomas Huth 
scsi_disk_base_class_initfn(ObjectClass * klass,void * data)3177993935f3SPaolo Bonzini static void scsi_disk_base_class_initfn(ObjectClass *klass, void *data)
3178993935f3SPaolo Bonzini {
3179993935f3SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
3180fcaafb10SPaolo Bonzini     SCSIDiskClass *sdc = SCSI_DISK_BASE_CLASS(klass);
3181993935f3SPaolo Bonzini 
3182993935f3SPaolo Bonzini     dc->fw_name = "disk";
3183e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, scsi_disk_reset);
3184fcaafb10SPaolo Bonzini     sdc->dma_readv = scsi_dma_readv;
3185fcaafb10SPaolo Bonzini     sdc->dma_writev = scsi_dma_writev;
318694f8ba11SPaolo Bonzini     sdc->need_fua_emulation = scsi_is_cmd_fua;
3187993935f3SPaolo Bonzini }
3188993935f3SPaolo Bonzini 
3189993935f3SPaolo Bonzini static const TypeInfo scsi_disk_base_info = {
3190993935f3SPaolo Bonzini     .name          = TYPE_SCSI_DISK_BASE,
3191993935f3SPaolo Bonzini     .parent        = TYPE_SCSI_DEVICE,
3192993935f3SPaolo Bonzini     .class_init    = scsi_disk_base_class_initfn,
3193993935f3SPaolo Bonzini     .instance_size = sizeof(SCSIDiskState),
3194fcaafb10SPaolo Bonzini     .class_size    = sizeof(SCSIDiskClass),
31956214a11aSPaolo Bonzini     .abstract      = true,
3196993935f3SPaolo Bonzini };
3197993935f3SPaolo Bonzini 
319849ab747fSPaolo Bonzini #define DEFINE_SCSI_DISK_PROPERTIES()                                   \
31994f71fb43SKevin Wolf     DEFINE_PROP_DRIVE_IOTHREAD("drive", SCSIDiskState, qdev.conf.blk),  \
32004f71fb43SKevin Wolf     DEFINE_BLOCK_PROPERTIES_BASE(SCSIDiskState, qdev.conf),             \
32018c398252SKevin Wolf     DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf),            \
320249ab747fSPaolo Bonzini     DEFINE_PROP_STRING("ver", SCSIDiskState, version),                  \
320349ab747fSPaolo Bonzini     DEFINE_PROP_STRING("serial", SCSIDiskState, serial),                \
320449ab747fSPaolo Bonzini     DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor),                \
32057471a649SKevin Wolf     DEFINE_PROP_STRING("product", SCSIDiskState, product),              \
3206b4912afaSHyman Huang     DEFINE_PROP_STRING("device_id", SCSIDiskState, device_id),          \
3207b4912afaSHyman Huang     DEFINE_PROP_BOOL("migrate-emulated-scsi-request", SCSIDiskState, migrate_emulated_scsi_request, true)
32087471a649SKevin Wolf 
320949ab747fSPaolo Bonzini 
321049ab747fSPaolo Bonzini static Property scsi_hd_properties[] = {
321149ab747fSPaolo Bonzini     DEFINE_SCSI_DISK_PROPERTIES(),
321249ab747fSPaolo Bonzini     DEFINE_PROP_BIT("removable", SCSIDiskState, features,
321349ab747fSPaolo Bonzini                     SCSI_DISK_F_REMOVABLE, false),
321449ab747fSPaolo Bonzini     DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
321549ab747fSPaolo Bonzini                     SCSI_DISK_F_DPOFUA, false),
32162ecab408SPaolo Bonzini     DEFINE_PROP_UINT64("wwn", SCSIDiskState, qdev.wwn, 0),
32172ecab408SPaolo Bonzini     DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, qdev.port_wwn, 0),
321864cc2284SRoland Dreier     DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
32198a1bd297SPaolo Bonzini     DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
32208a1bd297SPaolo Bonzini                        DEFAULT_MAX_UNMAP_SIZE),
3221f8e1f533SPaolo Bonzini     DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size,
3222f8e1f533SPaolo Bonzini                        DEFAULT_MAX_IO_SIZE),
3223070f8009SDaniel P. Berrange     DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0),
32242343be0dSPaolo Bonzini     DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version,
32252343be0dSPaolo Bonzini                       5),
322609274de1SMark Cave-Ayland     DEFINE_PROP_BIT("quirk_mode_page_vendor_specific_apple", SCSIDiskState,
322709274de1SMark Cave-Ayland                     quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE,
322809274de1SMark Cave-Ayland                     0),
322949ab747fSPaolo Bonzini     DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf),
323049ab747fSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
323149ab747fSPaolo Bonzini };
323249ab747fSPaolo Bonzini 
323349ab747fSPaolo Bonzini static const VMStateDescription vmstate_scsi_disk_state = {
323449ab747fSPaolo Bonzini     .name = "scsi-disk",
323549ab747fSPaolo Bonzini     .version_id = 1,
323649ab747fSPaolo Bonzini     .minimum_version_id = 1,
32372d7b39a6SRichard Henderson     .fields = (const VMStateField[]) {
323849ab747fSPaolo Bonzini         VMSTATE_SCSI_DEVICE(qdev, SCSIDiskState),
323949ab747fSPaolo Bonzini         VMSTATE_BOOL(media_changed, SCSIDiskState),
324049ab747fSPaolo Bonzini         VMSTATE_BOOL(media_event, SCSIDiskState),
324149ab747fSPaolo Bonzini         VMSTATE_BOOL(eject_request, SCSIDiskState),
324249ab747fSPaolo Bonzini         VMSTATE_BOOL(tray_open, SCSIDiskState),
324349ab747fSPaolo Bonzini         VMSTATE_BOOL(tray_locked, SCSIDiskState),
324449ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
324549ab747fSPaolo Bonzini     }
324649ab747fSPaolo Bonzini };
324749ab747fSPaolo Bonzini 
scsi_hd_class_initfn(ObjectClass * klass,void * data)324849ab747fSPaolo Bonzini static void scsi_hd_class_initfn(ObjectClass *klass, void *data)
324949ab747fSPaolo Bonzini {
325049ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
325149ab747fSPaolo Bonzini     SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
325249ab747fSPaolo Bonzini 
3253a818a4b6SFam Zheng     sc->realize      = scsi_hd_realize;
325471f571a2SSam Eiderman     sc->unrealize    = scsi_unrealize;
325549ab747fSPaolo Bonzini     sc->alloc_req    = scsi_new_request;
325649ab747fSPaolo Bonzini     sc->unit_attention_reported = scsi_disk_unit_attention_reported;
325749ab747fSPaolo Bonzini     dc->desc = "virtual SCSI disk";
32584f67d30bSMarc-André Lureau     device_class_set_props(dc, scsi_hd_properties);
325949ab747fSPaolo Bonzini     dc->vmsd  = &vmstate_scsi_disk_state;
3260429442e5SThomas Huth 
3261429442e5SThomas Huth     scsi_property_add_specifics(dc);
326249ab747fSPaolo Bonzini }
326349ab747fSPaolo Bonzini 
326449ab747fSPaolo Bonzini static const TypeInfo scsi_hd_info = {
326549ab747fSPaolo Bonzini     .name          = "scsi-hd",
3266993935f3SPaolo Bonzini     .parent        = TYPE_SCSI_DISK_BASE,
326749ab747fSPaolo Bonzini     .class_init    = scsi_hd_class_initfn,
326849ab747fSPaolo Bonzini };
326949ab747fSPaolo Bonzini 
327049ab747fSPaolo Bonzini static Property scsi_cd_properties[] = {
327149ab747fSPaolo Bonzini     DEFINE_SCSI_DISK_PROPERTIES(),
32722ecab408SPaolo Bonzini     DEFINE_PROP_UINT64("wwn", SCSIDiskState, qdev.wwn, 0),
32732ecab408SPaolo Bonzini     DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, qdev.port_wwn, 0),
327464cc2284SRoland Dreier     DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
3275f8e1f533SPaolo Bonzini     DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size,
3276f8e1f533SPaolo Bonzini                        DEFAULT_MAX_IO_SIZE),
32772343be0dSPaolo Bonzini     DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version,
32782343be0dSPaolo Bonzini                       5),
327909d37867SMark Cave-Ayland     DEFINE_PROP_BIT("quirk_mode_page_apple_vendor", SCSIDiskState, quirks,
328009d37867SMark Cave-Ayland                     SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR, 0),
3281f43c2b94SMark Cave-Ayland     DEFINE_PROP_BIT("quirk_mode_sense_rom_use_dbd", SCSIDiskState, quirks,
3282f43c2b94SMark Cave-Ayland                     SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD, 0),
328309274de1SMark Cave-Ayland     DEFINE_PROP_BIT("quirk_mode_page_vendor_specific_apple", SCSIDiskState,
328409274de1SMark Cave-Ayland                     quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE,
328509274de1SMark Cave-Ayland                     0),
3286389e18ebSMark Cave-Ayland     DEFINE_PROP_BIT("quirk_mode_page_truncated", SCSIDiskState, quirks,
3287389e18ebSMark Cave-Ayland                     SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED, 0),
328849ab747fSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
328949ab747fSPaolo Bonzini };
329049ab747fSPaolo Bonzini 
scsi_cd_class_initfn(ObjectClass * klass,void * data)329149ab747fSPaolo Bonzini static void scsi_cd_class_initfn(ObjectClass *klass, void *data)
329249ab747fSPaolo Bonzini {
329349ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
329449ab747fSPaolo Bonzini     SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
329549ab747fSPaolo Bonzini 
3296a818a4b6SFam Zheng     sc->realize      = scsi_cd_realize;
329749ab747fSPaolo Bonzini     sc->alloc_req    = scsi_new_request;
329849ab747fSPaolo Bonzini     sc->unit_attention_reported = scsi_disk_unit_attention_reported;
329949ab747fSPaolo Bonzini     dc->desc = "virtual SCSI CD-ROM";
33004f67d30bSMarc-André Lureau     device_class_set_props(dc, scsi_cd_properties);
330149ab747fSPaolo Bonzini     dc->vmsd  = &vmstate_scsi_disk_state;
3302429442e5SThomas Huth 
3303429442e5SThomas Huth     scsi_property_add_specifics(dc);
330449ab747fSPaolo Bonzini }
330549ab747fSPaolo Bonzini 
330649ab747fSPaolo Bonzini static const TypeInfo scsi_cd_info = {
330749ab747fSPaolo Bonzini     .name          = "scsi-cd",
3308993935f3SPaolo Bonzini     .parent        = TYPE_SCSI_DISK_BASE,
330949ab747fSPaolo Bonzini     .class_init    = scsi_cd_class_initfn,
331049ab747fSPaolo Bonzini };
331149ab747fSPaolo Bonzini 
331249ab747fSPaolo Bonzini #ifdef __linux__
331349ab747fSPaolo Bonzini static Property scsi_block_properties[] = {
331478ee6bd0SPhilippe Mathieu-Daudé     DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf),
33154be74634SMarkus Armbruster     DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk),
331607488549SFam Zheng     DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false),
3317070f8009SDaniel P. Berrange     DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0),
33180a96ca24SDaniel Henrique Barboza     DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
33190a96ca24SDaniel Henrique Barboza                        DEFAULT_MAX_UNMAP_SIZE),
33200a96ca24SDaniel Henrique Barboza     DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size,
33210a96ca24SDaniel Henrique Barboza                        DEFAULT_MAX_IO_SIZE),
33222343be0dSPaolo Bonzini     DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version,
332329e560f0SDaniel Henrique Barboza                       -1),
3324c9b6609bSHannes Reinecke     DEFINE_PROP_UINT32("io_timeout", SCSIDiskState, qdev.io_timeout,
3325c9b6609bSHannes Reinecke                        DEFAULT_IO_TIMEOUT),
332649ab747fSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
332749ab747fSPaolo Bonzini };
332849ab747fSPaolo Bonzini 
scsi_block_class_initfn(ObjectClass * klass,void * data)332949ab747fSPaolo Bonzini static void scsi_block_class_initfn(ObjectClass *klass, void *data)
333049ab747fSPaolo Bonzini {
333149ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
333249ab747fSPaolo Bonzini     SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
33338fdc7839SPaolo Bonzini     SCSIDiskClass *sdc = SCSI_DISK_BASE_CLASS(klass);
333449ab747fSPaolo Bonzini 
3335a818a4b6SFam Zheng     sc->realize      = scsi_block_realize;
333649ab747fSPaolo Bonzini     sc->alloc_req    = scsi_block_new_request;
33373e7e180aSPaolo Bonzini     sc->parse_cdb    = scsi_block_parse_cdb;
33388fdc7839SPaolo Bonzini     sdc->dma_readv   = scsi_block_dma_readv;
33398fdc7839SPaolo Bonzini     sdc->dma_writev  = scsi_block_dma_writev;
3340d31347f5SShinichiro Kawasaki     sdc->update_sense = scsi_block_update_sense;
33418fdc7839SPaolo Bonzini     sdc->need_fua_emulation = scsi_block_no_fua;
334249ab747fSPaolo Bonzini     dc->desc = "SCSI block device passthrough";
33434f67d30bSMarc-André Lureau     device_class_set_props(dc, scsi_block_properties);
334449ab747fSPaolo Bonzini     dc->vmsd  = &vmstate_scsi_disk_state;
334549ab747fSPaolo Bonzini }
334649ab747fSPaolo Bonzini 
334749ab747fSPaolo Bonzini static const TypeInfo scsi_block_info = {
334849ab747fSPaolo Bonzini     .name          = "scsi-block",
3349993935f3SPaolo Bonzini     .parent        = TYPE_SCSI_DISK_BASE,
335049ab747fSPaolo Bonzini     .class_init    = scsi_block_class_initfn,
335149ab747fSPaolo Bonzini };
335249ab747fSPaolo Bonzini #endif
335349ab747fSPaolo Bonzini 
scsi_disk_register_types(void)335449ab747fSPaolo Bonzini static void scsi_disk_register_types(void)
335549ab747fSPaolo Bonzini {
3356993935f3SPaolo Bonzini     type_register_static(&scsi_disk_base_info);
335749ab747fSPaolo Bonzini     type_register_static(&scsi_hd_info);
335849ab747fSPaolo Bonzini     type_register_static(&scsi_cd_info);
335949ab747fSPaolo Bonzini #ifdef __linux__
336049ab747fSPaolo Bonzini     type_register_static(&scsi_block_info);
336149ab747fSPaolo Bonzini #endif
336249ab747fSPaolo Bonzini }
336349ab747fSPaolo Bonzini 
336449ab747fSPaolo Bonzini type_init(scsi_disk_register_types)
3365