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