blob: a5b5b2ec0d4ae43e3c1122bf62980c7390d45513 [file] [log] [blame]
Gerd Hoffmann1e376072009-11-26 15:33:47 +01001#ifndef QEMU_HW_SCSI_H
2#define QEMU_HW_SCSI_H
Gerd Hoffmann43b443b2009-10-30 09:54:00 +01003
4#include "qdev.h"
Paolo Bonzini737e1502012-12-17 18:19:44 +01005#include "block/block.h"
Markus Armbruster31e404f2012-07-11 15:08:36 +02006#include "hw/block-common.h"
Paolo Bonzini9c17d612012-12-17 18:20:04 +01007#include "sysemu/sysemu.h"
Gerd Hoffmann43b443b2009-10-30 09:54:00 +01008
Markus Armbruster27d6bf42011-01-28 11:21:40 +01009#define MAX_SCSI_DEVS 255
10
Gerd Hoffmann29362eb2009-11-26 15:33:51 +010011#define SCSI_CMD_BUF_SIZE 16
12
Gerd Hoffmann43b443b2009-10-30 09:54:00 +010013typedef struct SCSIBus SCSIBus;
Paolo Bonziniafd40302011-08-13 15:44:45 +020014typedef struct SCSIBusInfo SCSIBusInfo;
Paolo Bonzini2599aec2011-08-03 10:49:11 +020015typedef struct SCSICommand SCSICommand;
Gerd Hoffmann43b443b2009-10-30 09:54:00 +010016typedef struct SCSIDevice SCSIDevice;
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +020017typedef struct SCSIRequest SCSIRequest;
Paolo Bonzini8dbd4572011-08-03 10:49:08 +020018typedef struct SCSIReqOps SCSIReqOps;
Gerd Hoffmann43b443b2009-10-30 09:54:00 +010019
Gerd Hoffmann97a06432009-11-26 15:33:57 +010020enum SCSIXferMode {
21 SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */
22 SCSI_XFER_FROM_DEV, /* READ, INQUIRY, MODE_SENSE, ... */
23 SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */
24};
25
Hannes Reineckea1f0cce2011-04-18 12:53:14 +020026typedef struct SCSISense {
27 uint8_t key;
28 uint8_t asc;
29 uint8_t ascq;
30} SCSISense;
31
Paolo Bonzinib45ef672011-08-03 10:49:07 +020032#define SCSI_SENSE_BUF_SIZE 96
33
Paolo Bonzini2599aec2011-08-03 10:49:11 +020034struct SCSICommand {
35 uint8_t buf[SCSI_CMD_BUF_SIZE];
36 int len;
37 size_t xfer;
38 uint64_t lba;
39 enum SCSIXferMode mode;
40};
41
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +020042struct SCSIRequest {
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +010043 SCSIBus *bus;
44 SCSIDevice *dev;
Paolo Bonziniadcf2752011-10-12 12:57:59 +020045 const SCSIReqOps *ops;
Paolo Bonziniad2d30f2011-04-18 16:01:56 +020046 uint32_t refcount;
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +010047 uint32_t tag;
Gerd Hoffmann89b08ae2009-11-26 15:33:50 +010048 uint32_t lun;
Gerd Hoffmanned3a34a2009-11-26 15:34:00 +010049 uint32_t status;
Paolo Bonzini01e95452011-07-06 11:55:37 +020050 size_t resid;
Paolo Bonzini2599aec2011-08-03 10:49:11 +020051 SCSICommand cmd;
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +010052 BlockDriverAIOCB *aiocb;
Paolo Bonzini3d5aba92011-07-06 11:26:47 +020053 QEMUSGList *sg;
54 bool dma_started;
Paolo Bonzinib45ef672011-08-03 10:49:07 +020055 uint8_t sense[SCSI_SENSE_BUF_SIZE];
56 uint32_t sense_len;
Jan Kiszkae8637c92010-07-13 14:13:45 +020057 bool enqueued;
Paolo Bonzinie88c5912011-10-25 12:53:33 +020058 bool io_canceled;
Paolo Bonzini71544d32011-10-25 12:53:36 +020059 bool retry;
Hannes Reineckec5bf71a2011-07-11 15:02:24 +020060 void *hba_private;
Gerd Hoffmann9af99d92009-11-26 15:33:49 +010061 QTAILQ_ENTRY(SCSIRequest) next;
Hannes Reinecke5c6c0e52011-04-18 12:35:39 +020062};
Gerd Hoffmann4c41d2e2009-11-26 15:33:48 +010063
Anthony Liguorib9eea3e2011-12-15 14:50:08 -060064#define TYPE_SCSI_DEVICE "scsi-device"
65#define SCSI_DEVICE(obj) \
66 OBJECT_CHECK(SCSIDevice, (obj), TYPE_SCSI_DEVICE)
67#define SCSI_DEVICE_CLASS(klass) \
68 OBJECT_CLASS_CHECK(SCSIDeviceClass, (klass), TYPE_SCSI_DEVICE)
69#define SCSI_DEVICE_GET_CLASS(obj) \
70 OBJECT_GET_CLASS(SCSIDeviceClass, (obj), TYPE_SCSI_DEVICE)
71
72typedef struct SCSIDeviceClass {
73 DeviceClass parent_class;
74 int (*init)(SCSIDevice *dev);
75 void (*destroy)(SCSIDevice *s);
76 SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
77 uint8_t *buf, void *hba_private);
78 void (*unit_attention_reported)(SCSIDevice *s);
79} SCSIDeviceClass;
80
Gerd Hoffmann43b443b2009-10-30 09:54:00 +010081struct SCSIDevice
82{
83 DeviceState qdev;
Paolo Bonzini71544d32011-10-25 12:53:36 +020084 VMChangeStateEntry *vmsentry;
85 QEMUBH *bh;
Gerd Hoffmann43b443b2009-10-30 09:54:00 +010086 uint32_t id;
Christoph Hellwig428c1492010-02-10 23:37:09 +010087 BlockConf conf;
Paolo Bonzini6dc06f02011-08-03 10:49:17 +020088 SCSISense unit_attention;
Paolo Bonzini3653d8c2011-09-13 16:19:53 +020089 bool sense_is_ua;
Paolo Bonzinib45ef672011-08-03 10:49:07 +020090 uint8_t sense[SCSI_SENSE_BUF_SIZE];
91 uint32_t sense_len;
Gerd Hoffmann9af99d92009-11-26 15:33:49 +010092 QTAILQ_HEAD(, SCSIRequest) requests;
Paolo Bonzini0d3545e2011-07-27 23:24:50 +020093 uint32_t channel;
Paolo Bonzini87dcd1b2011-08-03 10:49:12 +020094 uint32_t lun;
Gerd Hoffmannb07995e2009-11-26 15:33:52 +010095 int blocksize;
Gerd Hoffmann91376652009-11-26 15:33:54 +010096 int type;
Paolo Bonzini78779032011-10-13 10:39:50 +020097 uint64_t max_lba;
Gerd Hoffmann43b443b2009-10-30 09:54:00 +010098};
99
Paolo Bonzini63f740d2011-12-02 16:27:02 +0100100extern const VMStateDescription vmstate_scsi_device;
101
102#define VMSTATE_SCSI_DEVICE(_field, _state) { \
103 .name = (stringify(_field)), \
104 .size = sizeof(SCSIDevice), \
105 .vmsd = &vmstate_scsi_device, \
106 .flags = VMS_STRUCT, \
107 .offset = vmstate_offset_value(_state, _field, SCSIDevice), \
108}
109
Gerd Hoffmann43b443b2009-10-30 09:54:00 +0100110/* cdrom.c */
111int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
112int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
113
114/* scsi-bus.c */
Paolo Bonzini8dbd4572011-08-03 10:49:08 +0200115struct SCSIReqOps {
116 size_t size;
Paolo Bonzini12010e72011-08-03 10:49:09 +0200117 void (*free_req)(SCSIRequest *req);
118 int32_t (*send_command)(SCSIRequest *req, uint8_t *buf);
119 void (*read_data)(SCSIRequest *req);
120 void (*write_data)(SCSIRequest *req);
121 void (*cancel_io)(SCSIRequest *req);
122 uint8_t *(*get_buf)(SCSIRequest *req);
Paolo Bonzini63f740d2011-12-02 16:27:02 +0100123
124 void (*save_request)(QEMUFile *f, SCSIRequest *req);
125 void (*load_request)(QEMUFile *f, SCSIRequest *req);
Paolo Bonzini8dbd4572011-08-03 10:49:08 +0200126};
127
Paolo Bonziniafd40302011-08-13 15:44:45 +0200128struct SCSIBusInfo {
Paolo Bonzini7e0380b2011-08-13 18:55:17 +0200129 int tcq;
Paolo Bonzini0d3545e2011-07-27 23:24:50 +0200130 int max_channel, max_target, max_lun;
Paolo Bonzinic6df7102011-04-22 12:27:30 +0200131 void (*transfer_data)(SCSIRequest *req, uint32_t arg);
Paolo Bonzini01e95452011-07-06 11:55:37 +0200132 void (*complete)(SCSIRequest *req, uint32_t arg, size_t resid);
Paolo Bonzini94d3f982011-04-18 22:53:08 +0200133 void (*cancel)(SCSIRequest *req);
Cong Meng350e6e42012-06-20 14:47:10 +0800134 void (*hotplug)(SCSIBus *bus, SCSIDevice *dev);
135 void (*hot_unplug)(SCSIBus *bus, SCSIDevice *dev);
Paolo Bonzini53200fa2012-07-16 14:22:36 +0200136 void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense);
Paolo Bonzini3d5aba92011-07-06 11:26:47 +0200137 QEMUSGList *(*get_sg_list)(SCSIRequest *req);
Paolo Bonzini63f740d2011-12-02 16:27:02 +0100138
139 void (*save_request)(QEMUFile *f, SCSIRequest *req);
140 void *(*load_request)(QEMUFile *f, SCSIRequest *req);
Paolo Bonzini8e86b932012-07-09 12:06:28 +0200141 void (*free_request)(SCSIBus *bus, void *priv);
Paolo Bonzinicfdc1bb2011-04-18 17:11:14 +0200142};
143
Anthony Liguori0d936922012-05-02 09:00:20 +0200144#define TYPE_SCSI_BUS "SCSI"
145#define SCSI_BUS(obj) OBJECT_CHECK(SCSIBus, (obj), TYPE_SCSI_BUS)
146
Gerd Hoffmann43b443b2009-10-30 09:54:00 +0100147struct SCSIBus {
148 BusState qbus;
149 int busnr;
150
Paolo Bonzini6dc06f02011-08-03 10:49:17 +0200151 SCSISense unit_attention;
Paolo Bonziniafd40302011-08-13 15:44:45 +0200152 const SCSIBusInfo *info;
Gerd Hoffmann43b443b2009-10-30 09:54:00 +0100153};
154
Paolo Bonziniafd40302011-08-13 15:44:45 +0200155void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
Gerd Hoffmann43b443b2009-10-30 09:54:00 +0100156
157static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
158{
159 return DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
160}
161
Stefan Hajnoczi2d1fd262011-01-24 15:34:59 +0000162SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
Paolo Bonzinice4e7e42011-11-18 16:32:00 +0100163 int unit, bool removable, int bootindex);
Markus Armbrusterfa66b902010-06-25 18:53:21 +0200164int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
Gerd Hoffmann43b443b2009-10-30 09:54:00 +0100165
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200166/*
167 * Predefined sense codes
168 */
169
170/* No sense data available */
171extern const struct SCSISense sense_code_NO_SENSE;
172/* LUN not ready, Manual intervention required */
173extern const struct SCSISense sense_code_LUN_NOT_READY;
174/* LUN not ready, Medium not present */
175extern const struct SCSISense sense_code_NO_MEDIUM;
Markus Armbruster68bb01f2011-09-06 18:58:49 +0200176/* LUN not ready, medium removal prevented */
177extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200178/* Hardware error, internal target failure */
179extern const struct SCSISense sense_code_TARGET_FAILURE;
180/* Illegal request, invalid command operation code */
181extern const struct SCSISense sense_code_INVALID_OPCODE;
182/* Illegal request, LBA out of range */
183extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
184/* Illegal request, Invalid field in CDB */
185extern const struct SCSISense sense_code_INVALID_FIELD;
Paolo Bonzini380feaf2012-07-10 15:02:55 +0200186/* Illegal request, Invalid field in parameter list */
187extern const struct SCSISense sense_code_INVALID_PARAM;
188/* Illegal request, Parameter list length error */
189extern const struct SCSISense sense_code_INVALID_PARAM_LEN;
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200190/* Illegal request, LUN not supported */
191extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
Paolo Bonzinia872a302011-08-03 10:49:16 +0200192/* Illegal request, Saving parameters not supported */
193extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
194/* Illegal request, Incompatible format */
195extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
Markus Armbruster68bb01f2011-09-06 18:58:49 +0200196/* Illegal request, medium removal prevented */
197extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200198/* Command aborted, I/O process terminated */
199extern const struct SCSISense sense_code_IO_ERROR;
200/* Command aborted, I_T Nexus loss occurred */
201extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
202/* Command aborted, Logical Unit failure */
203extern const struct SCSISense sense_code_LUN_FAILURE;
Paolo Bonziniaaebace2012-07-16 14:07:55 +0200204/* LUN not ready, Capacity data has changed */
205extern const struct SCSISense sense_code_CAPACITY_CHANGED;
Paolo Bonzini8a9c16f2011-09-13 16:26:06 +0200206/* LUN not ready, Medium not present */
207extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
Paolo Bonzinia872a302011-08-03 10:49:16 +0200208/* Unit attention, Power on, reset or bus device reset occurred */
209extern const struct SCSISense sense_code_RESET;
210/* Unit attention, Medium may have changed*/
211extern const struct SCSISense sense_code_MEDIUM_CHANGED;
212/* Unit attention, Reported LUNs data has changed */
213extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
214/* Unit attention, Device internal reset */
215extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
Ronnie Sahlberg6a8a6852012-07-16 08:53:28 +0200216/* Data Protection, Write Protected */
217extern const struct SCSISense sense_code_WRITE_PROTECTED;
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200218
219#define SENSE_CODE(x) sense_code_ ## x
220
Paolo Bonzinibb729f72012-09-05 17:57:19 +0200221uint32_t scsi_data_cdb_length(uint8_t *buf);
222uint32_t scsi_cdb_length(uint8_t *buf);
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200223int scsi_sense_valid(SCSISense sense);
Paolo Bonzinif3b338e2011-11-14 14:31:51 +0100224int scsi_build_sense(uint8_t *in_buf, int in_len,
225 uint8_t *buf, int len, bool fixed);
Hannes Reineckea1f0cce2011-04-18 12:53:14 +0200226
Paolo Bonziniadcf2752011-10-12 12:57:59 +0200227SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
228 uint32_t tag, uint32_t lun, void *hba_private);
Hannes Reineckec5bf71a2011-07-11 15:02:24 +0200229SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
Paolo Bonzinic39ce112011-08-03 10:49:10 +0200230 uint8_t *buf, void *hba_private);
231int32_t scsi_req_enqueue(SCSIRequest *req);
Gerd Hoffmann89b08ae2009-11-26 15:33:50 +0100232void scsi_req_free(SCSIRequest *req);
Paolo Bonziniad2d30f2011-04-18 16:01:56 +0200233SCSIRequest *scsi_req_ref(SCSIRequest *req);
234void scsi_req_unref(SCSIRequest *req);
Gerd Hoffmann37659e52009-11-26 15:33:58 +0100235
Paolo Bonzinib45ef672011-08-03 10:49:07 +0200236void scsi_req_build_sense(SCSIRequest *req, SCSISense sense);
Gerd Hoffmannec766862009-11-26 15:34:01 +0100237void scsi_req_print(SCSIRequest *req);
Paolo Bonziniad3376c2011-04-18 15:28:11 +0200238void scsi_req_continue(SCSIRequest *req);
Paolo Bonziniab9adc82011-04-18 14:59:13 +0200239void scsi_req_data(SCSIRequest *req, int len);
Paolo Bonzini682a9b22011-08-03 10:49:06 +0200240void scsi_req_complete(SCSIRequest *req, int status);
Paolo Bonzini0c344592011-04-21 13:21:02 +0200241uint8_t *scsi_req_get_buf(SCSIRequest *req);
Hannes Reinecke74382212011-04-18 13:36:02 +0200242int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
Paolo Bonzini19d110a2011-04-18 17:14:51 +0200243void scsi_req_abort(SCSIRequest *req, int status);
Paolo Bonzini94d3f982011-04-18 22:53:08 +0200244void scsi_req_cancel(SCSIRequest *req);
Paolo Bonzini71544d32011-10-25 12:53:36 +0200245void scsi_req_retry(SCSIRequest *req);
Paolo Bonzinic7b48872011-08-03 10:49:18 +0200246void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
Paolo Bonzinie48e84e2012-07-16 14:18:58 +0200247void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense);
Paolo Bonzini53200fa2012-07-16 14:22:36 +0200248void scsi_device_report_change(SCSIDevice *dev, SCSISense sense);
Paolo Bonzinib45ef672011-08-03 10:49:07 +0200249int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
Paolo Bonzini0d3545e2011-07-27 23:24:50 +0200250SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
Gerd Hoffmann89b08ae2009-11-26 15:33:50 +0100251
Paolo Bonzini765d1522011-10-12 12:54:31 +0200252/* scsi-generic.c. */
253extern const SCSIReqOps scsi_generic_req_ops;
254
Gerd Hoffmann43b443b2009-10-30 09:54:00 +0100255#endif