root / hw / scsi-bus.c @ cde844fa
History | View | Annotate | Download (39.5 kB)
1 | d52affa7 | Gerd Hoffmann | #include "hw.h" |
---|---|---|---|
2 | 2f792016 | Markus Armbruster | #include "qemu-error.h" |
3 | 43b443b6 | Gerd Hoffmann | #include "scsi.h" |
4 | 2ec749cb | Gerd Hoffmann | #include "scsi-defs.h" |
5 | d52affa7 | Gerd Hoffmann | #include "qdev.h" |
6 | 2446333c | Blue Swirl | #include "blockdev.h" |
7 | 5138efec | Paolo Bonzini | #include "trace.h" |
8 | d52affa7 | Gerd Hoffmann | |
9 | db07c0f8 | Gleb Natapov | static char *scsibus_get_fw_dev_path(DeviceState *dev); |
10 | afa46c46 | Paolo Bonzini | static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf); |
11 | 71544d30 | Paolo Bonzini | static void scsi_req_dequeue(SCSIRequest *req); |
12 | db07c0f8 | Gleb Natapov | |
13 | d52affa7 | Gerd Hoffmann | static struct BusInfo scsi_bus_info = { |
14 | d52affa7 | Gerd Hoffmann | .name = "SCSI",
|
15 | d52affa7 | Gerd Hoffmann | .size = sizeof(SCSIBus),
|
16 | db07c0f8 | Gleb Natapov | .get_fw_dev_path = scsibus_get_fw_dev_path, |
17 | d52affa7 | Gerd Hoffmann | .props = (Property[]) { |
18 | 0d3545e7 | Paolo Bonzini | DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0), |
19 | d52affa7 | Gerd Hoffmann | DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1), |
20 | 7e0380b9 | Paolo Bonzini | DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1), |
21 | d52affa7 | Gerd Hoffmann | DEFINE_PROP_END_OF_LIST(), |
22 | d52affa7 | Gerd Hoffmann | }, |
23 | d52affa7 | Gerd Hoffmann | }; |
24 | d52affa7 | Gerd Hoffmann | static int next_scsi_bus; |
25 | d52affa7 | Gerd Hoffmann | |
26 | d52affa7 | Gerd Hoffmann | /* Create a scsi bus, and attach devices to it. */
|
27 | afd4030c | Paolo Bonzini | void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info) |
28 | d52affa7 | Gerd Hoffmann | { |
29 | ca9c39fa | Gerd Hoffmann | qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL);
|
30 | d52affa7 | Gerd Hoffmann | bus->busnr = next_scsi_bus++; |
31 | afd4030c | Paolo Bonzini | bus->info = info; |
32 | cb23117b | Gerd Hoffmann | bus->qbus.allow_hotplug = 1;
|
33 | d52affa7 | Gerd Hoffmann | } |
34 | d52affa7 | Gerd Hoffmann | |
35 | 71544d30 | Paolo Bonzini | static void scsi_dma_restart_bh(void *opaque) |
36 | 71544d30 | Paolo Bonzini | { |
37 | 71544d30 | Paolo Bonzini | SCSIDevice *s = opaque; |
38 | 71544d30 | Paolo Bonzini | SCSIRequest *req, *next; |
39 | 71544d30 | Paolo Bonzini | |
40 | 71544d30 | Paolo Bonzini | qemu_bh_delete(s->bh); |
41 | 71544d30 | Paolo Bonzini | s->bh = NULL;
|
42 | 71544d30 | Paolo Bonzini | |
43 | 71544d30 | Paolo Bonzini | QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) { |
44 | 71544d30 | Paolo Bonzini | scsi_req_ref(req); |
45 | 71544d30 | Paolo Bonzini | if (req->retry) {
|
46 | 71544d30 | Paolo Bonzini | req->retry = false;
|
47 | 71544d30 | Paolo Bonzini | switch (req->cmd.mode) {
|
48 | 71544d30 | Paolo Bonzini | case SCSI_XFER_FROM_DEV:
|
49 | 71544d30 | Paolo Bonzini | case SCSI_XFER_TO_DEV:
|
50 | 71544d30 | Paolo Bonzini | scsi_req_continue(req); |
51 | 71544d30 | Paolo Bonzini | break;
|
52 | 71544d30 | Paolo Bonzini | case SCSI_XFER_NONE:
|
53 | 71544d30 | Paolo Bonzini | scsi_req_dequeue(req); |
54 | 71544d30 | Paolo Bonzini | scsi_req_enqueue(req); |
55 | 71544d30 | Paolo Bonzini | break;
|
56 | 71544d30 | Paolo Bonzini | } |
57 | 71544d30 | Paolo Bonzini | } |
58 | 71544d30 | Paolo Bonzini | scsi_req_unref(req); |
59 | 71544d30 | Paolo Bonzini | } |
60 | 71544d30 | Paolo Bonzini | } |
61 | 71544d30 | Paolo Bonzini | |
62 | 71544d30 | Paolo Bonzini | void scsi_req_retry(SCSIRequest *req)
|
63 | 71544d30 | Paolo Bonzini | { |
64 | 71544d30 | Paolo Bonzini | /* No need to save a reference, because scsi_dma_restart_bh just
|
65 | 71544d30 | Paolo Bonzini | * looks at the request list. */
|
66 | 71544d30 | Paolo Bonzini | req->retry = true;
|
67 | 71544d30 | Paolo Bonzini | } |
68 | 71544d30 | Paolo Bonzini | |
69 | 71544d30 | Paolo Bonzini | static void scsi_dma_restart_cb(void *opaque, int running, RunState state) |
70 | 71544d30 | Paolo Bonzini | { |
71 | 71544d30 | Paolo Bonzini | SCSIDevice *s = opaque; |
72 | 71544d30 | Paolo Bonzini | |
73 | 71544d30 | Paolo Bonzini | if (!running) {
|
74 | 71544d30 | Paolo Bonzini | return;
|
75 | 71544d30 | Paolo Bonzini | } |
76 | 71544d30 | Paolo Bonzini | if (!s->bh) {
|
77 | 71544d30 | Paolo Bonzini | s->bh = qemu_bh_new(scsi_dma_restart_bh, s); |
78 | 71544d30 | Paolo Bonzini | qemu_bh_schedule(s->bh); |
79 | 71544d30 | Paolo Bonzini | } |
80 | 71544d30 | Paolo Bonzini | } |
81 | 71544d30 | Paolo Bonzini | |
82 | d52affa7 | Gerd Hoffmann | static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base) |
83 | d52affa7 | Gerd Hoffmann | { |
84 | d52affa7 | Gerd Hoffmann | SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); |
85 | d52affa7 | Gerd Hoffmann | SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base); |
86 | d52affa7 | Gerd Hoffmann | SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus); |
87 | 7e0380b9 | Paolo Bonzini | SCSIDevice *d; |
88 | 01985dcf | Gerd Hoffmann | int rc = -1; |
89 | d52affa7 | Gerd Hoffmann | |
90 | 0d3545e7 | Paolo Bonzini | if (dev->channel > bus->info->max_channel) {
|
91 | 0d3545e7 | Paolo Bonzini | error_report("bad scsi channel id: %d", dev->channel);
|
92 | 0d3545e7 | Paolo Bonzini | goto err;
|
93 | 0d3545e7 | Paolo Bonzini | } |
94 | 7e0380b9 | Paolo Bonzini | if (dev->id != -1 && dev->id > bus->info->max_target) { |
95 | 1ecda02b | Markus Armbruster | error_report("bad scsi device id: %d", dev->id);
|
96 | d52affa7 | Gerd Hoffmann | goto err;
|
97 | d52affa7 | Gerd Hoffmann | } |
98 | d52affa7 | Gerd Hoffmann | |
99 | 7e0380b9 | Paolo Bonzini | if (dev->id == -1) { |
100 | 7e0380b9 | Paolo Bonzini | int id = -1; |
101 | 7e0380b9 | Paolo Bonzini | if (dev->lun == -1) { |
102 | 7e0380b9 | Paolo Bonzini | dev->lun = 0;
|
103 | 7e0380b9 | Paolo Bonzini | } |
104 | 7e0380b9 | Paolo Bonzini | do {
|
105 | 0d3545e7 | Paolo Bonzini | d = scsi_device_find(bus, dev->channel, ++id, dev->lun); |
106 | 7e0380b9 | Paolo Bonzini | } while (d && d->lun == dev->lun && id <= bus->info->max_target);
|
107 | 7e0380b9 | Paolo Bonzini | if (id > bus->info->max_target) {
|
108 | 7e0380b9 | Paolo Bonzini | error_report("no free target");
|
109 | 7e0380b9 | Paolo Bonzini | goto err;
|
110 | 7e0380b9 | Paolo Bonzini | } |
111 | 7e0380b9 | Paolo Bonzini | dev->id = id; |
112 | 7e0380b9 | Paolo Bonzini | } else if (dev->lun == -1) { |
113 | 7e0380b9 | Paolo Bonzini | int lun = -1; |
114 | 7e0380b9 | Paolo Bonzini | do {
|
115 | 0d3545e7 | Paolo Bonzini | d = scsi_device_find(bus, dev->channel, dev->id, ++lun); |
116 | 7e0380b9 | Paolo Bonzini | } while (d && d->lun == lun && lun < bus->info->max_lun);
|
117 | 7e0380b9 | Paolo Bonzini | if (lun > bus->info->max_lun) {
|
118 | 7e0380b9 | Paolo Bonzini | error_report("no free lun");
|
119 | 7e0380b9 | Paolo Bonzini | goto err;
|
120 | 7e0380b9 | Paolo Bonzini | } |
121 | 7e0380b9 | Paolo Bonzini | dev->lun = lun; |
122 | 7e0380b9 | Paolo Bonzini | } else {
|
123 | 0d3545e7 | Paolo Bonzini | d = scsi_device_find(bus, dev->channel, dev->id, dev->lun); |
124 | 7e0380b9 | Paolo Bonzini | if (dev->lun == d->lun && dev != d) {
|
125 | 7e0380b9 | Paolo Bonzini | qdev_free(&d->qdev); |
126 | 7e0380b9 | Paolo Bonzini | } |
127 | d52affa7 | Gerd Hoffmann | } |
128 | d52affa7 | Gerd Hoffmann | |
129 | d52affa7 | Gerd Hoffmann | dev->info = info; |
130 | 9af99d98 | Gerd Hoffmann | QTAILQ_INIT(&dev->requests); |
131 | 01985dcf | Gerd Hoffmann | rc = dev->info->init(dev); |
132 | 71544d30 | Paolo Bonzini | if (rc == 0) { |
133 | 71544d30 | Paolo Bonzini | dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb, |
134 | 71544d30 | Paolo Bonzini | dev); |
135 | 71544d30 | Paolo Bonzini | } |
136 | d52affa7 | Gerd Hoffmann | |
137 | d52affa7 | Gerd Hoffmann | err:
|
138 | 01985dcf | Gerd Hoffmann | return rc;
|
139 | 01985dcf | Gerd Hoffmann | } |
140 | 01985dcf | Gerd Hoffmann | |
141 | 01985dcf | Gerd Hoffmann | static int scsi_qdev_exit(DeviceState *qdev) |
142 | 01985dcf | Gerd Hoffmann | { |
143 | 01985dcf | Gerd Hoffmann | SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); |
144 | 01985dcf | Gerd Hoffmann | |
145 | 71544d30 | Paolo Bonzini | if (dev->vmsentry) {
|
146 | 71544d30 | Paolo Bonzini | qemu_del_vm_change_state_handler(dev->vmsentry); |
147 | 71544d30 | Paolo Bonzini | } |
148 | f48a7a6e | Paolo Bonzini | if (dev->info->destroy) {
|
149 | f48a7a6e | Paolo Bonzini | dev->info->destroy(dev); |
150 | 01985dcf | Gerd Hoffmann | } |
151 | 01985dcf | Gerd Hoffmann | return 0; |
152 | d52affa7 | Gerd Hoffmann | } |
153 | d52affa7 | Gerd Hoffmann | |
154 | d52affa7 | Gerd Hoffmann | void scsi_qdev_register(SCSIDeviceInfo *info)
|
155 | d52affa7 | Gerd Hoffmann | { |
156 | d52affa7 | Gerd Hoffmann | info->qdev.bus_info = &scsi_bus_info; |
157 | d52affa7 | Gerd Hoffmann | info->qdev.init = scsi_qdev_init; |
158 | cb23117b | Gerd Hoffmann | info->qdev.unplug = qdev_simple_unplug_cb; |
159 | 01985dcf | Gerd Hoffmann | info->qdev.exit = scsi_qdev_exit; |
160 | d52affa7 | Gerd Hoffmann | qdev_register(&info->qdev); |
161 | d52affa7 | Gerd Hoffmann | } |
162 | d52affa7 | Gerd Hoffmann | |
163 | d52affa7 | Gerd Hoffmann | /* handle legacy '-drive if=scsi,...' cmd line args */
|
164 | 2d1fd261 | Stefan Hajnoczi | SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, |
165 | 2d1fd261 | Stefan Hajnoczi | int unit, bool removable) |
166 | d52affa7 | Gerd Hoffmann | { |
167 | d52affa7 | Gerd Hoffmann | const char *driver; |
168 | d52affa7 | Gerd Hoffmann | DeviceState *dev; |
169 | d52affa7 | Gerd Hoffmann | |
170 | f8b6cc00 | Markus Armbruster | driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk"; |
171 | d52affa7 | Gerd Hoffmann | dev = qdev_create(&bus->qbus, driver); |
172 | d52affa7 | Gerd Hoffmann | qdev_prop_set_uint32(dev, "scsi-id", unit);
|
173 | 2d1fd261 | Stefan Hajnoczi | if (qdev_prop_exists(dev, "removable")) { |
174 | 2d1fd261 | Stefan Hajnoczi | qdev_prop_set_bit(dev, "removable", removable);
|
175 | 2d1fd261 | Stefan Hajnoczi | } |
176 | 18846dee | Markus Armbruster | if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) { |
177 | 18846dee | Markus Armbruster | qdev_free(dev); |
178 | 18846dee | Markus Armbruster | return NULL; |
179 | 18846dee | Markus Armbruster | } |
180 | 33e66b86 | Markus Armbruster | if (qdev_init(dev) < 0) |
181 | 33e66b86 | Markus Armbruster | return NULL; |
182 | d52affa7 | Gerd Hoffmann | return DO_UPCAST(SCSIDevice, qdev, dev);
|
183 | d52affa7 | Gerd Hoffmann | } |
184 | d52affa7 | Gerd Hoffmann | |
185 | fa66b909 | Markus Armbruster | int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
|
186 | d52affa7 | Gerd Hoffmann | { |
187 | 42e766a2 | Markus Armbruster | Location loc; |
188 | d52affa7 | Gerd Hoffmann | DriveInfo *dinfo; |
189 | fa66b909 | Markus Armbruster | int res = 0, unit; |
190 | d52affa7 | Gerd Hoffmann | |
191 | 42e766a2 | Markus Armbruster | loc_push_none(&loc); |
192 | 7e0380b9 | Paolo Bonzini | for (unit = 0; unit < bus->info->max_target; unit++) { |
193 | d52affa7 | Gerd Hoffmann | dinfo = drive_get(IF_SCSI, bus->busnr, unit); |
194 | d52affa7 | Gerd Hoffmann | if (dinfo == NULL) { |
195 | d52affa7 | Gerd Hoffmann | continue;
|
196 | d52affa7 | Gerd Hoffmann | } |
197 | 42e766a2 | Markus Armbruster | qemu_opts_loc_restore(dinfo->opts); |
198 | 2d1fd261 | Stefan Hajnoczi | if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false)) { |
199 | fa66b909 | Markus Armbruster | res = -1;
|
200 | fa66b909 | Markus Armbruster | break;
|
201 | fa66b909 | Markus Armbruster | } |
202 | d52affa7 | Gerd Hoffmann | } |
203 | 42e766a2 | Markus Armbruster | loc_pop(&loc); |
204 | fa66b909 | Markus Armbruster | return res;
|
205 | d52affa7 | Gerd Hoffmann | } |
206 | 89b08ae1 | Gerd Hoffmann | |
207 | afa46c46 | Paolo Bonzini | /* SCSIReqOps implementation for invalid commands. */
|
208 | afa46c46 | Paolo Bonzini | |
209 | afa46c46 | Paolo Bonzini | static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf)
|
210 | afa46c46 | Paolo Bonzini | { |
211 | afa46c46 | Paolo Bonzini | scsi_req_build_sense(req, SENSE_CODE(INVALID_OPCODE)); |
212 | afa46c46 | Paolo Bonzini | scsi_req_complete(req, CHECK_CONDITION); |
213 | afa46c46 | Paolo Bonzini | return 0; |
214 | afa46c46 | Paolo Bonzini | } |
215 | afa46c46 | Paolo Bonzini | |
216 | adcf2754 | Paolo Bonzini | static const struct SCSIReqOps reqops_invalid_opcode = { |
217 | afa46c46 | Paolo Bonzini | .size = sizeof(SCSIRequest),
|
218 | afa46c46 | Paolo Bonzini | .send_command = scsi_invalid_command |
219 | afa46c46 | Paolo Bonzini | }; |
220 | afa46c46 | Paolo Bonzini | |
221 | 6dc06f08 | Paolo Bonzini | /* SCSIReqOps implementation for unit attention conditions. */
|
222 | 6dc06f08 | Paolo Bonzini | |
223 | 6dc06f08 | Paolo Bonzini | static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
|
224 | 6dc06f08 | Paolo Bonzini | { |
225 | 6dc06f08 | Paolo Bonzini | if (req->dev && req->dev->unit_attention.key == UNIT_ATTENTION) {
|
226 | 6dc06f08 | Paolo Bonzini | scsi_req_build_sense(req, req->dev->unit_attention); |
227 | 6dc06f08 | Paolo Bonzini | } else if (req->bus->unit_attention.key == UNIT_ATTENTION) { |
228 | 6dc06f08 | Paolo Bonzini | scsi_req_build_sense(req, req->bus->unit_attention); |
229 | 6dc06f08 | Paolo Bonzini | } |
230 | 6dc06f08 | Paolo Bonzini | scsi_req_complete(req, CHECK_CONDITION); |
231 | 6dc06f08 | Paolo Bonzini | return 0; |
232 | 6dc06f08 | Paolo Bonzini | } |
233 | 6dc06f08 | Paolo Bonzini | |
234 | adcf2754 | Paolo Bonzini | static const struct SCSIReqOps reqops_unit_attention = { |
235 | 6dc06f08 | Paolo Bonzini | .size = sizeof(SCSIRequest),
|
236 | 6dc06f08 | Paolo Bonzini | .send_command = scsi_unit_attention |
237 | 6dc06f08 | Paolo Bonzini | }; |
238 | 6dc06f08 | Paolo Bonzini | |
239 | fdaef069 | Paolo Bonzini | /* SCSIReqOps implementation for REPORT LUNS and for commands sent to
|
240 | fdaef069 | Paolo Bonzini | an invalid LUN. */
|
241 | fdaef069 | Paolo Bonzini | |
242 | fdaef069 | Paolo Bonzini | typedef struct SCSITargetReq SCSITargetReq; |
243 | fdaef069 | Paolo Bonzini | |
244 | fdaef069 | Paolo Bonzini | struct SCSITargetReq {
|
245 | fdaef069 | Paolo Bonzini | SCSIRequest req; |
246 | fdaef069 | Paolo Bonzini | int len;
|
247 | ba74307c | Paolo Bonzini | uint8_t buf[2056];
|
248 | fdaef069 | Paolo Bonzini | }; |
249 | fdaef069 | Paolo Bonzini | |
250 | fdaef069 | Paolo Bonzini | static void store_lun(uint8_t *outbuf, int lun) |
251 | fdaef069 | Paolo Bonzini | { |
252 | fdaef069 | Paolo Bonzini | if (lun < 256) { |
253 | fdaef069 | Paolo Bonzini | outbuf[1] = lun;
|
254 | fdaef069 | Paolo Bonzini | return;
|
255 | fdaef069 | Paolo Bonzini | } |
256 | fdaef069 | Paolo Bonzini | outbuf[1] = (lun & 255); |
257 | fdaef069 | Paolo Bonzini | outbuf[0] = (lun >> 8) | 0x40; |
258 | fdaef069 | Paolo Bonzini | } |
259 | fdaef069 | Paolo Bonzini | |
260 | fdaef069 | Paolo Bonzini | static bool scsi_target_emulate_report_luns(SCSITargetReq *r) |
261 | fdaef069 | Paolo Bonzini | { |
262 | ba74307c | Paolo Bonzini | DeviceState *qdev; |
263 | ba74307c | Paolo Bonzini | int i, len, n;
|
264 | 0d3545e7 | Paolo Bonzini | int channel, id;
|
265 | ba74307c | Paolo Bonzini | bool found_lun0;
|
266 | ba74307c | Paolo Bonzini | |
267 | fdaef069 | Paolo Bonzini | if (r->req.cmd.xfer < 16) { |
268 | fdaef069 | Paolo Bonzini | return false; |
269 | fdaef069 | Paolo Bonzini | } |
270 | fdaef069 | Paolo Bonzini | if (r->req.cmd.buf[2] > 2) { |
271 | fdaef069 | Paolo Bonzini | return false; |
272 | fdaef069 | Paolo Bonzini | } |
273 | 0d3545e7 | Paolo Bonzini | channel = r->req.dev->channel; |
274 | ba74307c | Paolo Bonzini | id = r->req.dev->id; |
275 | ba74307c | Paolo Bonzini | found_lun0 = false;
|
276 | ba74307c | Paolo Bonzini | n = 0;
|
277 | ba74307c | Paolo Bonzini | QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) { |
278 | ba74307c | Paolo Bonzini | SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); |
279 | ba74307c | Paolo Bonzini | |
280 | 0d3545e7 | Paolo Bonzini | if (dev->channel == channel && dev->id == id) {
|
281 | ba74307c | Paolo Bonzini | if (dev->lun == 0) { |
282 | ba74307c | Paolo Bonzini | found_lun0 = true;
|
283 | ba74307c | Paolo Bonzini | } |
284 | ba74307c | Paolo Bonzini | n += 8;
|
285 | ba74307c | Paolo Bonzini | } |
286 | ba74307c | Paolo Bonzini | } |
287 | ba74307c | Paolo Bonzini | if (!found_lun0) {
|
288 | ba74307c | Paolo Bonzini | n += 8;
|
289 | ba74307c | Paolo Bonzini | } |
290 | ba74307c | Paolo Bonzini | len = MIN(n + 8, r->req.cmd.xfer & ~7); |
291 | ba74307c | Paolo Bonzini | if (len > sizeof(r->buf)) { |
292 | ba74307c | Paolo Bonzini | /* TODO: > 256 LUNs? */
|
293 | ba74307c | Paolo Bonzini | return false; |
294 | ba74307c | Paolo Bonzini | } |
295 | ba74307c | Paolo Bonzini | |
296 | fdaef069 | Paolo Bonzini | memset(r->buf, 0, len);
|
297 | ba74307c | Paolo Bonzini | stl_be_p(&r->buf, n); |
298 | ba74307c | Paolo Bonzini | i = found_lun0 ? 8 : 16; |
299 | ba74307c | Paolo Bonzini | QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) { |
300 | ba74307c | Paolo Bonzini | SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); |
301 | ba74307c | Paolo Bonzini | |
302 | 0d3545e7 | Paolo Bonzini | if (dev->channel == channel && dev->id == id) {
|
303 | ba74307c | Paolo Bonzini | store_lun(&r->buf[i], dev->lun); |
304 | ba74307c | Paolo Bonzini | i += 8;
|
305 | ba74307c | Paolo Bonzini | } |
306 | fdaef069 | Paolo Bonzini | } |
307 | ba74307c | Paolo Bonzini | assert(i == n + 8);
|
308 | ba74307c | Paolo Bonzini | r->len = len; |
309 | fdaef069 | Paolo Bonzini | return true; |
310 | fdaef069 | Paolo Bonzini | } |
311 | fdaef069 | Paolo Bonzini | |
312 | fdaef069 | Paolo Bonzini | static bool scsi_target_emulate_inquiry(SCSITargetReq *r) |
313 | fdaef069 | Paolo Bonzini | { |
314 | fdaef069 | Paolo Bonzini | assert(r->req.dev->lun != r->req.lun); |
315 | fdaef069 | Paolo Bonzini | if (r->req.cmd.buf[1] & 0x2) { |
316 | fdaef069 | Paolo Bonzini | /* Command support data - optional, not implemented */
|
317 | fdaef069 | Paolo Bonzini | return false; |
318 | fdaef069 | Paolo Bonzini | } |
319 | fdaef069 | Paolo Bonzini | |
320 | fdaef069 | Paolo Bonzini | if (r->req.cmd.buf[1] & 0x1) { |
321 | fdaef069 | Paolo Bonzini | /* Vital product data */
|
322 | fdaef069 | Paolo Bonzini | uint8_t page_code = r->req.cmd.buf[2];
|
323 | fdaef069 | Paolo Bonzini | if (r->req.cmd.xfer < 4) { |
324 | fdaef069 | Paolo Bonzini | return false; |
325 | fdaef069 | Paolo Bonzini | } |
326 | fdaef069 | Paolo Bonzini | |
327 | fdaef069 | Paolo Bonzini | r->buf[r->len++] = page_code ; /* this page */
|
328 | fdaef069 | Paolo Bonzini | r->buf[r->len++] = 0x00;
|
329 | fdaef069 | Paolo Bonzini | |
330 | fdaef069 | Paolo Bonzini | switch (page_code) {
|
331 | fdaef069 | Paolo Bonzini | case 0x00: /* Supported page codes, mandatory */ |
332 | fdaef069 | Paolo Bonzini | { |
333 | fdaef069 | Paolo Bonzini | int pages;
|
334 | fdaef069 | Paolo Bonzini | pages = r->len++; |
335 | fdaef069 | Paolo Bonzini | r->buf[r->len++] = 0x00; /* list of supported pages (this page) */ |
336 | fdaef069 | Paolo Bonzini | r->buf[pages] = r->len - pages - 1; /* number of pages */ |
337 | fdaef069 | Paolo Bonzini | break;
|
338 | fdaef069 | Paolo Bonzini | } |
339 | fdaef069 | Paolo Bonzini | default:
|
340 | fdaef069 | Paolo Bonzini | return false; |
341 | fdaef069 | Paolo Bonzini | } |
342 | fdaef069 | Paolo Bonzini | /* done with EVPD */
|
343 | fdaef069 | Paolo Bonzini | assert(r->len < sizeof(r->buf));
|
344 | fdaef069 | Paolo Bonzini | r->len = MIN(r->req.cmd.xfer, r->len); |
345 | fdaef069 | Paolo Bonzini | return true; |
346 | fdaef069 | Paolo Bonzini | } |
347 | fdaef069 | Paolo Bonzini | |
348 | fdaef069 | Paolo Bonzini | /* Standard INQUIRY data */
|
349 | fdaef069 | Paolo Bonzini | if (r->req.cmd.buf[2] != 0) { |
350 | fdaef069 | Paolo Bonzini | return false; |
351 | fdaef069 | Paolo Bonzini | } |
352 | fdaef069 | Paolo Bonzini | |
353 | fdaef069 | Paolo Bonzini | /* PAGE CODE == 0 */
|
354 | fdaef069 | Paolo Bonzini | if (r->req.cmd.xfer < 5) { |
355 | fdaef069 | Paolo Bonzini | return -1; |
356 | fdaef069 | Paolo Bonzini | } |
357 | fdaef069 | Paolo Bonzini | |
358 | fdaef069 | Paolo Bonzini | r->len = MIN(r->req.cmd.xfer, 36);
|
359 | fdaef069 | Paolo Bonzini | memset(r->buf, 0, r->len);
|
360 | fdaef069 | Paolo Bonzini | if (r->req.lun != 0) { |
361 | fdaef069 | Paolo Bonzini | r->buf[0] = TYPE_NO_LUN;
|
362 | fdaef069 | Paolo Bonzini | } else {
|
363 | fdaef069 | Paolo Bonzini | r->buf[0] = TYPE_NOT_PRESENT | TYPE_INACTIVE;
|
364 | fdaef069 | Paolo Bonzini | r->buf[2] = 5; /* Version */ |
365 | fdaef069 | Paolo Bonzini | r->buf[3] = 2 | 0x10; /* HiSup, response data format */ |
366 | fdaef069 | Paolo Bonzini | r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */ |
367 | afd4030c | Paolo Bonzini | r->buf[7] = 0x10 | (r->req.bus->info->tcq ? 0x02 : 0); /* Sync, TCQ. */ |
368 | fdaef069 | Paolo Bonzini | memcpy(&r->buf[8], "QEMU ", 8); |
369 | fdaef069 | Paolo Bonzini | memcpy(&r->buf[16], "QEMU TARGET ", 16); |
370 | fdaef069 | Paolo Bonzini | strncpy((char *) &r->buf[32], QEMU_VERSION, 4); |
371 | fdaef069 | Paolo Bonzini | } |
372 | fdaef069 | Paolo Bonzini | return true; |
373 | fdaef069 | Paolo Bonzini | } |
374 | fdaef069 | Paolo Bonzini | |
375 | fdaef069 | Paolo Bonzini | static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
|
376 | fdaef069 | Paolo Bonzini | { |
377 | fdaef069 | Paolo Bonzini | SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req); |
378 | fdaef069 | Paolo Bonzini | |
379 | fdaef069 | Paolo Bonzini | switch (buf[0]) { |
380 | fdaef069 | Paolo Bonzini | case REPORT_LUNS:
|
381 | fdaef069 | Paolo Bonzini | if (!scsi_target_emulate_report_luns(r)) {
|
382 | fdaef069 | Paolo Bonzini | goto illegal_request;
|
383 | fdaef069 | Paolo Bonzini | } |
384 | fdaef069 | Paolo Bonzini | break;
|
385 | fdaef069 | Paolo Bonzini | case INQUIRY:
|
386 | fdaef069 | Paolo Bonzini | if (!scsi_target_emulate_inquiry(r)) {
|
387 | fdaef069 | Paolo Bonzini | goto illegal_request;
|
388 | fdaef069 | Paolo Bonzini | } |
389 | fdaef069 | Paolo Bonzini | break;
|
390 | 739df215 | Paolo Bonzini | case REQUEST_SENSE:
|
391 | 739df215 | Paolo Bonzini | if (req->cmd.xfer < 4) { |
392 | 739df215 | Paolo Bonzini | goto illegal_request;
|
393 | 739df215 | Paolo Bonzini | } |
394 | 8b2a04ee | Paolo Bonzini | r->len = scsi_device_get_sense(r->req.dev, r->buf, |
395 | 8b2a04ee | Paolo Bonzini | MIN(req->cmd.xfer, sizeof r->buf),
|
396 | 739df215 | Paolo Bonzini | (req->cmd.buf[1] & 1) == 0); |
397 | 3653d8c4 | Paolo Bonzini | if (r->req.dev->sense_is_ua) {
|
398 | 3653d8c4 | Paolo Bonzini | if (r->req.dev->info->unit_attention_reported) {
|
399 | 3653d8c4 | Paolo Bonzini | r->req.dev->info->unit_attention_reported(req->dev); |
400 | 3653d8c4 | Paolo Bonzini | } |
401 | 3653d8c4 | Paolo Bonzini | r->req.dev->sense_len = 0;
|
402 | 3653d8c4 | Paolo Bonzini | r->req.dev->sense_is_ua = false;
|
403 | 3653d8c4 | Paolo Bonzini | } |
404 | 739df215 | Paolo Bonzini | break;
|
405 | fdaef069 | Paolo Bonzini | default:
|
406 | fdaef069 | Paolo Bonzini | scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED)); |
407 | fdaef069 | Paolo Bonzini | scsi_req_complete(req, CHECK_CONDITION); |
408 | fdaef069 | Paolo Bonzini | return 0; |
409 | fdaef069 | Paolo Bonzini | illegal_request:
|
410 | fdaef069 | Paolo Bonzini | scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD)); |
411 | fdaef069 | Paolo Bonzini | scsi_req_complete(req, CHECK_CONDITION); |
412 | fdaef069 | Paolo Bonzini | return 0; |
413 | fdaef069 | Paolo Bonzini | } |
414 | fdaef069 | Paolo Bonzini | |
415 | fdaef069 | Paolo Bonzini | if (!r->len) {
|
416 | fdaef069 | Paolo Bonzini | scsi_req_complete(req, GOOD); |
417 | fdaef069 | Paolo Bonzini | } |
418 | fdaef069 | Paolo Bonzini | return r->len;
|
419 | fdaef069 | Paolo Bonzini | } |
420 | fdaef069 | Paolo Bonzini | |
421 | fdaef069 | Paolo Bonzini | static void scsi_target_read_data(SCSIRequest *req) |
422 | fdaef069 | Paolo Bonzini | { |
423 | fdaef069 | Paolo Bonzini | SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req); |
424 | fdaef069 | Paolo Bonzini | uint32_t n; |
425 | fdaef069 | Paolo Bonzini | |
426 | fdaef069 | Paolo Bonzini | n = r->len; |
427 | fdaef069 | Paolo Bonzini | if (n > 0) { |
428 | fdaef069 | Paolo Bonzini | r->len = 0;
|
429 | fdaef069 | Paolo Bonzini | scsi_req_data(&r->req, n); |
430 | fdaef069 | Paolo Bonzini | } else {
|
431 | fdaef069 | Paolo Bonzini | scsi_req_complete(&r->req, GOOD); |
432 | fdaef069 | Paolo Bonzini | } |
433 | fdaef069 | Paolo Bonzini | } |
434 | fdaef069 | Paolo Bonzini | |
435 | fdaef069 | Paolo Bonzini | static uint8_t *scsi_target_get_buf(SCSIRequest *req)
|
436 | fdaef069 | Paolo Bonzini | { |
437 | fdaef069 | Paolo Bonzini | SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req); |
438 | fdaef069 | Paolo Bonzini | |
439 | fdaef069 | Paolo Bonzini | return r->buf;
|
440 | fdaef069 | Paolo Bonzini | } |
441 | fdaef069 | Paolo Bonzini | |
442 | adcf2754 | Paolo Bonzini | static const struct SCSIReqOps reqops_target_command = { |
443 | fdaef069 | Paolo Bonzini | .size = sizeof(SCSITargetReq),
|
444 | fdaef069 | Paolo Bonzini | .send_command = scsi_target_send_command, |
445 | fdaef069 | Paolo Bonzini | .read_data = scsi_target_read_data, |
446 | fdaef069 | Paolo Bonzini | .get_buf = scsi_target_get_buf, |
447 | fdaef069 | Paolo Bonzini | }; |
448 | fdaef069 | Paolo Bonzini | |
449 | fdaef069 | Paolo Bonzini | |
450 | adcf2754 | Paolo Bonzini | SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
|
451 | adcf2754 | Paolo Bonzini | uint32_t tag, uint32_t lun, void *hba_private)
|
452 | 89b08ae1 | Gerd Hoffmann | { |
453 | 89b08ae1 | Gerd Hoffmann | SCSIRequest *req; |
454 | 89b08ae1 | Gerd Hoffmann | |
455 | 7267c094 | Anthony Liguori | req = g_malloc0(reqops->size); |
456 | 5c6c0e51 | Hannes Reinecke | req->refcount = 1;
|
457 | 89b08ae1 | Gerd Hoffmann | req->bus = scsi_bus_from_device(d); |
458 | 89b08ae1 | Gerd Hoffmann | req->dev = d; |
459 | 89b08ae1 | Gerd Hoffmann | req->tag = tag; |
460 | 89b08ae1 | Gerd Hoffmann | req->lun = lun; |
461 | c5bf71a9 | Hannes Reinecke | req->hba_private = hba_private; |
462 | ed3a34a3 | Gerd Hoffmann | req->status = -1;
|
463 | b45ef674 | Paolo Bonzini | req->sense_len = 0;
|
464 | 8dbd4574 | Paolo Bonzini | req->ops = reqops; |
465 | 5138efec | Paolo Bonzini | trace_scsi_req_alloc(req->dev->id, req->lun, req->tag); |
466 | 89b08ae1 | Gerd Hoffmann | return req;
|
467 | 89b08ae1 | Gerd Hoffmann | } |
468 | 89b08ae1 | Gerd Hoffmann | |
469 | c5bf71a9 | Hannes Reinecke | SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, |
470 | c39ce112 | Paolo Bonzini | uint8_t *buf, void *hba_private)
|
471 | 43a2b339 | Paolo Bonzini | { |
472 | 6dc06f08 | Paolo Bonzini | SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus); |
473 | c39ce112 | Paolo Bonzini | SCSIRequest *req; |
474 | afa46c46 | Paolo Bonzini | SCSICommand cmd; |
475 | afa46c46 | Paolo Bonzini | |
476 | afa46c46 | Paolo Bonzini | if (scsi_req_parse(&cmd, d, buf) != 0) { |
477 | afa46c46 | Paolo Bonzini | trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]);
|
478 | afa46c46 | Paolo Bonzini | req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private); |
479 | afa46c46 | Paolo Bonzini | } else {
|
480 | afa46c46 | Paolo Bonzini | trace_scsi_req_parsed(d->id, lun, tag, buf[0],
|
481 | afa46c46 | Paolo Bonzini | cmd.mode, cmd.xfer); |
482 | 3b6ffe50 | Peter Maydell | if (cmd.lba != -1) { |
483 | afa46c46 | Paolo Bonzini | trace_scsi_req_parsed_lba(d->id, lun, tag, buf[0],
|
484 | afa46c46 | Paolo Bonzini | cmd.lba); |
485 | afa46c46 | Paolo Bonzini | } |
486 | fdaef069 | Paolo Bonzini | |
487 | 6dc06f08 | Paolo Bonzini | if ((d->unit_attention.key == UNIT_ATTENTION ||
|
488 | 6dc06f08 | Paolo Bonzini | bus->unit_attention.key == UNIT_ATTENTION) && |
489 | 6dc06f08 | Paolo Bonzini | (buf[0] != INQUIRY &&
|
490 | 6dc06f08 | Paolo Bonzini | buf[0] != REPORT_LUNS &&
|
491 | 6dc06f08 | Paolo Bonzini | buf[0] != GET_CONFIGURATION &&
|
492 | 3653d8c4 | Paolo Bonzini | buf[0] != GET_EVENT_STATUS_NOTIFICATION &&
|
493 | 3653d8c4 | Paolo Bonzini | |
494 | 3653d8c4 | Paolo Bonzini | /*
|
495 | 3653d8c4 | Paolo Bonzini | * If we already have a pending unit attention condition,
|
496 | 3653d8c4 | Paolo Bonzini | * report this one before triggering another one.
|
497 | 3653d8c4 | Paolo Bonzini | */
|
498 | 3653d8c4 | Paolo Bonzini | !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) {
|
499 | 6dc06f08 | Paolo Bonzini | req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun, |
500 | 6dc06f08 | Paolo Bonzini | hba_private); |
501 | 6dc06f08 | Paolo Bonzini | } else if (lun != d->lun || |
502 | 739df215 | Paolo Bonzini | buf[0] == REPORT_LUNS ||
|
503 | f3b338ef | Paolo Bonzini | (buf[0] == REQUEST_SENSE && (d->sense_len || cmd.xfer < 4))) { |
504 | fdaef069 | Paolo Bonzini | req = scsi_req_alloc(&reqops_target_command, d, tag, lun, |
505 | fdaef069 | Paolo Bonzini | hba_private); |
506 | fdaef069 | Paolo Bonzini | } else {
|
507 | 63db0f0e | Paolo Bonzini | req = d->info->alloc_req(d, tag, lun, buf, hba_private); |
508 | fdaef069 | Paolo Bonzini | } |
509 | afa46c46 | Paolo Bonzini | } |
510 | afa46c46 | Paolo Bonzini | |
511 | afa46c46 | Paolo Bonzini | req->cmd = cmd; |
512 | 98254542 | Paolo Bonzini | switch (buf[0]) { |
513 | 98254542 | Paolo Bonzini | case INQUIRY:
|
514 | 98254542 | Paolo Bonzini | trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]); |
515 | 98254542 | Paolo Bonzini | break;
|
516 | 98254542 | Paolo Bonzini | case TEST_UNIT_READY:
|
517 | 98254542 | Paolo Bonzini | trace_scsi_test_unit_ready(d->id, lun, tag); |
518 | 98254542 | Paolo Bonzini | break;
|
519 | 98254542 | Paolo Bonzini | case REPORT_LUNS:
|
520 | 98254542 | Paolo Bonzini | trace_scsi_report_luns(d->id, lun, tag); |
521 | 98254542 | Paolo Bonzini | break;
|
522 | 98254542 | Paolo Bonzini | case REQUEST_SENSE:
|
523 | 98254542 | Paolo Bonzini | trace_scsi_request_sense(d->id, lun, tag); |
524 | 98254542 | Paolo Bonzini | break;
|
525 | 98254542 | Paolo Bonzini | default:
|
526 | 98254542 | Paolo Bonzini | break;
|
527 | 98254542 | Paolo Bonzini | } |
528 | 98254542 | Paolo Bonzini | |
529 | c39ce112 | Paolo Bonzini | return req;
|
530 | 43a2b339 | Paolo Bonzini | } |
531 | 43a2b339 | Paolo Bonzini | |
532 | 0c34459b | Paolo Bonzini | uint8_t *scsi_req_get_buf(SCSIRequest *req) |
533 | 0c34459b | Paolo Bonzini | { |
534 | 12010e7b | Paolo Bonzini | return req->ops->get_buf(req);
|
535 | 0c34459b | Paolo Bonzini | } |
536 | 0c34459b | Paolo Bonzini | |
537 | 6dc06f08 | Paolo Bonzini | static void scsi_clear_unit_attention(SCSIRequest *req) |
538 | 6dc06f08 | Paolo Bonzini | { |
539 | 6dc06f08 | Paolo Bonzini | SCSISense *ua; |
540 | 6dc06f08 | Paolo Bonzini | if (req->dev->unit_attention.key != UNIT_ATTENTION &&
|
541 | 6dc06f08 | Paolo Bonzini | req->bus->unit_attention.key != UNIT_ATTENTION) { |
542 | 6dc06f08 | Paolo Bonzini | return;
|
543 | 6dc06f08 | Paolo Bonzini | } |
544 | 6dc06f08 | Paolo Bonzini | |
545 | 6dc06f08 | Paolo Bonzini | /*
|
546 | 6dc06f08 | Paolo Bonzini | * If an INQUIRY command enters the enabled command state,
|
547 | 6dc06f08 | Paolo Bonzini | * the device server shall [not] clear any unit attention condition;
|
548 | 6dc06f08 | Paolo Bonzini | * See also MMC-6, paragraphs 6.5 and 6.6.2.
|
549 | 6dc06f08 | Paolo Bonzini | */
|
550 | 6dc06f08 | Paolo Bonzini | if (req->cmd.buf[0] == INQUIRY || |
551 | 6dc06f08 | Paolo Bonzini | req->cmd.buf[0] == GET_CONFIGURATION ||
|
552 | 6dc06f08 | Paolo Bonzini | req->cmd.buf[0] == GET_EVENT_STATUS_NOTIFICATION) {
|
553 | 6dc06f08 | Paolo Bonzini | return;
|
554 | 6dc06f08 | Paolo Bonzini | } |
555 | 6dc06f08 | Paolo Bonzini | |
556 | 6dc06f08 | Paolo Bonzini | if (req->dev->unit_attention.key == UNIT_ATTENTION) {
|
557 | 6dc06f08 | Paolo Bonzini | ua = &req->dev->unit_attention; |
558 | 6dc06f08 | Paolo Bonzini | } else {
|
559 | 6dc06f08 | Paolo Bonzini | ua = &req->bus->unit_attention; |
560 | 6dc06f08 | Paolo Bonzini | } |
561 | 6dc06f08 | Paolo Bonzini | |
562 | 6dc06f08 | Paolo Bonzini | /*
|
563 | 6dc06f08 | Paolo Bonzini | * If a REPORT LUNS command enters the enabled command state, [...]
|
564 | 6dc06f08 | Paolo Bonzini | * the device server shall clear any pending unit attention condition
|
565 | 6dc06f08 | Paolo Bonzini | * with an additional sense code of REPORTED LUNS DATA HAS CHANGED.
|
566 | 6dc06f08 | Paolo Bonzini | */
|
567 | 6dc06f08 | Paolo Bonzini | if (req->cmd.buf[0] == REPORT_LUNS && |
568 | 6dc06f08 | Paolo Bonzini | !(ua->asc == SENSE_CODE(REPORTED_LUNS_CHANGED).asc && |
569 | 6dc06f08 | Paolo Bonzini | ua->ascq == SENSE_CODE(REPORTED_LUNS_CHANGED).ascq)) { |
570 | 6dc06f08 | Paolo Bonzini | return;
|
571 | 6dc06f08 | Paolo Bonzini | } |
572 | 6dc06f08 | Paolo Bonzini | |
573 | 6dc06f08 | Paolo Bonzini | *ua = SENSE_CODE(NO_SENSE); |
574 | 6dc06f08 | Paolo Bonzini | } |
575 | 6dc06f08 | Paolo Bonzini | |
576 | 74382217 | Hannes Reinecke | int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len) |
577 | 74382217 | Hannes Reinecke | { |
578 | 6dc06f08 | Paolo Bonzini | int ret;
|
579 | 6dc06f08 | Paolo Bonzini | |
580 | b45ef674 | Paolo Bonzini | assert(len >= 14);
|
581 | b45ef674 | Paolo Bonzini | if (!req->sense_len) {
|
582 | 74382217 | Hannes Reinecke | return 0; |
583 | 74382217 | Hannes Reinecke | } |
584 | 6dc06f08 | Paolo Bonzini | |
585 | 6dc06f08 | Paolo Bonzini | ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true);
|
586 | 6dc06f08 | Paolo Bonzini | |
587 | 6dc06f08 | Paolo Bonzini | /*
|
588 | 6dc06f08 | Paolo Bonzini | * FIXME: clearing unit attention conditions upon autosense should be done
|
589 | 6dc06f08 | Paolo Bonzini | * only if the UA_INTLCK_CTRL field in the Control mode page is set to 00b
|
590 | 6dc06f08 | Paolo Bonzini | * (SAM-5, 5.14).
|
591 | 6dc06f08 | Paolo Bonzini | *
|
592 | 6dc06f08 | Paolo Bonzini | * We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and
|
593 | 6dc06f08 | Paolo Bonzini | * 10b for HBAs that do not support it (do not call scsi_req_get_sense).
|
594 | 3653d8c4 | Paolo Bonzini | * Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
|
595 | 6dc06f08 | Paolo Bonzini | */
|
596 | 3653d8c4 | Paolo Bonzini | if (req->dev->sense_is_ua) {
|
597 | 3653d8c4 | Paolo Bonzini | if (req->dev->info->unit_attention_reported) {
|
598 | 3653d8c4 | Paolo Bonzini | req->dev->info->unit_attention_reported(req->dev); |
599 | 3653d8c4 | Paolo Bonzini | } |
600 | 3653d8c4 | Paolo Bonzini | req->dev->sense_len = 0;
|
601 | 3653d8c4 | Paolo Bonzini | req->dev->sense_is_ua = false;
|
602 | 3653d8c4 | Paolo Bonzini | } |
603 | 6dc06f08 | Paolo Bonzini | return ret;
|
604 | b45ef674 | Paolo Bonzini | } |
605 | b45ef674 | Paolo Bonzini | |
606 | b45ef674 | Paolo Bonzini | int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed) |
607 | b45ef674 | Paolo Bonzini | { |
608 | b45ef674 | Paolo Bonzini | return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed);
|
609 | b45ef674 | Paolo Bonzini | } |
610 | b45ef674 | Paolo Bonzini | |
611 | b45ef674 | Paolo Bonzini | void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
|
612 | b45ef674 | Paolo Bonzini | { |
613 | b45ef674 | Paolo Bonzini | trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag, |
614 | b45ef674 | Paolo Bonzini | sense.key, sense.asc, sense.ascq); |
615 | b45ef674 | Paolo Bonzini | memset(req->sense, 0, 18); |
616 | b45ef674 | Paolo Bonzini | req->sense[0] = 0xf0; |
617 | b45ef674 | Paolo Bonzini | req->sense[2] = sense.key;
|
618 | eae31cb9 | Paolo Bonzini | req->sense[7] = 10; |
619 | b45ef674 | Paolo Bonzini | req->sense[12] = sense.asc;
|
620 | b45ef674 | Paolo Bonzini | req->sense[13] = sense.ascq;
|
621 | b45ef674 | Paolo Bonzini | req->sense_len = 18;
|
622 | 74382217 | Hannes Reinecke | } |
623 | 74382217 | Hannes Reinecke | |
624 | c39ce112 | Paolo Bonzini | int32_t scsi_req_enqueue(SCSIRequest *req) |
625 | 89b08ae1 | Gerd Hoffmann | { |
626 | fc4f0754 | Paolo Bonzini | int32_t rc; |
627 | fc4f0754 | Paolo Bonzini | |
628 | 5c6c0e51 | Hannes Reinecke | assert(!req->enqueued); |
629 | 5c6c0e51 | Hannes Reinecke | scsi_req_ref(req); |
630 | 5c6c0e51 | Hannes Reinecke | req->enqueued = true;
|
631 | 5c6c0e51 | Hannes Reinecke | QTAILQ_INSERT_TAIL(&req->dev->requests, req, next); |
632 | fc4f0754 | Paolo Bonzini | |
633 | fc4f0754 | Paolo Bonzini | scsi_req_ref(req); |
634 | c39ce112 | Paolo Bonzini | rc = req->ops->send_command(req, req->cmd.buf); |
635 | fc4f0754 | Paolo Bonzini | scsi_req_unref(req); |
636 | fc4f0754 | Paolo Bonzini | return rc;
|
637 | 89b08ae1 | Gerd Hoffmann | } |
638 | 89b08ae1 | Gerd Hoffmann | |
639 | a1f0cce2 | Hannes Reinecke | static void scsi_req_dequeue(SCSIRequest *req) |
640 | e8637c90 | Jan Kiszka | { |
641 | 5138efec | Paolo Bonzini | trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag); |
642 | 71544d30 | Paolo Bonzini | req->retry = false;
|
643 | e8637c90 | Jan Kiszka | if (req->enqueued) {
|
644 | e8637c90 | Jan Kiszka | QTAILQ_REMOVE(&req->dev->requests, req, next); |
645 | e8637c90 | Jan Kiszka | req->enqueued = false;
|
646 | ad2d30f7 | Paolo Bonzini | scsi_req_unref(req); |
647 | e8637c90 | Jan Kiszka | } |
648 | e8637c90 | Jan Kiszka | } |
649 | e8637c90 | Jan Kiszka | |
650 | 06b86357 | Paolo Bonzini | static int scsi_get_performance_length(int num_desc, int type, int data_type) |
651 | 06b86357 | Paolo Bonzini | { |
652 | 06b86357 | Paolo Bonzini | /* MMC-6, paragraph 6.7. */
|
653 | 06b86357 | Paolo Bonzini | switch (type) {
|
654 | 06b86357 | Paolo Bonzini | case 0: |
655 | 06b86357 | Paolo Bonzini | if ((data_type & 3) == 0) { |
656 | 06b86357 | Paolo Bonzini | /* Each descriptor is as in Table 295 - Nominal performance. */
|
657 | 06b86357 | Paolo Bonzini | return 16 * num_desc + 8; |
658 | 06b86357 | Paolo Bonzini | } else {
|
659 | 06b86357 | Paolo Bonzini | /* Each descriptor is as in Table 296 - Exceptions. */
|
660 | 06b86357 | Paolo Bonzini | return 6 * num_desc + 8; |
661 | 06b86357 | Paolo Bonzini | } |
662 | 06b86357 | Paolo Bonzini | case 1: |
663 | 06b86357 | Paolo Bonzini | case 4: |
664 | 06b86357 | Paolo Bonzini | case 5: |
665 | 06b86357 | Paolo Bonzini | return 8 * num_desc + 8; |
666 | 06b86357 | Paolo Bonzini | case 2: |
667 | 06b86357 | Paolo Bonzini | return 2048 * num_desc + 8; |
668 | 06b86357 | Paolo Bonzini | case 3: |
669 | 06b86357 | Paolo Bonzini | return 16 * num_desc + 8; |
670 | 06b86357 | Paolo Bonzini | default:
|
671 | 06b86357 | Paolo Bonzini | return 8; |
672 | 06b86357 | Paolo Bonzini | } |
673 | 06b86357 | Paolo Bonzini | } |
674 | 06b86357 | Paolo Bonzini | |
675 | 2599aece | Paolo Bonzini | static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) |
676 | 2ec749cb | Gerd Hoffmann | { |
677 | 2599aece | Paolo Bonzini | switch (buf[0] >> 5) { |
678 | 2ec749cb | Gerd Hoffmann | case 0: |
679 | 2599aece | Paolo Bonzini | cmd->xfer = buf[4];
|
680 | 2599aece | Paolo Bonzini | cmd->len = 6;
|
681 | 2ec749cb | Gerd Hoffmann | /* length 0 means 256 blocks */
|
682 | 2599aece | Paolo Bonzini | if (cmd->xfer == 0) { |
683 | 2599aece | Paolo Bonzini | cmd->xfer = 256;
|
684 | 2599aece | Paolo Bonzini | } |
685 | 2ec749cb | Gerd Hoffmann | break;
|
686 | 2ec749cb | Gerd Hoffmann | case 1: |
687 | 2ec749cb | Gerd Hoffmann | case 2: |
688 | bd5da232 | Paolo Bonzini | cmd->xfer = lduw_be_p(&buf[7]);
|
689 | 2599aece | Paolo Bonzini | cmd->len = 10;
|
690 | 2ec749cb | Gerd Hoffmann | break;
|
691 | 2ec749cb | Gerd Hoffmann | case 4: |
692 | 06b86357 | Paolo Bonzini | cmd->xfer = ldl_be_p(&buf[10]) & 0xffffffffULL; |
693 | 2599aece | Paolo Bonzini | cmd->len = 16;
|
694 | 2ec749cb | Gerd Hoffmann | break;
|
695 | 2ec749cb | Gerd Hoffmann | case 5: |
696 | 06b86357 | Paolo Bonzini | cmd->xfer = ldl_be_p(&buf[6]) & 0xffffffffULL; |
697 | 2599aece | Paolo Bonzini | cmd->len = 12;
|
698 | 2ec749cb | Gerd Hoffmann | break;
|
699 | 2ec749cb | Gerd Hoffmann | default:
|
700 | 2ec749cb | Gerd Hoffmann | return -1; |
701 | 2ec749cb | Gerd Hoffmann | } |
702 | 2ec749cb | Gerd Hoffmann | |
703 | 2599aece | Paolo Bonzini | switch (buf[0]) { |
704 | 2ec749cb | Gerd Hoffmann | case TEST_UNIT_READY:
|
705 | 5e30a07d | Hannes Reinecke | case REWIND:
|
706 | 2ec749cb | Gerd Hoffmann | case START_STOP:
|
707 | 00a01ad4 | Paolo Bonzini | case SET_CAPACITY:
|
708 | 2ec749cb | Gerd Hoffmann | case WRITE_FILEMARKS:
|
709 | 06b86357 | Paolo Bonzini | case WRITE_FILEMARKS_16:
|
710 | 2ec749cb | Gerd Hoffmann | case SPACE:
|
711 | a5e3d9ef | Bernhard Kohl | case RESERVE:
|
712 | a5e3d9ef | Bernhard Kohl | case RELEASE:
|
713 | 2ec749cb | Gerd Hoffmann | case ERASE:
|
714 | 2ec749cb | Gerd Hoffmann | case ALLOW_MEDIUM_REMOVAL:
|
715 | 5e30a07d | Hannes Reinecke | case VERIFY_10:
|
716 | 2ec749cb | Gerd Hoffmann | case SEEK_10:
|
717 | 2ec749cb | Gerd Hoffmann | case SYNCHRONIZE_CACHE:
|
718 | 06b86357 | Paolo Bonzini | case SYNCHRONIZE_CACHE_16:
|
719 | 06b86357 | Paolo Bonzini | case LOCATE_16:
|
720 | 2ec749cb | Gerd Hoffmann | case LOCK_UNLOCK_CACHE:
|
721 | 2ec749cb | Gerd Hoffmann | case LOAD_UNLOAD:
|
722 | 2ec749cb | Gerd Hoffmann | case SET_CD_SPEED:
|
723 | 2ec749cb | Gerd Hoffmann | case SET_LIMITS:
|
724 | 5e30a07d | Hannes Reinecke | case WRITE_LONG_10:
|
725 | 2ec749cb | Gerd Hoffmann | case MOVE_MEDIUM:
|
726 | 2ec749cb | Gerd Hoffmann | case UPDATE_BLOCK:
|
727 | 06b86357 | Paolo Bonzini | case RESERVE_TRACK:
|
728 | 06b86357 | Paolo Bonzini | case SET_READ_AHEAD:
|
729 | 06b86357 | Paolo Bonzini | case PRE_FETCH:
|
730 | 06b86357 | Paolo Bonzini | case PRE_FETCH_16:
|
731 | 06b86357 | Paolo Bonzini | case ALLOW_OVERWRITE:
|
732 | 2599aece | Paolo Bonzini | cmd->xfer = 0;
|
733 | 2ec749cb | Gerd Hoffmann | break;
|
734 | 2ec749cb | Gerd Hoffmann | case MODE_SENSE:
|
735 | 2ec749cb | Gerd Hoffmann | break;
|
736 | 5e30a07d | Hannes Reinecke | case WRITE_SAME_10:
|
737 | 2599aece | Paolo Bonzini | cmd->xfer = 1;
|
738 | 2ec749cb | Gerd Hoffmann | break;
|
739 | 5e30a07d | Hannes Reinecke | case READ_CAPACITY_10:
|
740 | 2599aece | Paolo Bonzini | cmd->xfer = 8;
|
741 | 2ec749cb | Gerd Hoffmann | break;
|
742 | 2ec749cb | Gerd Hoffmann | case READ_BLOCK_LIMITS:
|
743 | 2599aece | Paolo Bonzini | cmd->xfer = 6;
|
744 | 2ec749cb | Gerd Hoffmann | break;
|
745 | 2ec749cb | Gerd Hoffmann | case SEND_VOLUME_TAG:
|
746 | 06b86357 | Paolo Bonzini | /* GPCMD_SET_STREAMING from multimedia commands. */
|
747 | 06b86357 | Paolo Bonzini | if (dev->type == TYPE_ROM) {
|
748 | 06b86357 | Paolo Bonzini | cmd->xfer = buf[10] | (buf[9] << 8); |
749 | 06b86357 | Paolo Bonzini | } else {
|
750 | 06b86357 | Paolo Bonzini | cmd->xfer = buf[9] | (buf[8] << 8); |
751 | 06b86357 | Paolo Bonzini | } |
752 | 2ec749cb | Gerd Hoffmann | break;
|
753 | 2ec749cb | Gerd Hoffmann | case WRITE_10:
|
754 | 5e30a07d | Hannes Reinecke | case WRITE_VERIFY_10:
|
755 | 2ec749cb | Gerd Hoffmann | case WRITE_6:
|
756 | 2ec749cb | Gerd Hoffmann | case WRITE_12:
|
757 | 2ec749cb | Gerd Hoffmann | case WRITE_VERIFY_12:
|
758 | bd536cf3 | Gerd Hoffmann | case WRITE_16:
|
759 | bd536cf3 | Gerd Hoffmann | case WRITE_VERIFY_16:
|
760 | 2599aece | Paolo Bonzini | cmd->xfer *= dev->blocksize; |
761 | 2ec749cb | Gerd Hoffmann | break;
|
762 | 2ec749cb | Gerd Hoffmann | case READ_10:
|
763 | 2ec749cb | Gerd Hoffmann | case READ_6:
|
764 | 2ec749cb | Gerd Hoffmann | case READ_REVERSE:
|
765 | 2ec749cb | Gerd Hoffmann | case RECOVER_BUFFERED_DATA:
|
766 | 2ec749cb | Gerd Hoffmann | case READ_12:
|
767 | bd536cf3 | Gerd Hoffmann | case READ_16:
|
768 | 2599aece | Paolo Bonzini | cmd->xfer *= dev->blocksize; |
769 | 2ec749cb | Gerd Hoffmann | break;
|
770 | 06b86357 | Paolo Bonzini | case FORMAT_UNIT:
|
771 | 06b86357 | Paolo Bonzini | /* MMC mandates the parameter list to be 12-bytes long. Parameters
|
772 | 06b86357 | Paolo Bonzini | * for block devices are restricted to the header right now. */
|
773 | 06b86357 | Paolo Bonzini | if (dev->type == TYPE_ROM && (buf[1] & 16)) { |
774 | 06b86357 | Paolo Bonzini | cmd->xfer = 12;
|
775 | 06b86357 | Paolo Bonzini | } else {
|
776 | 06b86357 | Paolo Bonzini | cmd->xfer = (buf[1] & 16) == 0 ? 0 : (buf[1] & 32 ? 8 : 4); |
777 | 06b86357 | Paolo Bonzini | } |
778 | 06b86357 | Paolo Bonzini | break;
|
779 | 2ec749cb | Gerd Hoffmann | case INQUIRY:
|
780 | 06b86357 | Paolo Bonzini | case RECEIVE_DIAGNOSTIC:
|
781 | 06b86357 | Paolo Bonzini | case SEND_DIAGNOSTIC:
|
782 | 2599aece | Paolo Bonzini | cmd->xfer = buf[4] | (buf[3] << 8); |
783 | 2ec749cb | Gerd Hoffmann | break;
|
784 | 06b86357 | Paolo Bonzini | case READ_CD:
|
785 | 06b86357 | Paolo Bonzini | case READ_BUFFER:
|
786 | 06b86357 | Paolo Bonzini | case WRITE_BUFFER:
|
787 | 06b86357 | Paolo Bonzini | case SEND_CUE_SHEET:
|
788 | 06b86357 | Paolo Bonzini | cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16); |
789 | 06b86357 | Paolo Bonzini | break;
|
790 | 06b86357 | Paolo Bonzini | case PERSISTENT_RESERVE_OUT:
|
791 | 06b86357 | Paolo Bonzini | cmd->xfer = ldl_be_p(&buf[5]) & 0xffffffffULL; |
792 | 06b86357 | Paolo Bonzini | break;
|
793 | 06b86357 | Paolo Bonzini | case ERASE_12:
|
794 | 06b86357 | Paolo Bonzini | if (dev->type == TYPE_ROM) {
|
795 | 06b86357 | Paolo Bonzini | /* MMC command GET PERFORMANCE. */
|
796 | 06b86357 | Paolo Bonzini | cmd->xfer = scsi_get_performance_length(buf[9] | (buf[8] << 8), |
797 | 06b86357 | Paolo Bonzini | buf[10], buf[1] & 0x1f); |
798 | 06b86357 | Paolo Bonzini | } |
799 | 06b86357 | Paolo Bonzini | break;
|
800 | 06b86357 | Paolo Bonzini | case MECHANISM_STATUS:
|
801 | 06b86357 | Paolo Bonzini | case READ_DVD_STRUCTURE:
|
802 | 06b86357 | Paolo Bonzini | case SEND_DVD_STRUCTURE:
|
803 | c7126d5b | Nicholas Bellinger | case MAINTENANCE_OUT:
|
804 | c7126d5b | Nicholas Bellinger | case MAINTENANCE_IN:
|
805 | 2599aece | Paolo Bonzini | if (dev->type == TYPE_ROM) {
|
806 | c7126d5b | Nicholas Bellinger | /* GPCMD_REPORT_KEY and GPCMD_SEND_KEY from multi media commands */
|
807 | 2599aece | Paolo Bonzini | cmd->xfer = buf[9] | (buf[8] << 8); |
808 | c7126d5b | Nicholas Bellinger | } |
809 | c7126d5b | Nicholas Bellinger | break;
|
810 | 2ec749cb | Gerd Hoffmann | } |
811 | 2ec749cb | Gerd Hoffmann | return 0; |
812 | 2ec749cb | Gerd Hoffmann | } |
813 | 2ec749cb | Gerd Hoffmann | |
814 | 2599aece | Paolo Bonzini | static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) |
815 | 2ec749cb | Gerd Hoffmann | { |
816 | 2599aece | Paolo Bonzini | switch (buf[0]) { |
817 | 2ec749cb | Gerd Hoffmann | /* stream commands */
|
818 | 06b86357 | Paolo Bonzini | case ERASE_12:
|
819 | 06b86357 | Paolo Bonzini | case ERASE_16:
|
820 | 06b86357 | Paolo Bonzini | cmd->xfer = 0;
|
821 | 06b86357 | Paolo Bonzini | break;
|
822 | 2ec749cb | Gerd Hoffmann | case READ_6:
|
823 | 2ec749cb | Gerd Hoffmann | case READ_REVERSE:
|
824 | 2ec749cb | Gerd Hoffmann | case RECOVER_BUFFERED_DATA:
|
825 | 2ec749cb | Gerd Hoffmann | case WRITE_6:
|
826 | 2599aece | Paolo Bonzini | cmd->len = 6;
|
827 | 2599aece | Paolo Bonzini | cmd->xfer = buf[4] | (buf[3] << 8) | (buf[2] << 16); |
828 | 2599aece | Paolo Bonzini | if (buf[1] & 0x01) { /* fixed */ |
829 | 2599aece | Paolo Bonzini | cmd->xfer *= dev->blocksize; |
830 | 2599aece | Paolo Bonzini | } |
831 | 2ec749cb | Gerd Hoffmann | break;
|
832 | 2ec749cb | Gerd Hoffmann | case REWIND:
|
833 | 2ec749cb | Gerd Hoffmann | case START_STOP:
|
834 | 2599aece | Paolo Bonzini | cmd->len = 6;
|
835 | 2599aece | Paolo Bonzini | cmd->xfer = 0;
|
836 | 2ec749cb | Gerd Hoffmann | break;
|
837 | 06b86357 | Paolo Bonzini | case SPACE_16:
|
838 | 06b86357 | Paolo Bonzini | cmd->xfer = buf[13] | (buf[12] << 8); |
839 | 06b86357 | Paolo Bonzini | break;
|
840 | 06b86357 | Paolo Bonzini | case READ_POSITION:
|
841 | 06b86357 | Paolo Bonzini | cmd->xfer = buf[8] | (buf[7] << 8); |
842 | 06b86357 | Paolo Bonzini | break;
|
843 | 06b86357 | Paolo Bonzini | case FORMAT_UNIT:
|
844 | 06b86357 | Paolo Bonzini | cmd->xfer = buf[4] | (buf[3] << 8); |
845 | 06b86357 | Paolo Bonzini | break;
|
846 | 2ec749cb | Gerd Hoffmann | /* generic commands */
|
847 | 2ec749cb | Gerd Hoffmann | default:
|
848 | 2599aece | Paolo Bonzini | return scsi_req_length(cmd, dev, buf);
|
849 | 2ec749cb | Gerd Hoffmann | } |
850 | 2ec749cb | Gerd Hoffmann | return 0; |
851 | 2ec749cb | Gerd Hoffmann | } |
852 | 2ec749cb | Gerd Hoffmann | |
853 | 2599aece | Paolo Bonzini | static void scsi_cmd_xfer_mode(SCSICommand *cmd) |
854 | 97a06435 | Gerd Hoffmann | { |
855 | 2599aece | Paolo Bonzini | switch (cmd->buf[0]) { |
856 | 97a06435 | Gerd Hoffmann | case WRITE_6:
|
857 | 97a06435 | Gerd Hoffmann | case WRITE_10:
|
858 | 5e30a07d | Hannes Reinecke | case WRITE_VERIFY_10:
|
859 | 97a06435 | Gerd Hoffmann | case WRITE_12:
|
860 | 97a06435 | Gerd Hoffmann | case WRITE_VERIFY_12:
|
861 | bd536cf3 | Gerd Hoffmann | case WRITE_16:
|
862 | bd536cf3 | Gerd Hoffmann | case WRITE_VERIFY_16:
|
863 | 97a06435 | Gerd Hoffmann | case COPY:
|
864 | 97a06435 | Gerd Hoffmann | case COPY_VERIFY:
|
865 | 97a06435 | Gerd Hoffmann | case COMPARE:
|
866 | 97a06435 | Gerd Hoffmann | case CHANGE_DEFINITION:
|
867 | 97a06435 | Gerd Hoffmann | case LOG_SELECT:
|
868 | 97a06435 | Gerd Hoffmann | case MODE_SELECT:
|
869 | 97a06435 | Gerd Hoffmann | case MODE_SELECT_10:
|
870 | 97a06435 | Gerd Hoffmann | case SEND_DIAGNOSTIC:
|
871 | 97a06435 | Gerd Hoffmann | case WRITE_BUFFER:
|
872 | 97a06435 | Gerd Hoffmann | case FORMAT_UNIT:
|
873 | 97a06435 | Gerd Hoffmann | case REASSIGN_BLOCKS:
|
874 | 97a06435 | Gerd Hoffmann | case SEARCH_EQUAL:
|
875 | 97a06435 | Gerd Hoffmann | case SEARCH_HIGH:
|
876 | 97a06435 | Gerd Hoffmann | case SEARCH_LOW:
|
877 | 97a06435 | Gerd Hoffmann | case UPDATE_BLOCK:
|
878 | 5e30a07d | Hannes Reinecke | case WRITE_LONG_10:
|
879 | 5e30a07d | Hannes Reinecke | case WRITE_SAME_10:
|
880 | 97a06435 | Gerd Hoffmann | case SEARCH_HIGH_12:
|
881 | 97a06435 | Gerd Hoffmann | case SEARCH_EQUAL_12:
|
882 | 97a06435 | Gerd Hoffmann | case SEARCH_LOW_12:
|
883 | 97a06435 | Gerd Hoffmann | case MEDIUM_SCAN:
|
884 | 97a06435 | Gerd Hoffmann | case SEND_VOLUME_TAG:
|
885 | 06b86357 | Paolo Bonzini | case SEND_CUE_SHEET:
|
886 | 06b86357 | Paolo Bonzini | case SEND_DVD_STRUCTURE:
|
887 | 01bedeba | Nicholas Bellinger | case PERSISTENT_RESERVE_OUT:
|
888 | c7126d5b | Nicholas Bellinger | case MAINTENANCE_OUT:
|
889 | 2599aece | Paolo Bonzini | cmd->mode = SCSI_XFER_TO_DEV; |
890 | 97a06435 | Gerd Hoffmann | break;
|
891 | 97a06435 | Gerd Hoffmann | default:
|
892 | 2599aece | Paolo Bonzini | if (cmd->xfer)
|
893 | 2599aece | Paolo Bonzini | cmd->mode = SCSI_XFER_FROM_DEV; |
894 | 97a06435 | Gerd Hoffmann | else {
|
895 | 2599aece | Paolo Bonzini | cmd->mode = SCSI_XFER_NONE; |
896 | 97a06435 | Gerd Hoffmann | } |
897 | 97a06435 | Gerd Hoffmann | break;
|
898 | 97a06435 | Gerd Hoffmann | } |
899 | 97a06435 | Gerd Hoffmann | } |
900 | 97a06435 | Gerd Hoffmann | |
901 | 2599aece | Paolo Bonzini | static uint64_t scsi_cmd_lba(SCSICommand *cmd)
|
902 | 2ec749cb | Gerd Hoffmann | { |
903 | 2599aece | Paolo Bonzini | uint8_t *buf = cmd->buf; |
904 | 2ec749cb | Gerd Hoffmann | uint64_t lba; |
905 | 2ec749cb | Gerd Hoffmann | |
906 | 2ec749cb | Gerd Hoffmann | switch (buf[0] >> 5) { |
907 | 2ec749cb | Gerd Hoffmann | case 0: |
908 | bd5da232 | Paolo Bonzini | lba = ldl_be_p(&buf[0]) & 0x1fffff; |
909 | 2ec749cb | Gerd Hoffmann | break;
|
910 | 2ec749cb | Gerd Hoffmann | case 1: |
911 | 2ec749cb | Gerd Hoffmann | case 2: |
912 | bd5da232 | Paolo Bonzini | case 5: |
913 | 06b86357 | Paolo Bonzini | lba = ldl_be_p(&buf[2]) & 0xffffffffULL; |
914 | 2ec749cb | Gerd Hoffmann | break;
|
915 | 2ec749cb | Gerd Hoffmann | case 4: |
916 | bd5da232 | Paolo Bonzini | lba = ldq_be_p(&buf[2]);
|
917 | 2ec749cb | Gerd Hoffmann | break;
|
918 | 2ec749cb | Gerd Hoffmann | default:
|
919 | 2ec749cb | Gerd Hoffmann | lba = -1;
|
920 | 2ec749cb | Gerd Hoffmann | |
921 | 2ec749cb | Gerd Hoffmann | } |
922 | 2ec749cb | Gerd Hoffmann | return lba;
|
923 | 2ec749cb | Gerd Hoffmann | } |
924 | 2ec749cb | Gerd Hoffmann | |
925 | afa46c46 | Paolo Bonzini | int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
926 | 2ec749cb | Gerd Hoffmann | { |
927 | 2ec749cb | Gerd Hoffmann | int rc;
|
928 | 2ec749cb | Gerd Hoffmann | |
929 | afa46c46 | Paolo Bonzini | if (dev->type == TYPE_TAPE) {
|
930 | afa46c46 | Paolo Bonzini | rc = scsi_req_stream_length(cmd, dev, buf); |
931 | 2ec749cb | Gerd Hoffmann | } else {
|
932 | afa46c46 | Paolo Bonzini | rc = scsi_req_length(cmd, dev, buf); |
933 | 2ec749cb | Gerd Hoffmann | } |
934 | 2ec749cb | Gerd Hoffmann | if (rc != 0) |
935 | 2ec749cb | Gerd Hoffmann | return rc;
|
936 | 2ec749cb | Gerd Hoffmann | |
937 | afa46c46 | Paolo Bonzini | memcpy(cmd->buf, buf, cmd->len); |
938 | afa46c46 | Paolo Bonzini | scsi_cmd_xfer_mode(cmd); |
939 | afa46c46 | Paolo Bonzini | cmd->lba = scsi_cmd_lba(cmd); |
940 | 2ec749cb | Gerd Hoffmann | return 0; |
941 | 2ec749cb | Gerd Hoffmann | } |
942 | ed3a34a3 | Gerd Hoffmann | |
943 | a1f0cce2 | Hannes Reinecke | /*
|
944 | a1f0cce2 | Hannes Reinecke | * Predefined sense codes
|
945 | a1f0cce2 | Hannes Reinecke | */
|
946 | a1f0cce2 | Hannes Reinecke | |
947 | a1f0cce2 | Hannes Reinecke | /* No sense data available */
|
948 | a1f0cce2 | Hannes Reinecke | const struct SCSISense sense_code_NO_SENSE = { |
949 | a1f0cce2 | Hannes Reinecke | .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00 |
950 | a1f0cce2 | Hannes Reinecke | }; |
951 | a1f0cce2 | Hannes Reinecke | |
952 | a1f0cce2 | Hannes Reinecke | /* LUN not ready, Manual intervention required */
|
953 | a1f0cce2 | Hannes Reinecke | const struct SCSISense sense_code_LUN_NOT_READY = { |
954 | a1f0cce2 | Hannes Reinecke | .key = NOT_READY, .asc = 0x04, .ascq = 0x03 |
955 | a1f0cce2 | Hannes Reinecke | }; |
956 | a1f0cce2 | Hannes Reinecke | |
957 | a1f0cce2 | Hannes Reinecke | /* LUN not ready, Medium not present */
|
958 | a1f0cce2 | Hannes Reinecke | const struct SCSISense sense_code_NO_MEDIUM = { |
959 | a1f0cce2 | Hannes Reinecke | .key = NOT_READY, .asc = 0x3a, .ascq = 0x00 |
960 | a1f0cce2 | Hannes Reinecke | }; |
961 | a1f0cce2 | Hannes Reinecke | |
962 | 68bb01f3 | Markus Armbruster | /* LUN not ready, medium removal prevented */
|
963 | 68bb01f3 | Markus Armbruster | const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = { |
964 | 68bb01f3 | Markus Armbruster | .key = NOT_READY, .asc = 0x53, .ascq = 0x00 |
965 | 68bb01f3 | Markus Armbruster | }; |
966 | 68bb01f3 | Markus Armbruster | |
967 | a1f0cce2 | Hannes Reinecke | /* Hardware error, internal target failure */
|
968 | a1f0cce2 | Hannes Reinecke | const struct SCSISense sense_code_TARGET_FAILURE = { |
969 | a1f0cce2 | Hannes Reinecke | .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00 |
970 | a1f0cce2 | Hannes Reinecke | }; |
971 | a1f0cce2 | Hannes Reinecke | |
972 | a1f0cce2 | Hannes Reinecke | /* Illegal request, invalid command operation code */
|
973 | a1f0cce2 | Hannes Reinecke | const struct SCSISense sense_code_INVALID_OPCODE = { |
974 | a1f0cce2 | Hannes Reinecke | .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00 |
975 | a1f0cce2 | Hannes Reinecke | }; |
976 | a1f0cce2 | Hannes Reinecke | |
977 | a1f0cce2 | Hannes Reinecke | /* Illegal request, LBA out of range */
|
978 | a1f0cce2 | Hannes Reinecke | const struct SCSISense sense_code_LBA_OUT_OF_RANGE = { |
979 | a1f0cce2 | Hannes Reinecke | .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00 |
980 | a1f0cce2 | Hannes Reinecke | }; |
981 | a1f0cce2 | Hannes Reinecke | |
982 | a1f0cce2 | Hannes Reinecke | /* Illegal request, Invalid field in CDB */
|
983 | a1f0cce2 | Hannes Reinecke | const struct SCSISense sense_code_INVALID_FIELD = { |
984 | a1f0cce2 | Hannes Reinecke | .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00 |
985 | a1f0cce2 | Hannes Reinecke | }; |
986 | a1f0cce2 | Hannes Reinecke | |
987 | a1f0cce2 | Hannes Reinecke | /* Illegal request, LUN not supported */
|
988 | a1f0cce2 | Hannes Reinecke | const struct SCSISense sense_code_LUN_NOT_SUPPORTED = { |
989 | a1f0cce2 | Hannes Reinecke | .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00 |
990 | a1f0cce2 | Hannes Reinecke | }; |
991 | a1f0cce2 | Hannes Reinecke | |
992 | a872a304 | Paolo Bonzini | /* Illegal request, Saving parameters not supported */
|
993 | a872a304 | Paolo Bonzini | const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = { |
994 | a872a304 | Paolo Bonzini | .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00 |
995 | a872a304 | Paolo Bonzini | }; |
996 | a872a304 | Paolo Bonzini | |
997 | a872a304 | Paolo Bonzini | /* Illegal request, Incompatible medium installed */
|
998 | 67cc61e4 | Paolo Bonzini | const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = { |
999 | a872a304 | Paolo Bonzini | .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00 |
1000 | a872a304 | Paolo Bonzini | }; |
1001 | a872a304 | Paolo Bonzini | |
1002 | 68bb01f3 | Markus Armbruster | /* Illegal request, medium removal prevented */
|
1003 | 68bb01f3 | Markus Armbruster | const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = { |
1004 | 68bb01f3 | Markus Armbruster | .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x00 |
1005 | 68bb01f3 | Markus Armbruster | }; |
1006 | 68bb01f3 | Markus Armbruster | |
1007 | a1f0cce2 | Hannes Reinecke | /* Command aborted, I/O process terminated */
|
1008 | a1f0cce2 | Hannes Reinecke | const struct SCSISense sense_code_IO_ERROR = { |
1009 | a1f0cce2 | Hannes Reinecke | .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06 |
1010 | a1f0cce2 | Hannes Reinecke | }; |
1011 | a1f0cce2 | Hannes Reinecke | |
1012 | a1f0cce2 | Hannes Reinecke | /* Command aborted, I_T Nexus loss occurred */
|
1013 | a1f0cce2 | Hannes Reinecke | const struct SCSISense sense_code_I_T_NEXUS_LOSS = { |
1014 | a1f0cce2 | Hannes Reinecke | .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07 |
1015 | a1f0cce2 | Hannes Reinecke | }; |
1016 | a1f0cce2 | Hannes Reinecke | |
1017 | a1f0cce2 | Hannes Reinecke | /* Command aborted, Logical Unit failure */
|
1018 | a1f0cce2 | Hannes Reinecke | const struct SCSISense sense_code_LUN_FAILURE = { |
1019 | a1f0cce2 | Hannes Reinecke | .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01 |
1020 | a1f0cce2 | Hannes Reinecke | }; |
1021 | a1f0cce2 | Hannes Reinecke | |
1022 | a872a304 | Paolo Bonzini | /* Unit attention, Power on, reset or bus device reset occurred */
|
1023 | a872a304 | Paolo Bonzini | const struct SCSISense sense_code_RESET = { |
1024 | a872a304 | Paolo Bonzini | .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00 |
1025 | a872a304 | Paolo Bonzini | }; |
1026 | a872a304 | Paolo Bonzini | |
1027 | 8a9c16f6 | Paolo Bonzini | /* Unit attention, No medium */
|
1028 | 8a9c16f6 | Paolo Bonzini | const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = { |
1029 | 8a9c16f6 | Paolo Bonzini | .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00 |
1030 | 8a9c16f6 | Paolo Bonzini | }; |
1031 | 8a9c16f6 | Paolo Bonzini | |
1032 | a872a304 | Paolo Bonzini | /* Unit attention, Medium may have changed */
|
1033 | a872a304 | Paolo Bonzini | const struct SCSISense sense_code_MEDIUM_CHANGED = { |
1034 | a872a304 | Paolo Bonzini | .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00 |
1035 | a872a304 | Paolo Bonzini | }; |
1036 | a872a304 | Paolo Bonzini | |
1037 | a872a304 | Paolo Bonzini | /* Unit attention, Reported LUNs data has changed */
|
1038 | a872a304 | Paolo Bonzini | const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = { |
1039 | a872a304 | Paolo Bonzini | .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e |
1040 | a872a304 | Paolo Bonzini | }; |
1041 | a872a304 | Paolo Bonzini | |
1042 | a872a304 | Paolo Bonzini | /* Unit attention, Device internal reset */
|
1043 | a872a304 | Paolo Bonzini | const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = { |
1044 | a872a304 | Paolo Bonzini | .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04 |
1045 | a872a304 | Paolo Bonzini | }; |
1046 | a872a304 | Paolo Bonzini | |
1047 | a1f0cce2 | Hannes Reinecke | /*
|
1048 | a1f0cce2 | Hannes Reinecke | * scsi_build_sense
|
1049 | a1f0cce2 | Hannes Reinecke | *
|
1050 | b45ef674 | Paolo Bonzini | * Convert between fixed and descriptor sense buffers
|
1051 | a1f0cce2 | Hannes Reinecke | */
|
1052 | b45ef674 | Paolo Bonzini | int scsi_build_sense(uint8_t *in_buf, int in_len, |
1053 | b45ef674 | Paolo Bonzini | uint8_t *buf, int len, bool fixed) |
1054 | a1f0cce2 | Hannes Reinecke | { |
1055 | b45ef674 | Paolo Bonzini | bool fixed_in;
|
1056 | b45ef674 | Paolo Bonzini | SCSISense sense; |
1057 | a1f0cce2 | Hannes Reinecke | if (!fixed && len < 8) { |
1058 | a1f0cce2 | Hannes Reinecke | return 0; |
1059 | a1f0cce2 | Hannes Reinecke | } |
1060 | a1f0cce2 | Hannes Reinecke | |
1061 | b45ef674 | Paolo Bonzini | if (in_len == 0) { |
1062 | b45ef674 | Paolo Bonzini | sense.key = NO_SENSE; |
1063 | b45ef674 | Paolo Bonzini | sense.asc = 0;
|
1064 | b45ef674 | Paolo Bonzini | sense.ascq = 0;
|
1065 | b45ef674 | Paolo Bonzini | } else {
|
1066 | b45ef674 | Paolo Bonzini | fixed_in = (in_buf[0] & 2) == 0; |
1067 | b45ef674 | Paolo Bonzini | |
1068 | b45ef674 | Paolo Bonzini | if (fixed == fixed_in) {
|
1069 | b45ef674 | Paolo Bonzini | memcpy(buf, in_buf, MIN(len, in_len)); |
1070 | b45ef674 | Paolo Bonzini | return MIN(len, in_len);
|
1071 | b45ef674 | Paolo Bonzini | } |
1072 | b45ef674 | Paolo Bonzini | |
1073 | b45ef674 | Paolo Bonzini | if (fixed_in) {
|
1074 | b45ef674 | Paolo Bonzini | sense.key = in_buf[2];
|
1075 | b45ef674 | Paolo Bonzini | sense.asc = in_buf[12];
|
1076 | b45ef674 | Paolo Bonzini | sense.ascq = in_buf[13];
|
1077 | b45ef674 | Paolo Bonzini | } else {
|
1078 | b45ef674 | Paolo Bonzini | sense.key = in_buf[1];
|
1079 | b45ef674 | Paolo Bonzini | sense.asc = in_buf[2];
|
1080 | b45ef674 | Paolo Bonzini | sense.ascq = in_buf[3];
|
1081 | b45ef674 | Paolo Bonzini | } |
1082 | b45ef674 | Paolo Bonzini | } |
1083 | b45ef674 | Paolo Bonzini | |
1084 | a1f0cce2 | Hannes Reinecke | memset(buf, 0, len);
|
1085 | a1f0cce2 | Hannes Reinecke | if (fixed) {
|
1086 | a1f0cce2 | Hannes Reinecke | /* Return fixed format sense buffer */
|
1087 | a1f0cce2 | Hannes Reinecke | buf[0] = 0xf0; |
1088 | a1f0cce2 | Hannes Reinecke | buf[2] = sense.key;
|
1089 | eae31cb9 | Paolo Bonzini | buf[7] = 10; |
1090 | a1f0cce2 | Hannes Reinecke | buf[12] = sense.asc;
|
1091 | a1f0cce2 | Hannes Reinecke | buf[13] = sense.ascq;
|
1092 | a1f0cce2 | Hannes Reinecke | return MIN(len, 18); |
1093 | a1f0cce2 | Hannes Reinecke | } else {
|
1094 | a1f0cce2 | Hannes Reinecke | /* Return descriptor format sense buffer */
|
1095 | a1f0cce2 | Hannes Reinecke | buf[0] = 0x72; |
1096 | a1f0cce2 | Hannes Reinecke | buf[1] = sense.key;
|
1097 | a1f0cce2 | Hannes Reinecke | buf[2] = sense.asc;
|
1098 | a1f0cce2 | Hannes Reinecke | buf[3] = sense.ascq;
|
1099 | a1f0cce2 | Hannes Reinecke | return 8; |
1100 | a1f0cce2 | Hannes Reinecke | } |
1101 | a1f0cce2 | Hannes Reinecke | } |
1102 | a1f0cce2 | Hannes Reinecke | |
1103 | ec766865 | Gerd Hoffmann | static const char *scsi_command_name(uint8_t cmd) |
1104 | ec766865 | Gerd Hoffmann | { |
1105 | ec766865 | Gerd Hoffmann | static const char *names[] = { |
1106 | ec766865 | Gerd Hoffmann | [ TEST_UNIT_READY ] = "TEST_UNIT_READY",
|
1107 | 5e30a07d | Hannes Reinecke | [ REWIND ] = "REWIND",
|
1108 | ec766865 | Gerd Hoffmann | [ REQUEST_SENSE ] = "REQUEST_SENSE",
|
1109 | ec766865 | Gerd Hoffmann | [ FORMAT_UNIT ] = "FORMAT_UNIT",
|
1110 | ec766865 | Gerd Hoffmann | [ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS",
|
1111 | ec766865 | Gerd Hoffmann | [ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS",
|
1112 | ec766865 | Gerd Hoffmann | [ READ_6 ] = "READ_6",
|
1113 | ec766865 | Gerd Hoffmann | [ WRITE_6 ] = "WRITE_6",
|
1114 | 00a01ad4 | Paolo Bonzini | [ SET_CAPACITY ] = "SET_CAPACITY",
|
1115 | ec766865 | Gerd Hoffmann | [ READ_REVERSE ] = "READ_REVERSE",
|
1116 | ec766865 | Gerd Hoffmann | [ WRITE_FILEMARKS ] = "WRITE_FILEMARKS",
|
1117 | ec766865 | Gerd Hoffmann | [ SPACE ] = "SPACE",
|
1118 | ec766865 | Gerd Hoffmann | [ INQUIRY ] = "INQUIRY",
|
1119 | ec766865 | Gerd Hoffmann | [ RECOVER_BUFFERED_DATA ] = "RECOVER_BUFFERED_DATA",
|
1120 | c7126d5b | Nicholas Bellinger | [ MAINTENANCE_IN ] = "MAINTENANCE_IN",
|
1121 | c7126d5b | Nicholas Bellinger | [ MAINTENANCE_OUT ] = "MAINTENANCE_OUT",
|
1122 | ec766865 | Gerd Hoffmann | [ MODE_SELECT ] = "MODE_SELECT",
|
1123 | ec766865 | Gerd Hoffmann | [ RESERVE ] = "RESERVE",
|
1124 | ec766865 | Gerd Hoffmann | [ RELEASE ] = "RELEASE",
|
1125 | ec766865 | Gerd Hoffmann | [ COPY ] = "COPY",
|
1126 | ec766865 | Gerd Hoffmann | [ ERASE ] = "ERASE",
|
1127 | ec766865 | Gerd Hoffmann | [ MODE_SENSE ] = "MODE_SENSE",
|
1128 | ec766865 | Gerd Hoffmann | [ START_STOP ] = "START_STOP",
|
1129 | ec766865 | Gerd Hoffmann | [ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC",
|
1130 | ec766865 | Gerd Hoffmann | [ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC",
|
1131 | ec766865 | Gerd Hoffmann | [ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL",
|
1132 | 5e30a07d | Hannes Reinecke | [ READ_CAPACITY_10 ] = "READ_CAPACITY_10",
|
1133 | ec766865 | Gerd Hoffmann | [ READ_10 ] = "READ_10",
|
1134 | ec766865 | Gerd Hoffmann | [ WRITE_10 ] = "WRITE_10",
|
1135 | ec766865 | Gerd Hoffmann | [ SEEK_10 ] = "SEEK_10",
|
1136 | 5e30a07d | Hannes Reinecke | [ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10",
|
1137 | 5e30a07d | Hannes Reinecke | [ VERIFY_10 ] = "VERIFY_10",
|
1138 | ec766865 | Gerd Hoffmann | [ SEARCH_HIGH ] = "SEARCH_HIGH",
|
1139 | ec766865 | Gerd Hoffmann | [ SEARCH_EQUAL ] = "SEARCH_EQUAL",
|
1140 | ec766865 | Gerd Hoffmann | [ SEARCH_LOW ] = "SEARCH_LOW",
|
1141 | ec766865 | Gerd Hoffmann | [ SET_LIMITS ] = "SET_LIMITS",
|
1142 | 00a01ad4 | Paolo Bonzini | [ PRE_FETCH ] = "PRE_FETCH/READ_POSITION",
|
1143 | 545557d4 | Blue Swirl | /* READ_POSITION and PRE_FETCH use the same operation code */
|
1144 | ec766865 | Gerd Hoffmann | [ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE",
|
1145 | ec766865 | Gerd Hoffmann | [ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE",
|
1146 | ec766865 | Gerd Hoffmann | [ READ_DEFECT_DATA ] = "READ_DEFECT_DATA",
|
1147 | ec766865 | Gerd Hoffmann | [ MEDIUM_SCAN ] = "MEDIUM_SCAN",
|
1148 | ec766865 | Gerd Hoffmann | [ COMPARE ] = "COMPARE",
|
1149 | ec766865 | Gerd Hoffmann | [ COPY_VERIFY ] = "COPY_VERIFY",
|
1150 | ec766865 | Gerd Hoffmann | [ WRITE_BUFFER ] = "WRITE_BUFFER",
|
1151 | ec766865 | Gerd Hoffmann | [ READ_BUFFER ] = "READ_BUFFER",
|
1152 | ec766865 | Gerd Hoffmann | [ UPDATE_BLOCK ] = "UPDATE_BLOCK",
|
1153 | 5e30a07d | Hannes Reinecke | [ READ_LONG_10 ] = "READ_LONG_10",
|
1154 | 5e30a07d | Hannes Reinecke | [ WRITE_LONG_10 ] = "WRITE_LONG_10",
|
1155 | ec766865 | Gerd Hoffmann | [ CHANGE_DEFINITION ] = "CHANGE_DEFINITION",
|
1156 | 5e30a07d | Hannes Reinecke | [ WRITE_SAME_10 ] = "WRITE_SAME_10",
|
1157 | 5e30a07d | Hannes Reinecke | [ UNMAP ] = "UNMAP",
|
1158 | ec766865 | Gerd Hoffmann | [ READ_TOC ] = "READ_TOC",
|
1159 | 5e30a07d | Hannes Reinecke | [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT",
|
1160 | 5e30a07d | Hannes Reinecke | [ GET_CONFIGURATION ] = "GET_CONFIGURATION",
|
1161 | ec766865 | Gerd Hoffmann | [ LOG_SELECT ] = "LOG_SELECT",
|
1162 | ec766865 | Gerd Hoffmann | [ LOG_SENSE ] = "LOG_SENSE",
|
1163 | ec766865 | Gerd Hoffmann | [ MODE_SELECT_10 ] = "MODE_SELECT_10",
|
1164 | ec766865 | Gerd Hoffmann | [ RESERVE_10 ] = "RESERVE_10",
|
1165 | ec766865 | Gerd Hoffmann | [ RELEASE_10 ] = "RELEASE_10",
|
1166 | ec766865 | Gerd Hoffmann | [ MODE_SENSE_10 ] = "MODE_SENSE_10",
|
1167 | ec766865 | Gerd Hoffmann | [ PERSISTENT_RESERVE_IN ] = "PERSISTENT_RESERVE_IN",
|
1168 | ec766865 | Gerd Hoffmann | [ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT",
|
1169 | 5e30a07d | Hannes Reinecke | [ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16",
|
1170 | 5e30a07d | Hannes Reinecke | [ EXTENDED_COPY ] = "EXTENDED_COPY",
|
1171 | 5e30a07d | Hannes Reinecke | [ ATA_PASSTHROUGH ] = "ATA_PASSTHROUGH",
|
1172 | 5e30a07d | Hannes Reinecke | [ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN",
|
1173 | 5e30a07d | Hannes Reinecke | [ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT",
|
1174 | 5e30a07d | Hannes Reinecke | [ READ_16 ] = "READ_16",
|
1175 | 5e30a07d | Hannes Reinecke | [ COMPARE_AND_WRITE ] = "COMPARE_AND_WRITE",
|
1176 | 5e30a07d | Hannes Reinecke | [ WRITE_16 ] = "WRITE_16",
|
1177 | 5e30a07d | Hannes Reinecke | [ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16",
|
1178 | 5e30a07d | Hannes Reinecke | [ VERIFY_16 ] = "VERIFY_16",
|
1179 | 00a01ad4 | Paolo Bonzini | [ PRE_FETCH_16 ] = "PRE_FETCH_16",
|
1180 | 00a01ad4 | Paolo Bonzini | [ SYNCHRONIZE_CACHE_16 ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
|
1181 | 00a01ad4 | Paolo Bonzini | /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
|
1182 | 5e30a07d | Hannes Reinecke | [ LOCATE_16 ] = "LOCATE_16",
|
1183 | 00a01ad4 | Paolo Bonzini | [ WRITE_SAME_16 ] = "ERASE_16/WRITE_SAME_16",
|
1184 | 48bb9f53 | Blue Swirl | /* ERASE_16 and WRITE_SAME_16 use the same operation code */
|
1185 | f6515262 | Paolo Bonzini | [ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16",
|
1186 | 5e30a07d | Hannes Reinecke | [ WRITE_LONG_16 ] = "WRITE_LONG_16",
|
1187 | 5e30a07d | Hannes Reinecke | [ REPORT_LUNS ] = "REPORT_LUNS",
|
1188 | 5e30a07d | Hannes Reinecke | [ BLANK ] = "BLANK",
|
1189 | ec766865 | Gerd Hoffmann | [ MOVE_MEDIUM ] = "MOVE_MEDIUM",
|
1190 | 5e30a07d | Hannes Reinecke | [ LOAD_UNLOAD ] = "LOAD_UNLOAD",
|
1191 | ec766865 | Gerd Hoffmann | [ READ_12 ] = "READ_12",
|
1192 | ec766865 | Gerd Hoffmann | [ WRITE_12 ] = "WRITE_12",
|
1193 | 00a01ad4 | Paolo Bonzini | [ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE",
|
1194 | 00a01ad4 | Paolo Bonzini | /* ERASE_12 and GET_PERFORMANCE use the same operation code */
|
1195 | f6515262 | Paolo Bonzini | [ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12",
|
1196 | ec766865 | Gerd Hoffmann | [ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12",
|
1197 | 5e30a07d | Hannes Reinecke | [ VERIFY_12 ] = "VERIFY_12",
|
1198 | ec766865 | Gerd Hoffmann | [ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12",
|
1199 | ec766865 | Gerd Hoffmann | [ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12",
|
1200 | ec766865 | Gerd Hoffmann | [ SEARCH_LOW_12 ] = "SEARCH_LOW_12",
|
1201 | ec766865 | Gerd Hoffmann | [ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS",
|
1202 | 00a01ad4 | Paolo Bonzini | [ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG/SET_STREAMING",
|
1203 | 00a01ad4 | Paolo Bonzini | /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
|
1204 | 00a01ad4 | Paolo Bonzini | [ READ_CD ] = "READ_CD",
|
1205 | 5e30a07d | Hannes Reinecke | [ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12",
|
1206 | 00a01ad4 | Paolo Bonzini | [ READ_DVD_STRUCTURE ] = "READ_DVD_STRUCTURE",
|
1207 | 00a01ad4 | Paolo Bonzini | [ RESERVE_TRACK ] = "RESERVE_TRACK",
|
1208 | 00a01ad4 | Paolo Bonzini | [ SEND_CUE_SHEET ] = "SEND_CUE_SHEET",
|
1209 | 00a01ad4 | Paolo Bonzini | [ SEND_DVD_STRUCTURE ] = "SEND_DVD_STRUCTURE",
|
1210 | ec766865 | Gerd Hoffmann | [ SET_CD_SPEED ] = "SET_CD_SPEED",
|
1211 | 00a01ad4 | Paolo Bonzini | [ SET_READ_AHEAD ] = "SET_READ_AHEAD",
|
1212 | 00a01ad4 | Paolo Bonzini | [ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE",
|
1213 | 00a01ad4 | Paolo Bonzini | [ MECHANISM_STATUS ] = "MECHANISM_STATUS",
|
1214 | ec766865 | Gerd Hoffmann | }; |
1215 | ec766865 | Gerd Hoffmann | |
1216 | ec766865 | Gerd Hoffmann | if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) |
1217 | ec766865 | Gerd Hoffmann | return "*UNKNOWN*"; |
1218 | ec766865 | Gerd Hoffmann | return names[cmd];
|
1219 | ec766865 | Gerd Hoffmann | } |
1220 | ec766865 | Gerd Hoffmann | |
1221 | ad2d30f7 | Paolo Bonzini | SCSIRequest *scsi_req_ref(SCSIRequest *req) |
1222 | ad2d30f7 | Paolo Bonzini | { |
1223 | ad2d30f7 | Paolo Bonzini | req->refcount++; |
1224 | ad2d30f7 | Paolo Bonzini | return req;
|
1225 | ad2d30f7 | Paolo Bonzini | } |
1226 | ad2d30f7 | Paolo Bonzini | |
1227 | ad2d30f7 | Paolo Bonzini | void scsi_req_unref(SCSIRequest *req)
|
1228 | ad2d30f7 | Paolo Bonzini | { |
1229 | ad2d30f7 | Paolo Bonzini | if (--req->refcount == 0) { |
1230 | 12010e7b | Paolo Bonzini | if (req->ops->free_req) {
|
1231 | 12010e7b | Paolo Bonzini | req->ops->free_req(req); |
1232 | ad2d30f7 | Paolo Bonzini | } |
1233 | 7267c094 | Anthony Liguori | g_free(req); |
1234 | ad2d30f7 | Paolo Bonzini | } |
1235 | ad2d30f7 | Paolo Bonzini | } |
1236 | ad2d30f7 | Paolo Bonzini | |
1237 | ad3376cc | Paolo Bonzini | /* Tell the device that we finished processing this chunk of I/O. It
|
1238 | ad3376cc | Paolo Bonzini | will start the next chunk or complete the command. */
|
1239 | ad3376cc | Paolo Bonzini | void scsi_req_continue(SCSIRequest *req)
|
1240 | ad3376cc | Paolo Bonzini | { |
1241 | ad3376cc | Paolo Bonzini | trace_scsi_req_continue(req->dev->id, req->lun, req->tag); |
1242 | ad3376cc | Paolo Bonzini | if (req->cmd.mode == SCSI_XFER_TO_DEV) {
|
1243 | 12010e7b | Paolo Bonzini | req->ops->write_data(req); |
1244 | ad3376cc | Paolo Bonzini | } else {
|
1245 | 12010e7b | Paolo Bonzini | req->ops->read_data(req); |
1246 | ad3376cc | Paolo Bonzini | } |
1247 | ad3376cc | Paolo Bonzini | } |
1248 | ad3376cc | Paolo Bonzini | |
1249 | ab9adc88 | Paolo Bonzini | /* Called by the devices when data is ready for the HBA. The HBA should
|
1250 | ab9adc88 | Paolo Bonzini | start a DMA operation to read or fill the device's data buffer.
|
1251 | ad3376cc | Paolo Bonzini | Once it completes, calling scsi_req_continue will restart I/O. */
|
1252 | ab9adc88 | Paolo Bonzini | void scsi_req_data(SCSIRequest *req, int len) |
1253 | ab9adc88 | Paolo Bonzini | { |
1254 | e88c591d | Paolo Bonzini | if (req->io_canceled) {
|
1255 | e88c591d | Paolo Bonzini | trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len); |
1256 | e88c591d | Paolo Bonzini | } else {
|
1257 | e88c591d | Paolo Bonzini | trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); |
1258 | e88c591d | Paolo Bonzini | req->bus->info->transfer_data(req, len); |
1259 | e88c591d | Paolo Bonzini | } |
1260 | ab9adc88 | Paolo Bonzini | } |
1261 | ab9adc88 | Paolo Bonzini | |
1262 | ec766865 | Gerd Hoffmann | void scsi_req_print(SCSIRequest *req)
|
1263 | ec766865 | Gerd Hoffmann | { |
1264 | ec766865 | Gerd Hoffmann | FILE *fp = stderr; |
1265 | ec766865 | Gerd Hoffmann | int i;
|
1266 | ec766865 | Gerd Hoffmann | |
1267 | ec766865 | Gerd Hoffmann | fprintf(fp, "[%s id=%d] %s",
|
1268 | ec766865 | Gerd Hoffmann | req->dev->qdev.parent_bus->name, |
1269 | ec766865 | Gerd Hoffmann | req->dev->id, |
1270 | ec766865 | Gerd Hoffmann | scsi_command_name(req->cmd.buf[0]));
|
1271 | ec766865 | Gerd Hoffmann | for (i = 1; i < req->cmd.len; i++) { |
1272 | ec766865 | Gerd Hoffmann | fprintf(fp, " 0x%02x", req->cmd.buf[i]);
|
1273 | ec766865 | Gerd Hoffmann | } |
1274 | ec766865 | Gerd Hoffmann | switch (req->cmd.mode) {
|
1275 | ec766865 | Gerd Hoffmann | case SCSI_XFER_NONE:
|
1276 | ec766865 | Gerd Hoffmann | fprintf(fp, " - none\n");
|
1277 | ec766865 | Gerd Hoffmann | break;
|
1278 | ec766865 | Gerd Hoffmann | case SCSI_XFER_FROM_DEV:
|
1279 | ec766865 | Gerd Hoffmann | fprintf(fp, " - from-dev len=%zd\n", req->cmd.xfer);
|
1280 | ec766865 | Gerd Hoffmann | break;
|
1281 | ec766865 | Gerd Hoffmann | case SCSI_XFER_TO_DEV:
|
1282 | ec766865 | Gerd Hoffmann | fprintf(fp, " - to-dev len=%zd\n", req->cmd.xfer);
|
1283 | ec766865 | Gerd Hoffmann | break;
|
1284 | ec766865 | Gerd Hoffmann | default:
|
1285 | ec766865 | Gerd Hoffmann | fprintf(fp, " - Oops\n");
|
1286 | ec766865 | Gerd Hoffmann | break;
|
1287 | ec766865 | Gerd Hoffmann | } |
1288 | ec766865 | Gerd Hoffmann | } |
1289 | ec766865 | Gerd Hoffmann | |
1290 | 682a9b21 | Paolo Bonzini | void scsi_req_complete(SCSIRequest *req, int status) |
1291 | ed3a34a3 | Gerd Hoffmann | { |
1292 | 682a9b21 | Paolo Bonzini | assert(req->status == -1);
|
1293 | 682a9b21 | Paolo Bonzini | req->status = status; |
1294 | b45ef674 | Paolo Bonzini | |
1295 | b45ef674 | Paolo Bonzini | assert(req->sense_len < sizeof(req->sense));
|
1296 | b45ef674 | Paolo Bonzini | if (status == GOOD) {
|
1297 | b45ef674 | Paolo Bonzini | req->sense_len = 0;
|
1298 | b45ef674 | Paolo Bonzini | } |
1299 | b45ef674 | Paolo Bonzini | |
1300 | b45ef674 | Paolo Bonzini | if (req->sense_len) {
|
1301 | b45ef674 | Paolo Bonzini | memcpy(req->dev->sense, req->sense, req->sense_len); |
1302 | 3653d8c4 | Paolo Bonzini | req->dev->sense_len = req->sense_len; |
1303 | 3653d8c4 | Paolo Bonzini | req->dev->sense_is_ua = (req->ops == &reqops_unit_attention); |
1304 | 3653d8c4 | Paolo Bonzini | } else {
|
1305 | 3653d8c4 | Paolo Bonzini | req->dev->sense_len = 0;
|
1306 | 3653d8c4 | Paolo Bonzini | req->dev->sense_is_ua = false;
|
1307 | b45ef674 | Paolo Bonzini | } |
1308 | b45ef674 | Paolo Bonzini | |
1309 | 6dc06f08 | Paolo Bonzini | /*
|
1310 | 6dc06f08 | Paolo Bonzini | * Unit attention state is now stored in the device's sense buffer
|
1311 | 6dc06f08 | Paolo Bonzini | * if the HBA didn't do autosense. Clear the pending unit attention
|
1312 | 6dc06f08 | Paolo Bonzini | * flags.
|
1313 | 6dc06f08 | Paolo Bonzini | */
|
1314 | 6dc06f08 | Paolo Bonzini | scsi_clear_unit_attention(req); |
1315 | 6dc06f08 | Paolo Bonzini | |
1316 | ad2d30f7 | Paolo Bonzini | scsi_req_ref(req); |
1317 | e8637c90 | Jan Kiszka | scsi_req_dequeue(req); |
1318 | afd4030c | Paolo Bonzini | req->bus->info->complete(req, req->status); |
1319 | ad2d30f7 | Paolo Bonzini | scsi_req_unref(req); |
1320 | ed3a34a3 | Gerd Hoffmann | } |
1321 | db07c0f8 | Gleb Natapov | |
1322 | 94d3f98a | Paolo Bonzini | void scsi_req_cancel(SCSIRequest *req)
|
1323 | 94d3f98a | Paolo Bonzini | { |
1324 | e88c591d | Paolo Bonzini | if (!req->enqueued) {
|
1325 | e88c591d | Paolo Bonzini | return;
|
1326 | 94d3f98a | Paolo Bonzini | } |
1327 | 94d3f98a | Paolo Bonzini | scsi_req_ref(req); |
1328 | 94d3f98a | Paolo Bonzini | scsi_req_dequeue(req); |
1329 | e88c591d | Paolo Bonzini | req->io_canceled = true;
|
1330 | e88c591d | Paolo Bonzini | if (req->ops->cancel_io) {
|
1331 | e88c591d | Paolo Bonzini | req->ops->cancel_io(req); |
1332 | e88c591d | Paolo Bonzini | } |
1333 | afd4030c | Paolo Bonzini | if (req->bus->info->cancel) {
|
1334 | afd4030c | Paolo Bonzini | req->bus->info->cancel(req); |
1335 | 94d3f98a | Paolo Bonzini | } |
1336 | 94d3f98a | Paolo Bonzini | scsi_req_unref(req); |
1337 | 94d3f98a | Paolo Bonzini | } |
1338 | 94d3f98a | Paolo Bonzini | |
1339 | 19d110ab | Paolo Bonzini | void scsi_req_abort(SCSIRequest *req, int status) |
1340 | 19d110ab | Paolo Bonzini | { |
1341 | e88c591d | Paolo Bonzini | if (!req->enqueued) {
|
1342 | e88c591d | Paolo Bonzini | return;
|
1343 | e88c591d | Paolo Bonzini | } |
1344 | e88c591d | Paolo Bonzini | scsi_req_ref(req); |
1345 | e88c591d | Paolo Bonzini | scsi_req_dequeue(req); |
1346 | e88c591d | Paolo Bonzini | req->io_canceled = true;
|
1347 | 12010e7b | Paolo Bonzini | if (req->ops->cancel_io) {
|
1348 | 12010e7b | Paolo Bonzini | req->ops->cancel_io(req); |
1349 | 19d110ab | Paolo Bonzini | } |
1350 | 682a9b21 | Paolo Bonzini | scsi_req_complete(req, status); |
1351 | e88c591d | Paolo Bonzini | scsi_req_unref(req); |
1352 | 19d110ab | Paolo Bonzini | } |
1353 | 19d110ab | Paolo Bonzini | |
1354 | c7b48872 | Paolo Bonzini | void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
|
1355 | c557e889 | Paolo Bonzini | { |
1356 | c557e889 | Paolo Bonzini | SCSIRequest *req; |
1357 | c557e889 | Paolo Bonzini | |
1358 | c557e889 | Paolo Bonzini | while (!QTAILQ_EMPTY(&sdev->requests)) {
|
1359 | c557e889 | Paolo Bonzini | req = QTAILQ_FIRST(&sdev->requests); |
1360 | 94d3f98a | Paolo Bonzini | scsi_req_cancel(req); |
1361 | c557e889 | Paolo Bonzini | } |
1362 | c7b48872 | Paolo Bonzini | sdev->unit_attention = sense; |
1363 | c557e889 | Paolo Bonzini | } |
1364 | c557e889 | Paolo Bonzini | |
1365 | db07c0f8 | Gleb Natapov | static char *scsibus_get_fw_dev_path(DeviceState *dev) |
1366 | db07c0f8 | Gleb Natapov | { |
1367 | 645a8ad6 | Zhi Yong Wu | SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev); |
1368 | db07c0f8 | Gleb Natapov | char path[100]; |
1369 | db07c0f8 | Gleb Natapov | |
1370 | 7082826e | Paolo Bonzini | snprintf(path, sizeof(path), "%s@%d,%d,%d", qdev_fw_name(dev), |
1371 | 0d3545e7 | Paolo Bonzini | d->channel, d->id, d->lun); |
1372 | db07c0f8 | Gleb Natapov | |
1373 | f48a7a6e | Paolo Bonzini | return strdup(path);
|
1374 | f48a7a6e | Paolo Bonzini | } |
1375 | f48a7a6e | Paolo Bonzini | |
1376 | 0d3545e7 | Paolo Bonzini | SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun) |
1377 | f48a7a6e | Paolo Bonzini | { |
1378 | f48a7a6e | Paolo Bonzini | DeviceState *qdev; |
1379 | f48a7a6e | Paolo Bonzini | SCSIDevice *target_dev = NULL;
|
1380 | db07c0f8 | Gleb Natapov | |
1381 | f48a7a6e | Paolo Bonzini | QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) { |
1382 | f48a7a6e | Paolo Bonzini | SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); |
1383 | db07c0f8 | Gleb Natapov | |
1384 | 0d3545e7 | Paolo Bonzini | if (dev->channel == channel && dev->id == id) {
|
1385 | f48a7a6e | Paolo Bonzini | if (dev->lun == lun) {
|
1386 | f48a7a6e | Paolo Bonzini | return dev;
|
1387 | f48a7a6e | Paolo Bonzini | } |
1388 | f48a7a6e | Paolo Bonzini | target_dev = dev; |
1389 | f48a7a6e | Paolo Bonzini | } |
1390 | f48a7a6e | Paolo Bonzini | } |
1391 | f48a7a6e | Paolo Bonzini | return target_dev;
|
1392 | db07c0f8 | Gleb Natapov | } |