File: | hw/scsi/scsi-bus.c |
Location: | line 607, column 9 |
Description: | Function call argument is an uninitialized value |
1 | #include "hw/hw.h" | |||
2 | #include "qemu/error-report.h" | |||
3 | #include "hw/scsi/scsi.h" | |||
4 | #include "block/scsi.h" | |||
5 | #include "hw/qdev.h" | |||
6 | #include "sysemu/blockdev.h" | |||
7 | #include "trace.h" | |||
8 | #include "sysemu/dma.h" | |||
9 | ||||
10 | static char *scsibus_get_dev_path(DeviceState *dev); | |||
11 | static char *scsibus_get_fw_dev_path(DeviceState *dev); | |||
12 | static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf); | |||
13 | static void scsi_req_dequeue(SCSIRequest *req); | |||
14 | static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len); | |||
15 | static void scsi_target_free_buf(SCSIRequest *req); | |||
16 | ||||
17 | static Property scsi_props[] = { | |||
18 | DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0){ .name = ("channel"), .info = &(qdev_prop_uint32), .offset = __builtin_offsetof(SCSIDevice, channel) + ((uint32_t*)0 - ( typeof(((SCSIDevice *)0)->channel)*)0), .qtype = QTYPE_QINT , .defval = (uint32_t)0, }, | |||
19 | DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1){ .name = ("scsi-id"), .info = &(qdev_prop_uint32), .offset = __builtin_offsetof(SCSIDevice, id) + ((uint32_t*)0 - (typeof (((SCSIDevice *)0)->id)*)0), .qtype = QTYPE_QINT, .defval = (uint32_t)-1, }, | |||
20 | DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1){ .name = ("lun"), .info = &(qdev_prop_uint32), .offset = __builtin_offsetof(SCSIDevice, lun) + ((uint32_t*)0 - (typeof (((SCSIDevice *)0)->lun)*)0), .qtype = QTYPE_QINT, .defval = (uint32_t)-1, }, | |||
21 | DEFINE_PROP_END_OF_LIST(){}, | |||
22 | }; | |||
23 | ||||
24 | static void scsi_bus_class_init(ObjectClass *klass, void *data) | |||
25 | { | |||
26 | BusClass *k = BUS_CLASS(klass)((BusClass *)object_class_dynamic_cast_assert(((ObjectClass * )((klass))), ("bus"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 26, __func__)); | |||
27 | ||||
28 | k->get_dev_path = scsibus_get_dev_path; | |||
29 | k->get_fw_dev_path = scsibus_get_fw_dev_path; | |||
30 | } | |||
31 | ||||
32 | static const TypeInfo scsi_bus_info = { | |||
33 | .name = TYPE_SCSI_BUS"SCSI", | |||
34 | .parent = TYPE_BUS"bus", | |||
35 | .instance_size = sizeof(SCSIBus), | |||
36 | .class_init = scsi_bus_class_init, | |||
37 | }; | |||
38 | static int next_scsi_bus; | |||
39 | ||||
40 | static int scsi_device_init(SCSIDevice *s) | |||
41 | { | |||
42 | SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s)((SCSIDeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)(object_get_class(((Object *)((s)))))), ("scsi-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 42, __func__)); | |||
43 | if (sc->init) { | |||
44 | return sc->init(s); | |||
45 | } | |||
46 | return 0; | |||
47 | } | |||
48 | ||||
49 | static void scsi_device_destroy(SCSIDevice *s) | |||
50 | { | |||
51 | SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s)((SCSIDeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)(object_get_class(((Object *)((s)))))), ("scsi-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 51, __func__)); | |||
52 | if (sc->destroy) { | |||
53 | sc->destroy(s); | |||
54 | } | |||
55 | } | |||
56 | ||||
57 | static SCSIRequest *scsi_device_alloc_req(SCSIDevice *s, uint32_t tag, uint32_t lun, | |||
58 | uint8_t *buf, void *hba_private) | |||
59 | { | |||
60 | SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s)((SCSIDeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)(object_get_class(((Object *)((s)))))), ("scsi-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 60, __func__)); | |||
61 | if (sc->alloc_req) { | |||
62 | return sc->alloc_req(s, tag, lun, buf, hba_private); | |||
63 | } | |||
64 | ||||
65 | return NULL((void*)0); | |||
66 | } | |||
67 | ||||
68 | static void scsi_device_unit_attention_reported(SCSIDevice *s) | |||
69 | { | |||
70 | SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s)((SCSIDeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)(object_get_class(((Object *)((s)))))), ("scsi-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 70, __func__)); | |||
71 | if (sc->unit_attention_reported) { | |||
72 | sc->unit_attention_reported(s); | |||
73 | } | |||
74 | } | |||
75 | ||||
76 | /* Create a scsi bus, and attach devices to it. */ | |||
77 | void scsi_bus_new(SCSIBus *bus, size_t bus_size, DeviceState *host, | |||
78 | const SCSIBusInfo *info, const char *bus_name) | |||
79 | { | |||
80 | qbus_create_inplace(bus, bus_size, TYPE_SCSI_BUS"SCSI", host, bus_name); | |||
81 | bus->busnr = next_scsi_bus++; | |||
82 | bus->info = info; | |||
83 | bus->qbus.allow_hotplug = 1; | |||
84 | } | |||
85 | ||||
86 | static void scsi_dma_restart_bh(void *opaque) | |||
87 | { | |||
88 | SCSIDevice *s = opaque; | |||
89 | SCSIRequest *req, *next; | |||
90 | ||||
91 | qemu_bh_delete(s->bh); | |||
92 | s->bh = NULL((void*)0); | |||
93 | ||||
94 | QTAILQ_FOREACH_SAFE(req, &s->requests, next, next)for ((req) = ((&s->requests)->tqh_first); (req) && ((next) = ((req)->next.tqe_next), 1); (req) = (next)) { | |||
95 | scsi_req_ref(req); | |||
96 | if (req->retry) { | |||
97 | req->retry = false0; | |||
98 | switch (req->cmd.mode) { | |||
99 | case SCSI_XFER_FROM_DEV: | |||
100 | case SCSI_XFER_TO_DEV: | |||
101 | scsi_req_continue(req); | |||
102 | break; | |||
103 | case SCSI_XFER_NONE: | |||
104 | assert(!req->sg)((!req->sg) ? (void) (0) : __assert_fail ("!req->sg", "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 104, __PRETTY_FUNCTION__)); | |||
105 | scsi_req_dequeue(req); | |||
106 | scsi_req_enqueue(req); | |||
107 | break; | |||
108 | } | |||
109 | } | |||
110 | scsi_req_unref(req); | |||
111 | } | |||
112 | } | |||
113 | ||||
114 | void scsi_req_retry(SCSIRequest *req) | |||
115 | { | |||
116 | /* No need to save a reference, because scsi_dma_restart_bh just | |||
117 | * looks at the request list. */ | |||
118 | req->retry = true1; | |||
119 | } | |||
120 | ||||
121 | static void scsi_dma_restart_cb(void *opaque, int running, RunState state) | |||
122 | { | |||
123 | SCSIDevice *s = opaque; | |||
124 | ||||
125 | if (!running) { | |||
126 | return; | |||
127 | } | |||
128 | if (!s->bh) { | |||
129 | s->bh = qemu_bh_new(scsi_dma_restart_bh, s); | |||
130 | qemu_bh_schedule(s->bh); | |||
131 | } | |||
132 | } | |||
133 | ||||
134 | static int scsi_qdev_init(DeviceState *qdev) | |||
135 | { | |||
136 | SCSIDevice *dev = SCSI_DEVICE(qdev)((SCSIDevice *)object_dynamic_cast_assert(((Object *)((qdev)) ), ("scsi-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 136, __func__)); | |||
137 | SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSIBus, qbus)]; ({ const typeof(((SCSIBus *) 0)->qbus) *__mptr = (dev->qdev.parent_bus); (SCSIBus *) ((char *) __mptr - __builtin_offsetof(SCSIBus, qbus));}); })); | |||
138 | SCSIDevice *d; | |||
139 | int rc = -1; | |||
140 | ||||
141 | if (dev->channel > bus->info->max_channel) { | |||
142 | error_report("bad scsi channel id: %d", dev->channel); | |||
143 | goto err; | |||
144 | } | |||
145 | if (dev->id != -1 && dev->id > bus->info->max_target) { | |||
146 | error_report("bad scsi device id: %d", dev->id); | |||
147 | goto err; | |||
148 | } | |||
149 | if (dev->lun != -1 && dev->lun > bus->info->max_lun) { | |||
150 | error_report("bad scsi device lun: %d", dev->lun); | |||
151 | goto err; | |||
152 | } | |||
153 | ||||
154 | if (dev->id == -1) { | |||
155 | int id = -1; | |||
156 | if (dev->lun == -1) { | |||
157 | dev->lun = 0; | |||
158 | } | |||
159 | do { | |||
160 | d = scsi_device_find(bus, dev->channel, ++id, dev->lun); | |||
161 | } while (d && d->lun == dev->lun && id < bus->info->max_target); | |||
162 | if (d && d->lun == dev->lun) { | |||
163 | error_report("no free target"); | |||
164 | goto err; | |||
165 | } | |||
166 | dev->id = id; | |||
167 | } else if (dev->lun == -1) { | |||
168 | int lun = -1; | |||
169 | do { | |||
170 | d = scsi_device_find(bus, dev->channel, dev->id, ++lun); | |||
171 | } while (d && d->lun == lun && lun < bus->info->max_lun); | |||
172 | if (d && d->lun == lun) { | |||
173 | error_report("no free lun"); | |||
174 | goto err; | |||
175 | } | |||
176 | dev->lun = lun; | |||
177 | } else { | |||
178 | d = scsi_device_find(bus, dev->channel, dev->id, dev->lun); | |||
179 | assert(d)((d) ? (void) (0) : __assert_fail ("d", "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 179, __PRETTY_FUNCTION__)); | |||
180 | if (d->lun == dev->lun && dev != d) { | |||
181 | object_unparent(OBJECT(d)((Object *)(d))); | |||
182 | } | |||
183 | } | |||
184 | ||||
185 | QTAILQ_INIT(&dev->requests)do { (&dev->requests)->tqh_first = ((void*)0); (& dev->requests)->tqh_last = &(&dev->requests) ->tqh_first; } while ( 0); | |||
186 | rc = scsi_device_init(dev); | |||
187 | if (rc == 0) { | |||
188 | dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb, | |||
189 | dev); | |||
190 | } | |||
191 | ||||
192 | if (bus->info->hotplug) { | |||
193 | bus->info->hotplug(bus, dev); | |||
194 | } | |||
195 | ||||
196 | err: | |||
197 | return rc; | |||
198 | } | |||
199 | ||||
200 | static int scsi_qdev_exit(DeviceState *qdev) | |||
201 | { | |||
202 | SCSIDevice *dev = SCSI_DEVICE(qdev)((SCSIDevice *)object_dynamic_cast_assert(((Object *)((qdev)) ), ("scsi-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 202, __func__)); | |||
203 | ||||
204 | if (dev->vmsentry) { | |||
205 | qemu_del_vm_change_state_handler(dev->vmsentry); | |||
206 | } | |||
207 | scsi_device_destroy(dev); | |||
208 | return 0; | |||
209 | } | |||
210 | ||||
211 | /* handle legacy '-drive if=scsi,...' cmd line args */ | |||
212 | SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, | |||
213 | int unit, bool_Bool removable, int bootindex, | |||
214 | const char *serial, Error **errp) | |||
215 | { | |||
216 | const char *driver; | |||
217 | DeviceState *dev; | |||
218 | Error *err = NULL((void*)0); | |||
219 | ||||
220 | driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk"; | |||
221 | dev = qdev_create(&bus->qbus, driver); | |||
222 | qdev_prop_set_uint32(dev, "scsi-id", unit); | |||
223 | if (bootindex >= 0) { | |||
224 | qdev_prop_set_int32(dev, "bootindex", bootindex); | |||
225 | } | |||
226 | if (object_property_find(OBJECT(dev)((Object *)(dev)), "removable", NULL((void*)0))) { | |||
227 | qdev_prop_set_bit(dev, "removable", removable); | |||
228 | } | |||
229 | if (serial && object_property_find(OBJECT(dev)((Object *)(dev)), "serial", NULL((void*)0))) { | |||
230 | qdev_prop_set_string(dev, "serial", serial); | |||
231 | } | |||
232 | if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) { | |||
233 | error_setg(errp, "Setting drive property failed")error_set(errp, ERROR_CLASS_GENERIC_ERROR, "Setting drive property failed" ); | |||
234 | object_unparent(OBJECT(dev)((Object *)(dev))); | |||
235 | return NULL((void*)0); | |||
236 | } | |||
237 | object_property_set_bool(OBJECT(dev)((Object *)(dev)), true1, "realized", &err); | |||
238 | if (err != NULL((void*)0)) { | |||
239 | error_propagate(errp, err); | |||
240 | object_unparent(OBJECT(dev)((Object *)(dev))); | |||
241 | return NULL((void*)0); | |||
242 | } | |||
243 | return SCSI_DEVICE(dev)((SCSIDevice *)object_dynamic_cast_assert(((Object *)((dev))) , ("scsi-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 243, __func__)); | |||
244 | } | |||
245 | ||||
246 | void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, Error **errp) | |||
247 | { | |||
248 | Location loc; | |||
249 | DriveInfo *dinfo; | |||
250 | int unit; | |||
251 | Error *err = NULL((void*)0); | |||
252 | ||||
253 | loc_push_none(&loc); | |||
254 | for (unit = 0; unit <= bus->info->max_target; unit++) { | |||
255 | dinfo = drive_get(IF_SCSI, bus->busnr, unit); | |||
256 | if (dinfo == NULL((void*)0)) { | |||
257 | continue; | |||
258 | } | |||
259 | qemu_opts_loc_restore(dinfo->opts); | |||
260 | scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false0, -1, NULL((void*)0), | |||
261 | &err); | |||
262 | if (err != NULL((void*)0)) { | |||
263 | error_propagate(errp, err); | |||
264 | break; | |||
265 | } | |||
266 | } | |||
267 | loc_pop(&loc); | |||
268 | } | |||
269 | ||||
270 | static int32_t scsi_invalid_field(SCSIRequest *req, uint8_t *buf) | |||
271 | { | |||
272 | scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD)sense_code_INVALID_FIELD); | |||
273 | scsi_req_complete(req, CHECK_CONDITION0x02); | |||
274 | return 0; | |||
275 | } | |||
276 | ||||
277 | static const struct SCSIReqOps reqops_invalid_field = { | |||
278 | .size = sizeof(SCSIRequest), | |||
279 | .send_command = scsi_invalid_field | |||
280 | }; | |||
281 | ||||
282 | /* SCSIReqOps implementation for invalid commands. */ | |||
283 | ||||
284 | static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf) | |||
285 | { | |||
286 | scsi_req_build_sense(req, SENSE_CODE(INVALID_OPCODE)sense_code_INVALID_OPCODE); | |||
287 | scsi_req_complete(req, CHECK_CONDITION0x02); | |||
288 | return 0; | |||
289 | } | |||
290 | ||||
291 | static const struct SCSIReqOps reqops_invalid_opcode = { | |||
292 | .size = sizeof(SCSIRequest), | |||
293 | .send_command = scsi_invalid_command | |||
294 | }; | |||
295 | ||||
296 | /* SCSIReqOps implementation for unit attention conditions. */ | |||
297 | ||||
298 | static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf) | |||
299 | { | |||
300 | if (req->dev->unit_attention.key == UNIT_ATTENTION0x06) { | |||
301 | scsi_req_build_sense(req, req->dev->unit_attention); | |||
302 | } else if (req->bus->unit_attention.key == UNIT_ATTENTION0x06) { | |||
303 | scsi_req_build_sense(req, req->bus->unit_attention); | |||
304 | } | |||
305 | scsi_req_complete(req, CHECK_CONDITION0x02); | |||
306 | return 0; | |||
307 | } | |||
308 | ||||
309 | static const struct SCSIReqOps reqops_unit_attention = { | |||
310 | .size = sizeof(SCSIRequest), | |||
311 | .send_command = scsi_unit_attention | |||
312 | }; | |||
313 | ||||
314 | /* SCSIReqOps implementation for REPORT LUNS and for commands sent to | |||
315 | an invalid LUN. */ | |||
316 | ||||
317 | typedef struct SCSITargetReq SCSITargetReq; | |||
318 | ||||
319 | struct SCSITargetReq { | |||
320 | SCSIRequest req; | |||
321 | int len; | |||
322 | uint8_t *buf; | |||
323 | int buf_len; | |||
324 | }; | |||
325 | ||||
326 | static void store_lun(uint8_t *outbuf, int lun) | |||
327 | { | |||
328 | if (lun < 256) { | |||
329 | outbuf[1] = lun; | |||
330 | return; | |||
331 | } | |||
332 | outbuf[1] = (lun & 255); | |||
333 | outbuf[0] = (lun >> 8) | 0x40; | |||
334 | } | |||
335 | ||||
336 | static bool_Bool scsi_target_emulate_report_luns(SCSITargetReq *r) | |||
337 | { | |||
338 | BusChild *kid; | |||
339 | int i, len, n; | |||
340 | int channel, id; | |||
341 | bool_Bool found_lun0; | |||
342 | ||||
343 | if (r->req.cmd.xfer < 16) { | |||
344 | return false0; | |||
345 | } | |||
346 | if (r->req.cmd.buf[2] > 2) { | |||
347 | return false0; | |||
348 | } | |||
349 | channel = r->req.dev->channel; | |||
350 | id = r->req.dev->id; | |||
351 | found_lun0 = false0; | |||
352 | n = 0; | |||
353 | QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling)for ((kid) = ((&r->req.bus->qbus.children)->tqh_first ); (kid); (kid) = ((kid)->sibling.tqe_next)) { | |||
354 | DeviceState *qdev = kid->child; | |||
355 | SCSIDevice *dev = SCSI_DEVICE(qdev)((SCSIDevice *)object_dynamic_cast_assert(((Object *)((qdev)) ), ("scsi-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 355, __func__)); | |||
356 | ||||
357 | if (dev->channel == channel && dev->id == id) { | |||
358 | if (dev->lun == 0) { | |||
359 | found_lun0 = true1; | |||
360 | } | |||
361 | n += 8; | |||
362 | } | |||
363 | } | |||
364 | if (!found_lun0) { | |||
365 | n += 8; | |||
366 | } | |||
367 | ||||
368 | scsi_target_alloc_buf(&r->req, n + 8); | |||
369 | ||||
370 | len = MIN(n + 8, r->req.cmd.xfer & ~7)(((n + 8) < (r->req.cmd.xfer & ~7)) ? (n + 8) : (r-> req.cmd.xfer & ~7)); | |||
371 | memset(r->buf, 0, len); | |||
372 | stl_be_p(&r->buf[0], n); | |||
373 | i = found_lun0 ? 8 : 16; | |||
374 | QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling)for ((kid) = ((&r->req.bus->qbus.children)->tqh_first ); (kid); (kid) = ((kid)->sibling.tqe_next)) { | |||
375 | DeviceState *qdev = kid->child; | |||
376 | SCSIDevice *dev = SCSI_DEVICE(qdev)((SCSIDevice *)object_dynamic_cast_assert(((Object *)((qdev)) ), ("scsi-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 376, __func__)); | |||
377 | ||||
378 | if (dev->channel == channel && dev->id == id) { | |||
379 | store_lun(&r->buf[i], dev->lun); | |||
380 | i += 8; | |||
381 | } | |||
382 | } | |||
383 | assert(i == n + 8)((i == n + 8) ? (void) (0) : __assert_fail ("i == n + 8", "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 383, __PRETTY_FUNCTION__)); | |||
384 | r->len = len; | |||
385 | return true1; | |||
386 | } | |||
387 | ||||
388 | static bool_Bool scsi_target_emulate_inquiry(SCSITargetReq *r) | |||
389 | { | |||
390 | assert(r->req.dev->lun != r->req.lun)((r->req.dev->lun != r->req.lun) ? (void) (0) : __assert_fail ("r->req.dev->lun != r->req.lun", "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 390, __PRETTY_FUNCTION__)); | |||
391 | ||||
392 | scsi_target_alloc_buf(&r->req, SCSI_INQUIRY_LEN36); | |||
393 | ||||
394 | if (r->req.cmd.buf[1] & 0x2) { | |||
395 | /* Command support data - optional, not implemented */ | |||
396 | return false0; | |||
397 | } | |||
398 | ||||
399 | if (r->req.cmd.buf[1] & 0x1) { | |||
400 | /* Vital product data */ | |||
401 | uint8_t page_code = r->req.cmd.buf[2]; | |||
402 | r->buf[r->len++] = page_code ; /* this page */ | |||
403 | r->buf[r->len++] = 0x00; | |||
404 | ||||
405 | switch (page_code) { | |||
406 | case 0x00: /* Supported page codes, mandatory */ | |||
407 | { | |||
408 | int pages; | |||
409 | pages = r->len++; | |||
410 | r->buf[r->len++] = 0x00; /* list of supported pages (this page) */ | |||
411 | r->buf[pages] = r->len - pages - 1; /* number of pages */ | |||
412 | break; | |||
413 | } | |||
414 | default: | |||
415 | return false0; | |||
416 | } | |||
417 | /* done with EVPD */ | |||
418 | assert(r->len < r->buf_len)((r->len < r->buf_len) ? (void) (0) : __assert_fail ( "r->len < r->buf_len", "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 418, __PRETTY_FUNCTION__)); | |||
419 | r->len = MIN(r->req.cmd.xfer, r->len)(((r->req.cmd.xfer) < (r->len)) ? (r->req.cmd.xfer ) : (r->len)); | |||
420 | return true1; | |||
421 | } | |||
422 | ||||
423 | /* Standard INQUIRY data */ | |||
424 | if (r->req.cmd.buf[2] != 0) { | |||
425 | return false0; | |||
426 | } | |||
427 | ||||
428 | /* PAGE CODE == 0 */ | |||
429 | r->len = MIN(r->req.cmd.xfer, SCSI_INQUIRY_LEN)(((r->req.cmd.xfer) < (36)) ? (r->req.cmd.xfer) : (36 )); | |||
430 | memset(r->buf, 0, r->len); | |||
431 | if (r->req.lun != 0) { | |||
432 | r->buf[0] = TYPE_NO_LUN0x7f; | |||
433 | } else { | |||
434 | r->buf[0] = TYPE_NOT_PRESENT0x1f | TYPE_INACTIVE0x20; | |||
435 | r->buf[2] = 5; /* Version */ | |||
436 | r->buf[3] = 2 | 0x10; /* HiSup, response data format */ | |||
437 | r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */ | |||
438 | r->buf[7] = 0x10 | (r->req.bus->info->tcq ? 0x02 : 0); /* Sync, TCQ. */ | |||
439 | memcpy(&r->buf[8], "QEMU ", 8); | |||
440 | memcpy(&r->buf[16], "QEMU TARGET ", 16); | |||
441 | pstrcpy((char *) &r->buf[32], 4, qemu_get_version()); | |||
442 | } | |||
443 | return true1; | |||
444 | } | |||
445 | ||||
446 | static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) | |||
447 | { | |||
448 | SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSITargetReq, req)]; ({ const typeof(( (SCSITargetReq *) 0)->req) *__mptr = (req); (SCSITargetReq *) ((char *) __mptr - __builtin_offsetof(SCSITargetReq, req) );});})); | |||
449 | ||||
450 | switch (buf[0]) { | |||
451 | case REPORT_LUNS0xa0: | |||
452 | if (!scsi_target_emulate_report_luns(r)) { | |||
453 | goto illegal_request; | |||
454 | } | |||
455 | break; | |||
456 | case INQUIRY0x12: | |||
457 | if (!scsi_target_emulate_inquiry(r)) { | |||
458 | goto illegal_request; | |||
459 | } | |||
460 | break; | |||
461 | case REQUEST_SENSE0x03: | |||
462 | scsi_target_alloc_buf(&r->req, SCSI_SENSE_LEN18); | |||
463 | r->len = scsi_device_get_sense(r->req.dev, r->buf, | |||
464 | MIN(req->cmd.xfer, r->buf_len)(((req->cmd.xfer) < (r->buf_len)) ? (req->cmd.xfer ) : (r->buf_len)), | |||
465 | (req->cmd.buf[1] & 1) == 0); | |||
466 | if (r->req.dev->sense_is_ua) { | |||
467 | scsi_device_unit_attention_reported(req->dev); | |||
468 | r->req.dev->sense_len = 0; | |||
469 | r->req.dev->sense_is_ua = false0; | |||
470 | } | |||
471 | break; | |||
472 | default: | |||
473 | scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED)sense_code_LUN_NOT_SUPPORTED); | |||
474 | scsi_req_complete(req, CHECK_CONDITION0x02); | |||
475 | return 0; | |||
476 | illegal_request: | |||
477 | scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD)sense_code_INVALID_FIELD); | |||
478 | scsi_req_complete(req, CHECK_CONDITION0x02); | |||
479 | return 0; | |||
480 | } | |||
481 | ||||
482 | if (!r->len) { | |||
483 | scsi_req_complete(req, GOOD0x00); | |||
484 | } | |||
485 | return r->len; | |||
486 | } | |||
487 | ||||
488 | static void scsi_target_read_data(SCSIRequest *req) | |||
489 | { | |||
490 | SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSITargetReq, req)]; ({ const typeof(( (SCSITargetReq *) 0)->req) *__mptr = (req); (SCSITargetReq *) ((char *) __mptr - __builtin_offsetof(SCSITargetReq, req) );});})); | |||
491 | uint32_t n; | |||
492 | ||||
493 | n = r->len; | |||
494 | if (n > 0) { | |||
495 | r->len = 0; | |||
496 | scsi_req_data(&r->req, n); | |||
497 | } else { | |||
498 | scsi_req_complete(&r->req, GOOD0x00); | |||
499 | } | |||
500 | } | |||
501 | ||||
502 | static uint8_t *scsi_target_get_buf(SCSIRequest *req) | |||
503 | { | |||
504 | SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSITargetReq, req)]; ({ const typeof(( (SCSITargetReq *) 0)->req) *__mptr = (req); (SCSITargetReq *) ((char *) __mptr - __builtin_offsetof(SCSITargetReq, req) );});})); | |||
505 | ||||
506 | return r->buf; | |||
507 | } | |||
508 | ||||
509 | static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len) | |||
510 | { | |||
511 | SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSITargetReq, req)]; ({ const typeof(( (SCSITargetReq *) 0)->req) *__mptr = (req); (SCSITargetReq *) ((char *) __mptr - __builtin_offsetof(SCSITargetReq, req) );});})); | |||
512 | ||||
513 | r->buf = g_malloc(len); | |||
514 | r->buf_len = len; | |||
515 | ||||
516 | return r->buf; | |||
517 | } | |||
518 | ||||
519 | static void scsi_target_free_buf(SCSIRequest *req) | |||
520 | { | |||
521 | SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSITargetReq, req)]; ({ const typeof(( (SCSITargetReq *) 0)->req) *__mptr = (req); (SCSITargetReq *) ((char *) __mptr - __builtin_offsetof(SCSITargetReq, req) );});})); | |||
522 | ||||
523 | g_free(r->buf); | |||
524 | } | |||
525 | ||||
526 | static const struct SCSIReqOps reqops_target_command = { | |||
527 | .size = sizeof(SCSITargetReq), | |||
528 | .send_command = scsi_target_send_command, | |||
529 | .read_data = scsi_target_read_data, | |||
530 | .get_buf = scsi_target_get_buf, | |||
531 | .free_req = scsi_target_free_buf, | |||
532 | }; | |||
533 | ||||
534 | ||||
535 | SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, | |||
536 | uint32_t tag, uint32_t lun, void *hba_private) | |||
537 | { | |||
538 | SCSIRequest *req; | |||
539 | SCSIBus *bus = scsi_bus_from_device(d); | |||
540 | BusState *qbus = BUS(bus)((BusState *)object_dynamic_cast_assert(((Object *)((bus))), ( "bus"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 540, __func__)); | |||
541 | ||||
542 | req = g_malloc0(reqops->size); | |||
543 | req->refcount = 1; | |||
544 | req->bus = bus; | |||
545 | req->dev = d; | |||
546 | req->tag = tag; | |||
547 | req->lun = lun; | |||
548 | req->hba_private = hba_private; | |||
549 | req->status = -1; | |||
550 | req->sense_len = 0; | |||
551 | req->ops = reqops; | |||
552 | object_ref(OBJECT(d)((Object *)(d))); | |||
553 | object_ref(OBJECT(qbus->parent)((Object *)(qbus->parent))); | |||
554 | trace_scsi_req_alloc(req->dev->id, req->lun, req->tag); | |||
555 | return req; | |||
556 | } | |||
557 | ||||
558 | SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, | |||
559 | uint8_t *buf, void *hba_private) | |||
560 | { | |||
561 | SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSIBus, qbus)]; ({ const typeof(((SCSIBus *) 0)->qbus) *__mptr = (d->qdev.parent_bus); (SCSIBus * ) ((char *) __mptr - __builtin_offsetof(SCSIBus, qbus));});}) ); | |||
562 | SCSIRequest *req; | |||
563 | SCSICommand cmd; | |||
564 | ||||
565 | if (scsi_req_parse(&cmd, d, buf) != 0) { | |||
566 | trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]); | |||
567 | req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private); | |||
568 | } else { | |||
569 | trace_scsi_req_parsed(d->id, lun, tag, buf[0], | |||
570 | cmd.mode, cmd.xfer); | |||
571 | if (cmd.lba != -1) { | |||
572 | trace_scsi_req_parsed_lba(d->id, lun, tag, buf[0], | |||
573 | cmd.lba); | |||
574 | } | |||
575 | ||||
576 | if (cmd.xfer > INT32_MAX(2147483647)) { | |||
577 | req = scsi_req_alloc(&reqops_invalid_field, d, tag, lun, hba_private); | |||
578 | } else if ((d->unit_attention.key == UNIT_ATTENTION0x06 || | |||
579 | bus->unit_attention.key == UNIT_ATTENTION0x06) && | |||
580 | (buf[0] != INQUIRY0x12 && | |||
581 | buf[0] != REPORT_LUNS0xa0 && | |||
582 | buf[0] != GET_CONFIGURATION0x46 && | |||
583 | buf[0] != GET_EVENT_STATUS_NOTIFICATION0x4a && | |||
584 | ||||
585 | /* | |||
586 | * If we already have a pending unit attention condition, | |||
587 | * report this one before triggering another one. | |||
588 | */ | |||
589 | !(buf[0] == REQUEST_SENSE0x03 && d->sense_is_ua))) { | |||
590 | req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun, | |||
591 | hba_private); | |||
592 | } else if (lun != d->lun || | |||
593 | buf[0] == REPORT_LUNS0xa0 || | |||
594 | (buf[0] == REQUEST_SENSE0x03 && d->sense_len)) { | |||
595 | req = scsi_req_alloc(&reqops_target_command, d, tag, lun, | |||
596 | hba_private); | |||
597 | } else { | |||
598 | req = scsi_device_alloc_req(d, tag, lun, buf, hba_private); | |||
599 | } | |||
600 | } | |||
601 | ||||
602 | req->cmd = cmd; | |||
603 | req->resid = req->cmd.xfer; | |||
604 | ||||
605 | switch (buf[0]) { | |||
606 | case INQUIRY0x12: | |||
607 | trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]); | |||
| ||||
608 | break; | |||
609 | case TEST_UNIT_READY0x00: | |||
610 | trace_scsi_test_unit_ready(d->id, lun, tag); | |||
611 | break; | |||
612 | case REPORT_LUNS0xa0: | |||
613 | trace_scsi_report_luns(d->id, lun, tag); | |||
614 | break; | |||
615 | case REQUEST_SENSE0x03: | |||
616 | trace_scsi_request_sense(d->id, lun, tag); | |||
617 | break; | |||
618 | default: | |||
619 | break; | |||
620 | } | |||
621 | ||||
622 | return req; | |||
623 | } | |||
624 | ||||
625 | uint8_t *scsi_req_get_buf(SCSIRequest *req) | |||
626 | { | |||
627 | return req->ops->get_buf(req); | |||
628 | } | |||
629 | ||||
630 | static void scsi_clear_unit_attention(SCSIRequest *req) | |||
631 | { | |||
632 | SCSISense *ua; | |||
633 | if (req->dev->unit_attention.key != UNIT_ATTENTION0x06 && | |||
634 | req->bus->unit_attention.key != UNIT_ATTENTION0x06) { | |||
635 | return; | |||
636 | } | |||
637 | ||||
638 | /* | |||
639 | * If an INQUIRY command enters the enabled command state, | |||
640 | * the device server shall [not] clear any unit attention condition; | |||
641 | * See also MMC-6, paragraphs 6.5 and 6.6.2. | |||
642 | */ | |||
643 | if (req->cmd.buf[0] == INQUIRY0x12 || | |||
644 | req->cmd.buf[0] == GET_CONFIGURATION0x46 || | |||
645 | req->cmd.buf[0] == GET_EVENT_STATUS_NOTIFICATION0x4a) { | |||
646 | return; | |||
647 | } | |||
648 | ||||
649 | if (req->dev->unit_attention.key == UNIT_ATTENTION0x06) { | |||
650 | ua = &req->dev->unit_attention; | |||
651 | } else { | |||
652 | ua = &req->bus->unit_attention; | |||
653 | } | |||
654 | ||||
655 | /* | |||
656 | * If a REPORT LUNS command enters the enabled command state, [...] | |||
657 | * the device server shall clear any pending unit attention condition | |||
658 | * with an additional sense code of REPORTED LUNS DATA HAS CHANGED. | |||
659 | */ | |||
660 | if (req->cmd.buf[0] == REPORT_LUNS0xa0 && | |||
661 | !(ua->asc == SENSE_CODE(REPORTED_LUNS_CHANGED)sense_code_REPORTED_LUNS_CHANGED.asc && | |||
662 | ua->ascq == SENSE_CODE(REPORTED_LUNS_CHANGED)sense_code_REPORTED_LUNS_CHANGED.ascq)) { | |||
663 | return; | |||
664 | } | |||
665 | ||||
666 | *ua = SENSE_CODE(NO_SENSE)sense_code_NO_SENSE; | |||
667 | } | |||
668 | ||||
669 | int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len) | |||
670 | { | |||
671 | int ret; | |||
672 | ||||
673 | assert(len >= 14)((len >= 14) ? (void) (0) : __assert_fail ("len >= 14", "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c", 673 , __PRETTY_FUNCTION__)); | |||
674 | if (!req->sense_len) { | |||
675 | return 0; | |||
676 | } | |||
677 | ||||
678 | ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true1); | |||
679 | ||||
680 | /* | |||
681 | * FIXME: clearing unit attention conditions upon autosense should be done | |||
682 | * only if the UA_INTLCK_CTRL field in the Control mode page is set to 00b | |||
683 | * (SAM-5, 5.14). | |||
684 | * | |||
685 | * We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and | |||
686 | * 10b for HBAs that do not support it (do not call scsi_req_get_sense). | |||
687 | * Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b. | |||
688 | */ | |||
689 | if (req->dev->sense_is_ua) { | |||
690 | scsi_device_unit_attention_reported(req->dev); | |||
691 | req->dev->sense_len = 0; | |||
692 | req->dev->sense_is_ua = false0; | |||
693 | } | |||
694 | return ret; | |||
695 | } | |||
696 | ||||
697 | int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool_Bool fixed) | |||
698 | { | |||
699 | return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed); | |||
700 | } | |||
701 | ||||
702 | void scsi_req_build_sense(SCSIRequest *req, SCSISense sense) | |||
703 | { | |||
704 | trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag, | |||
705 | sense.key, sense.asc, sense.ascq); | |||
706 | memset(req->sense, 0, 18); | |||
707 | req->sense[0] = 0x70; | |||
708 | req->sense[2] = sense.key; | |||
709 | req->sense[7] = 10; | |||
710 | req->sense[12] = sense.asc; | |||
711 | req->sense[13] = sense.ascq; | |||
712 | req->sense_len = 18; | |||
713 | } | |||
714 | ||||
715 | static void scsi_req_enqueue_internal(SCSIRequest *req) | |||
716 | { | |||
717 | assert(!req->enqueued)((!req->enqueued) ? (void) (0) : __assert_fail ("!req->enqueued" , "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c", 717 , __PRETTY_FUNCTION__)); | |||
718 | scsi_req_ref(req); | |||
719 | if (req->bus->info->get_sg_list) { | |||
720 | req->sg = req->bus->info->get_sg_list(req); | |||
721 | } else { | |||
722 | req->sg = NULL((void*)0); | |||
723 | } | |||
724 | req->enqueued = true1; | |||
725 | QTAILQ_INSERT_TAIL(&req->dev->requests, req, next)do { (req)->next.tqe_next = ((void*)0); (req)->next.tqe_prev = (&req->dev->requests)->tqh_last; *(&req-> dev->requests)->tqh_last = (req); (&req->dev-> requests)->tqh_last = &(req)->next.tqe_next; } while ( 0); | |||
726 | } | |||
727 | ||||
728 | int32_t scsi_req_enqueue(SCSIRequest *req) | |||
729 | { | |||
730 | int32_t rc; | |||
731 | ||||
732 | assert(!req->retry)((!req->retry) ? (void) (0) : __assert_fail ("!req->retry" , "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c", 732 , __PRETTY_FUNCTION__)); | |||
733 | scsi_req_enqueue_internal(req); | |||
734 | scsi_req_ref(req); | |||
735 | rc = req->ops->send_command(req, req->cmd.buf); | |||
736 | scsi_req_unref(req); | |||
737 | return rc; | |||
738 | } | |||
739 | ||||
740 | static void scsi_req_dequeue(SCSIRequest *req) | |||
741 | { | |||
742 | trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag); | |||
743 | req->retry = false0; | |||
744 | if (req->enqueued) { | |||
745 | QTAILQ_REMOVE(&req->dev->requests, req, next)do { if (((req)->next.tqe_next) != ((void*)0)) (req)->next .tqe_next->next.tqe_prev = (req)->next.tqe_prev; else ( &req->dev->requests)->tqh_last = (req)->next. tqe_prev; *(req)->next.tqe_prev = (req)->next.tqe_next; } while ( 0); | |||
746 | req->enqueued = false0; | |||
747 | scsi_req_unref(req); | |||
748 | } | |||
749 | } | |||
750 | ||||
751 | static int scsi_get_performance_length(int num_desc, int type, int data_type) | |||
752 | { | |||
753 | /* MMC-6, paragraph 6.7. */ | |||
754 | switch (type) { | |||
755 | case 0: | |||
756 | if ((data_type & 3) == 0) { | |||
757 | /* Each descriptor is as in Table 295 - Nominal performance. */ | |||
758 | return 16 * num_desc + 8; | |||
759 | } else { | |||
760 | /* Each descriptor is as in Table 296 - Exceptions. */ | |||
761 | return 6 * num_desc + 8; | |||
762 | } | |||
763 | case 1: | |||
764 | case 4: | |||
765 | case 5: | |||
766 | return 8 * num_desc + 8; | |||
767 | case 2: | |||
768 | return 2048 * num_desc + 8; | |||
769 | case 3: | |||
770 | return 16 * num_desc + 8; | |||
771 | default: | |||
772 | return 8; | |||
773 | } | |||
774 | } | |||
775 | ||||
776 | static int ata_passthrough_xfer_unit(SCSIDevice *dev, uint8_t *buf) | |||
777 | { | |||
778 | int byte_block = (buf[2] >> 2) & 0x1; | |||
779 | int type = (buf[2] >> 4) & 0x1; | |||
780 | int xfer_unit; | |||
781 | ||||
782 | if (byte_block) { | |||
783 | if (type) { | |||
784 | xfer_unit = dev->blocksize; | |||
785 | } else { | |||
786 | xfer_unit = 512; | |||
787 | } | |||
788 | } else { | |||
789 | xfer_unit = 1; | |||
790 | } | |||
791 | ||||
792 | return xfer_unit; | |||
793 | } | |||
794 | ||||
795 | static int ata_passthrough_12_xfer_size(SCSIDevice *dev, uint8_t *buf) | |||
796 | { | |||
797 | int length = buf[2] & 0x3; | |||
798 | int xfer; | |||
799 | int unit = ata_passthrough_xfer_unit(dev, buf); | |||
800 | ||||
801 | switch (length) { | |||
802 | case 0: | |||
803 | case 3: /* USB-specific. */ | |||
804 | default: | |||
805 | xfer = 0; | |||
806 | break; | |||
807 | case 1: | |||
808 | xfer = buf[3]; | |||
809 | break; | |||
810 | case 2: | |||
811 | xfer = buf[4]; | |||
812 | break; | |||
813 | } | |||
814 | ||||
815 | return xfer * unit; | |||
816 | } | |||
817 | ||||
818 | static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf) | |||
819 | { | |||
820 | int extend = buf[1] & 0x1; | |||
821 | int length = buf[2] & 0x3; | |||
822 | int xfer; | |||
823 | int unit = ata_passthrough_xfer_unit(dev, buf); | |||
824 | ||||
825 | switch (length) { | |||
826 | case 0: | |||
827 | case 3: /* USB-specific. */ | |||
828 | default: | |||
829 | xfer = 0; | |||
830 | break; | |||
831 | case 1: | |||
832 | xfer = buf[4]; | |||
833 | xfer |= (extend ? buf[3] << 8 : 0); | |||
834 | break; | |||
835 | case 2: | |||
836 | xfer = buf[6]; | |||
837 | xfer |= (extend ? buf[5] << 8 : 0); | |||
838 | break; | |||
839 | } | |||
840 | ||||
841 | return xfer * unit; | |||
842 | } | |||
843 | ||||
844 | uint32_t scsi_data_cdb_length(uint8_t *buf) | |||
845 | { | |||
846 | if ((buf[0] >> 5) == 0 && buf[4] == 0) { | |||
847 | return 256; | |||
848 | } else { | |||
849 | return scsi_cdb_length(buf); | |||
850 | } | |||
851 | } | |||
852 | ||||
853 | uint32_t scsi_cdb_length(uint8_t *buf) | |||
854 | { | |||
855 | switch (buf[0] >> 5) { | |||
856 | case 0: | |||
857 | return buf[4]; | |||
858 | break; | |||
859 | case 1: | |||
860 | case 2: | |||
861 | return lduw_be_p(&buf[7]); | |||
862 | break; | |||
863 | case 4: | |||
864 | return ldl_be_p(&buf[10]) & 0xffffffffULL; | |||
865 | break; | |||
866 | case 5: | |||
867 | return ldl_be_p(&buf[6]) & 0xffffffffULL; | |||
868 | break; | |||
869 | default: | |||
870 | return -1; | |||
871 | } | |||
872 | } | |||
873 | ||||
874 | static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) | |||
875 | { | |||
876 | cmd->xfer = scsi_cdb_length(buf); | |||
877 | switch (buf[0]) { | |||
878 | case TEST_UNIT_READY0x00: | |||
879 | case REWIND0x01: | |||
880 | case START_STOP0x1b: | |||
881 | case SET_CAPACITY0x0b: | |||
882 | case WRITE_FILEMARKS0x10: | |||
883 | case WRITE_FILEMARKS_160x80: | |||
884 | case SPACE0x11: | |||
885 | case RESERVE0x16: | |||
886 | case RELEASE0x17: | |||
887 | case ERASE0x19: | |||
888 | case ALLOW_MEDIUM_REMOVAL0x1e: | |||
889 | case SEEK_100x2b: | |||
890 | case SYNCHRONIZE_CACHE0x35: | |||
891 | case SYNCHRONIZE_CACHE_160x91: | |||
892 | case LOCATE_160x92: | |||
893 | case LOCK_UNLOCK_CACHE0x36: | |||
894 | case SET_CD_SPEED0xbb: | |||
895 | case SET_LIMITS0x33: | |||
896 | case WRITE_LONG_100x3f: | |||
897 | case UPDATE_BLOCK0x3d: | |||
898 | case RESERVE_TRACK0x53: | |||
899 | case SET_READ_AHEAD0xa7: | |||
900 | case PRE_FETCH0x34: | |||
901 | case PRE_FETCH_160x90: | |||
902 | case ALLOW_OVERWRITE0x82: | |||
903 | cmd->xfer = 0; | |||
904 | break; | |||
905 | case VERIFY_100x2f: | |||
906 | case VERIFY_120xaf: | |||
907 | case VERIFY_160x8f: | |||
908 | if ((buf[1] & 2) == 0) { | |||
909 | cmd->xfer = 0; | |||
910 | } else if ((buf[1] & 4) == 1) { | |||
911 | cmd->xfer = 1; | |||
912 | } | |||
913 | cmd->xfer *= dev->blocksize; | |||
914 | break; | |||
915 | case MODE_SENSE0x1a: | |||
916 | break; | |||
917 | case WRITE_SAME_100x41: | |||
918 | case WRITE_SAME_160x93: | |||
919 | cmd->xfer = dev->blocksize; | |||
920 | break; | |||
921 | case READ_CAPACITY_100x25: | |||
922 | cmd->xfer = 8; | |||
923 | break; | |||
924 | case READ_BLOCK_LIMITS0x05: | |||
925 | cmd->xfer = 6; | |||
926 | break; | |||
927 | case SEND_VOLUME_TAG0xb6: | |||
928 | /* GPCMD_SET_STREAMING from multimedia commands. */ | |||
929 | if (dev->type == TYPE_ROM0x05) { | |||
930 | cmd->xfer = buf[10] | (buf[9] << 8); | |||
931 | } else { | |||
932 | cmd->xfer = buf[9] | (buf[8] << 8); | |||
933 | } | |||
934 | break; | |||
935 | case WRITE_60x0a: | |||
936 | /* length 0 means 256 blocks */ | |||
937 | if (cmd->xfer == 0) { | |||
938 | cmd->xfer = 256; | |||
939 | } | |||
940 | case WRITE_100x2a: | |||
941 | case WRITE_VERIFY_100x2e: | |||
942 | case WRITE_120xaa: | |||
943 | case WRITE_VERIFY_120xae: | |||
944 | case WRITE_160x8a: | |||
945 | case WRITE_VERIFY_160x8e: | |||
946 | cmd->xfer *= dev->blocksize; | |||
947 | break; | |||
948 | case READ_60x08: | |||
949 | case READ_REVERSE0x0f: | |||
950 | /* length 0 means 256 blocks */ | |||
951 | if (cmd->xfer == 0) { | |||
952 | cmd->xfer = 256; | |||
953 | } | |||
954 | case READ_100x28: | |||
955 | case RECOVER_BUFFERED_DATA0x14: | |||
956 | case READ_120xa8: | |||
957 | case READ_160x88: | |||
958 | cmd->xfer *= dev->blocksize; | |||
959 | break; | |||
960 | case FORMAT_UNIT0x04: | |||
961 | /* MMC mandates the parameter list to be 12-bytes long. Parameters | |||
962 | * for block devices are restricted to the header right now. */ | |||
963 | if (dev->type == TYPE_ROM0x05 && (buf[1] & 16)) { | |||
964 | cmd->xfer = 12; | |||
965 | } else { | |||
966 | cmd->xfer = (buf[1] & 16) == 0 ? 0 : (buf[1] & 32 ? 8 : 4); | |||
967 | } | |||
968 | break; | |||
969 | case INQUIRY0x12: | |||
970 | case RECEIVE_DIAGNOSTIC0x1c: | |||
971 | case SEND_DIAGNOSTIC0x1d: | |||
972 | cmd->xfer = buf[4] | (buf[3] << 8); | |||
973 | break; | |||
974 | case READ_CD0xbe: | |||
975 | case READ_BUFFER0x3c: | |||
976 | case WRITE_BUFFER0x3b: | |||
977 | case SEND_CUE_SHEET0x5d: | |||
978 | cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16); | |||
979 | break; | |||
980 | case PERSISTENT_RESERVE_OUT0x5f: | |||
981 | cmd->xfer = ldl_be_p(&buf[5]) & 0xffffffffULL; | |||
982 | break; | |||
983 | case ERASE_120xac: | |||
984 | if (dev->type == TYPE_ROM0x05) { | |||
985 | /* MMC command GET PERFORMANCE. */ | |||
986 | cmd->xfer = scsi_get_performance_length(buf[9] | (buf[8] << 8), | |||
987 | buf[10], buf[1] & 0x1f); | |||
988 | } | |||
989 | break; | |||
990 | case MECHANISM_STATUS0xbd: | |||
991 | case READ_DVD_STRUCTURE0xad: | |||
992 | case SEND_DVD_STRUCTURE0xbf: | |||
993 | case MAINTENANCE_OUT0xa4: | |||
994 | case MAINTENANCE_IN0xa3: | |||
995 | if (dev->type == TYPE_ROM0x05) { | |||
996 | /* GPCMD_REPORT_KEY and GPCMD_SEND_KEY from multi media commands */ | |||
997 | cmd->xfer = buf[9] | (buf[8] << 8); | |||
998 | } | |||
999 | break; | |||
1000 | case ATA_PASSTHROUGH_120xa1: | |||
1001 | if (dev->type == TYPE_ROM0x05) { | |||
1002 | /* BLANK command of MMC */ | |||
1003 | cmd->xfer = 0; | |||
1004 | } else { | |||
1005 | cmd->xfer = ata_passthrough_12_xfer_size(dev, buf); | |||
1006 | } | |||
1007 | break; | |||
1008 | case ATA_PASSTHROUGH_160x85: | |||
1009 | cmd->xfer = ata_passthrough_16_xfer_size(dev, buf); | |||
1010 | break; | |||
1011 | } | |||
1012 | return 0; | |||
1013 | } | |||
1014 | ||||
1015 | static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) | |||
1016 | { | |||
1017 | switch (buf[0]) { | |||
1018 | /* stream commands */ | |||
1019 | case ERASE_120xac: | |||
1020 | case ERASE_160x93: | |||
1021 | cmd->xfer = 0; | |||
1022 | break; | |||
1023 | case READ_60x08: | |||
1024 | case READ_REVERSE0x0f: | |||
1025 | case RECOVER_BUFFERED_DATA0x14: | |||
1026 | case WRITE_60x0a: | |||
1027 | cmd->xfer = buf[4] | (buf[3] << 8) | (buf[2] << 16); | |||
1028 | if (buf[1] & 0x01) { /* fixed */ | |||
1029 | cmd->xfer *= dev->blocksize; | |||
1030 | } | |||
1031 | break; | |||
1032 | case READ_160x88: | |||
1033 | case READ_REVERSE_160x81: | |||
1034 | case VERIFY_160x8f: | |||
1035 | case WRITE_160x8a: | |||
1036 | cmd->xfer = buf[14] | (buf[13] << 8) | (buf[12] << 16); | |||
1037 | if (buf[1] & 0x01) { /* fixed */ | |||
1038 | cmd->xfer *= dev->blocksize; | |||
1039 | } | |||
1040 | break; | |||
1041 | case REWIND0x01: | |||
1042 | case LOAD_UNLOAD0x1b: | |||
1043 | cmd->xfer = 0; | |||
1044 | break; | |||
1045 | case SPACE_160x91: | |||
1046 | cmd->xfer = buf[13] | (buf[12] << 8); | |||
1047 | break; | |||
1048 | case READ_POSITION0x34: | |||
1049 | switch (buf[1] & 0x1f) /* operation code */ { | |||
1050 | case SHORT_FORM_BLOCK_ID0x00: | |||
1051 | case SHORT_FORM_VENDOR_SPECIFIC0x01: | |||
1052 | cmd->xfer = 20; | |||
1053 | break; | |||
1054 | case LONG_FORM0x06: | |||
1055 | cmd->xfer = 32; | |||
1056 | break; | |||
1057 | case EXTENDED_FORM0x08: | |||
1058 | cmd->xfer = buf[8] | (buf[7] << 8); | |||
1059 | break; | |||
1060 | default: | |||
1061 | return -1; | |||
1062 | } | |||
1063 | ||||
1064 | break; | |||
1065 | case FORMAT_UNIT0x04: | |||
1066 | cmd->xfer = buf[4] | (buf[3] << 8); | |||
1067 | break; | |||
1068 | /* generic commands */ | |||
1069 | default: | |||
1070 | return scsi_req_length(cmd, dev, buf); | |||
1071 | } | |||
1072 | return 0; | |||
1073 | } | |||
1074 | ||||
1075 | static int scsi_req_medium_changer_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) | |||
1076 | { | |||
1077 | switch (buf[0]) { | |||
1078 | /* medium changer commands */ | |||
1079 | case EXCHANGE_MEDIUM0xa6: | |||
1080 | case INITIALIZE_ELEMENT_STATUS0x07: | |||
1081 | case INITIALIZE_ELEMENT_STATUS_WITH_RANGE0x37: | |||
1082 | case MOVE_MEDIUM0xa5: | |||
1083 | case POSITION_TO_ELEMENT0x2b: | |||
1084 | cmd->xfer = 0; | |||
1085 | break; | |||
1086 | case READ_ELEMENT_STATUS0xb8: | |||
1087 | cmd->xfer = buf[9] | (buf[8] << 8) | (buf[7] << 16); | |||
1088 | break; | |||
1089 | ||||
1090 | /* generic commands */ | |||
1091 | default: | |||
1092 | return scsi_req_length(cmd, dev, buf); | |||
1093 | } | |||
1094 | return 0; | |||
1095 | } | |||
1096 | ||||
1097 | ||||
1098 | static void scsi_cmd_xfer_mode(SCSICommand *cmd) | |||
1099 | { | |||
1100 | if (!cmd->xfer) { | |||
1101 | cmd->mode = SCSI_XFER_NONE; | |||
1102 | return; | |||
1103 | } | |||
1104 | switch (cmd->buf[0]) { | |||
1105 | case WRITE_60x0a: | |||
1106 | case WRITE_100x2a: | |||
1107 | case WRITE_VERIFY_100x2e: | |||
1108 | case WRITE_120xaa: | |||
1109 | case WRITE_VERIFY_120xae: | |||
1110 | case WRITE_160x8a: | |||
1111 | case WRITE_VERIFY_160x8e: | |||
1112 | case VERIFY_100x2f: | |||
1113 | case VERIFY_120xaf: | |||
1114 | case VERIFY_160x8f: | |||
1115 | case COPY0x18: | |||
1116 | case COPY_VERIFY0x3a: | |||
1117 | case COMPARE0x39: | |||
1118 | case CHANGE_DEFINITION0x40: | |||
1119 | case LOG_SELECT0x4c: | |||
1120 | case MODE_SELECT0x15: | |||
1121 | case MODE_SELECT_100x55: | |||
1122 | case SEND_DIAGNOSTIC0x1d: | |||
1123 | case WRITE_BUFFER0x3b: | |||
1124 | case FORMAT_UNIT0x04: | |||
1125 | case REASSIGN_BLOCKS0x07: | |||
1126 | case SEARCH_EQUAL0x31: | |||
1127 | case SEARCH_HIGH0x30: | |||
1128 | case SEARCH_LOW0x32: | |||
1129 | case UPDATE_BLOCK0x3d: | |||
1130 | case WRITE_LONG_100x3f: | |||
1131 | case WRITE_SAME_100x41: | |||
1132 | case WRITE_SAME_160x93: | |||
1133 | case UNMAP0x42: | |||
1134 | case SEARCH_HIGH_120xb0: | |||
1135 | case SEARCH_EQUAL_120xb1: | |||
1136 | case SEARCH_LOW_120xb2: | |||
1137 | case MEDIUM_SCAN0x38: | |||
1138 | case SEND_VOLUME_TAG0xb6: | |||
1139 | case SEND_CUE_SHEET0x5d: | |||
1140 | case SEND_DVD_STRUCTURE0xbf: | |||
1141 | case PERSISTENT_RESERVE_OUT0x5f: | |||
1142 | case MAINTENANCE_OUT0xa4: | |||
1143 | cmd->mode = SCSI_XFER_TO_DEV; | |||
1144 | break; | |||
1145 | case ATA_PASSTHROUGH_120xa1: | |||
1146 | case ATA_PASSTHROUGH_160x85: | |||
1147 | /* T_DIR */ | |||
1148 | cmd->mode = (cmd->buf[2] & 0x8) ? | |||
1149 | SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV; | |||
1150 | break; | |||
1151 | default: | |||
1152 | cmd->mode = SCSI_XFER_FROM_DEV; | |||
1153 | break; | |||
1154 | } | |||
1155 | } | |||
1156 | ||||
1157 | static uint64_t scsi_cmd_lba(SCSICommand *cmd) | |||
1158 | { | |||
1159 | uint8_t *buf = cmd->buf; | |||
1160 | uint64_t lba; | |||
1161 | ||||
1162 | switch (buf[0] >> 5) { | |||
1163 | case 0: | |||
1164 | lba = ldl_be_p(&buf[0]) & 0x1fffff; | |||
1165 | break; | |||
1166 | case 1: | |||
1167 | case 2: | |||
1168 | case 5: | |||
1169 | lba = ldl_be_p(&buf[2]) & 0xffffffffULL; | |||
1170 | break; | |||
1171 | case 4: | |||
1172 | lba = ldq_be_p(&buf[2]); | |||
1173 | break; | |||
1174 | default: | |||
1175 | lba = -1; | |||
1176 | ||||
1177 | } | |||
1178 | return lba; | |||
1179 | } | |||
1180 | ||||
1181 | int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) | |||
1182 | { | |||
1183 | int rc; | |||
1184 | ||||
1185 | switch (buf[0] >> 5) { | |||
1186 | case 0: | |||
1187 | cmd->len = 6; | |||
1188 | break; | |||
1189 | case 1: | |||
1190 | case 2: | |||
1191 | cmd->len = 10; | |||
1192 | break; | |||
1193 | case 4: | |||
1194 | cmd->len = 16; | |||
1195 | break; | |||
1196 | case 5: | |||
1197 | cmd->len = 12; | |||
1198 | break; | |||
1199 | default: | |||
1200 | return -1; | |||
1201 | } | |||
1202 | ||||
1203 | switch (dev->type) { | |||
1204 | case TYPE_TAPE0x01: | |||
1205 | rc = scsi_req_stream_length(cmd, dev, buf); | |||
1206 | break; | |||
1207 | case TYPE_MEDIUM_CHANGER0x08: | |||
1208 | rc = scsi_req_medium_changer_length(cmd, dev, buf); | |||
1209 | break; | |||
1210 | default: | |||
1211 | rc = scsi_req_length(cmd, dev, buf); | |||
1212 | break; | |||
1213 | } | |||
1214 | ||||
1215 | if (rc != 0) | |||
1216 | return rc; | |||
1217 | ||||
1218 | memcpy(cmd->buf, buf, cmd->len); | |||
1219 | scsi_cmd_xfer_mode(cmd); | |||
1220 | cmd->lba = scsi_cmd_lba(cmd); | |||
1221 | return 0; | |||
1222 | } | |||
1223 | ||||
1224 | void scsi_device_report_change(SCSIDevice *dev, SCSISense sense) | |||
1225 | { | |||
1226 | SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSIBus, qbus)]; ({ const typeof(((SCSIBus *) 0)->qbus) *__mptr = (dev->qdev.parent_bus); (SCSIBus *) ((char *) __mptr - __builtin_offsetof(SCSIBus, qbus));}); })); | |||
1227 | ||||
1228 | scsi_device_set_ua(dev, sense); | |||
1229 | if (bus->info->change) { | |||
1230 | bus->info->change(bus, dev, sense); | |||
1231 | } | |||
1232 | } | |||
1233 | ||||
1234 | /* | |||
1235 | * Predefined sense codes | |||
1236 | */ | |||
1237 | ||||
1238 | /* No sense data available */ | |||
1239 | const struct SCSISense sense_code_NO_SENSE = { | |||
1240 | .key = NO_SENSE0x00 , .asc = 0x00 , .ascq = 0x00 | |||
1241 | }; | |||
1242 | ||||
1243 | /* LUN not ready, Manual intervention required */ | |||
1244 | const struct SCSISense sense_code_LUN_NOT_READY = { | |||
1245 | .key = NOT_READY0x02, .asc = 0x04, .ascq = 0x03 | |||
1246 | }; | |||
1247 | ||||
1248 | /* LUN not ready, Medium not present */ | |||
1249 | const struct SCSISense sense_code_NO_MEDIUM = { | |||
1250 | .key = NOT_READY0x02, .asc = 0x3a, .ascq = 0x00 | |||
1251 | }; | |||
1252 | ||||
1253 | /* LUN not ready, medium removal prevented */ | |||
1254 | const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = { | |||
1255 | .key = NOT_READY0x02, .asc = 0x53, .ascq = 0x02 | |||
1256 | }; | |||
1257 | ||||
1258 | /* Hardware error, internal target failure */ | |||
1259 | const struct SCSISense sense_code_TARGET_FAILURE = { | |||
1260 | .key = HARDWARE_ERROR0x04, .asc = 0x44, .ascq = 0x00 | |||
1261 | }; | |||
1262 | ||||
1263 | /* Illegal request, invalid command operation code */ | |||
1264 | const struct SCSISense sense_code_INVALID_OPCODE = { | |||
1265 | .key = ILLEGAL_REQUEST0x05, .asc = 0x20, .ascq = 0x00 | |||
1266 | }; | |||
1267 | ||||
1268 | /* Illegal request, LBA out of range */ | |||
1269 | const struct SCSISense sense_code_LBA_OUT_OF_RANGE = { | |||
1270 | .key = ILLEGAL_REQUEST0x05, .asc = 0x21, .ascq = 0x00 | |||
1271 | }; | |||
1272 | ||||
1273 | /* Illegal request, Invalid field in CDB */ | |||
1274 | const struct SCSISense sense_code_INVALID_FIELD = { | |||
1275 | .key = ILLEGAL_REQUEST0x05, .asc = 0x24, .ascq = 0x00 | |||
1276 | }; | |||
1277 | ||||
1278 | /* Illegal request, Invalid field in parameter list */ | |||
1279 | const struct SCSISense sense_code_INVALID_PARAM = { | |||
1280 | .key = ILLEGAL_REQUEST0x05, .asc = 0x26, .ascq = 0x00 | |||
1281 | }; | |||
1282 | ||||
1283 | /* Illegal request, Parameter list length error */ | |||
1284 | const struct SCSISense sense_code_INVALID_PARAM_LEN = { | |||
1285 | .key = ILLEGAL_REQUEST0x05, .asc = 0x1a, .ascq = 0x00 | |||
1286 | }; | |||
1287 | ||||
1288 | /* Illegal request, LUN not supported */ | |||
1289 | const struct SCSISense sense_code_LUN_NOT_SUPPORTED = { | |||
1290 | .key = ILLEGAL_REQUEST0x05, .asc = 0x25, .ascq = 0x00 | |||
1291 | }; | |||
1292 | ||||
1293 | /* Illegal request, Saving parameters not supported */ | |||
1294 | const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = { | |||
1295 | .key = ILLEGAL_REQUEST0x05, .asc = 0x39, .ascq = 0x00 | |||
1296 | }; | |||
1297 | ||||
1298 | /* Illegal request, Incompatible medium installed */ | |||
1299 | const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = { | |||
1300 | .key = ILLEGAL_REQUEST0x05, .asc = 0x30, .ascq = 0x00 | |||
1301 | }; | |||
1302 | ||||
1303 | /* Illegal request, medium removal prevented */ | |||
1304 | const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = { | |||
1305 | .key = ILLEGAL_REQUEST0x05, .asc = 0x53, .ascq = 0x02 | |||
1306 | }; | |||
1307 | ||||
1308 | /* Illegal request, Invalid Transfer Tag */ | |||
1309 | const struct SCSISense sense_code_INVALID_TAG = { | |||
1310 | .key = ILLEGAL_REQUEST0x05, .asc = 0x4b, .ascq = 0x01 | |||
1311 | }; | |||
1312 | ||||
1313 | /* Command aborted, I/O process terminated */ | |||
1314 | const struct SCSISense sense_code_IO_ERROR = { | |||
1315 | .key = ABORTED_COMMAND0x0b, .asc = 0x00, .ascq = 0x06 | |||
1316 | }; | |||
1317 | ||||
1318 | /* Command aborted, I_T Nexus loss occurred */ | |||
1319 | const struct SCSISense sense_code_I_T_NEXUS_LOSS = { | |||
1320 | .key = ABORTED_COMMAND0x0b, .asc = 0x29, .ascq = 0x07 | |||
1321 | }; | |||
1322 | ||||
1323 | /* Command aborted, Logical Unit failure */ | |||
1324 | const struct SCSISense sense_code_LUN_FAILURE = { | |||
1325 | .key = ABORTED_COMMAND0x0b, .asc = 0x3e, .ascq = 0x01 | |||
1326 | }; | |||
1327 | ||||
1328 | /* Command aborted, Overlapped Commands Attempted */ | |||
1329 | const struct SCSISense sense_code_OVERLAPPED_COMMANDS = { | |||
1330 | .key = ABORTED_COMMAND0x0b, .asc = 0x4e, .ascq = 0x00 | |||
1331 | }; | |||
1332 | ||||
1333 | /* Unit attention, Capacity data has changed */ | |||
1334 | const struct SCSISense sense_code_CAPACITY_CHANGED = { | |||
1335 | .key = UNIT_ATTENTION0x06, .asc = 0x2a, .ascq = 0x09 | |||
1336 | }; | |||
1337 | ||||
1338 | /* Unit attention, Power on, reset or bus device reset occurred */ | |||
1339 | const struct SCSISense sense_code_RESET = { | |||
1340 | .key = UNIT_ATTENTION0x06, .asc = 0x29, .ascq = 0x00 | |||
1341 | }; | |||
1342 | ||||
1343 | /* Unit attention, No medium */ | |||
1344 | const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = { | |||
1345 | .key = UNIT_ATTENTION0x06, .asc = 0x3a, .ascq = 0x00 | |||
1346 | }; | |||
1347 | ||||
1348 | /* Unit attention, Medium may have changed */ | |||
1349 | const struct SCSISense sense_code_MEDIUM_CHANGED = { | |||
1350 | .key = UNIT_ATTENTION0x06, .asc = 0x28, .ascq = 0x00 | |||
1351 | }; | |||
1352 | ||||
1353 | /* Unit attention, Reported LUNs data has changed */ | |||
1354 | const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = { | |||
1355 | .key = UNIT_ATTENTION0x06, .asc = 0x3f, .ascq = 0x0e | |||
1356 | }; | |||
1357 | ||||
1358 | /* Unit attention, Device internal reset */ | |||
1359 | const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = { | |||
1360 | .key = UNIT_ATTENTION0x06, .asc = 0x29, .ascq = 0x04 | |||
1361 | }; | |||
1362 | ||||
1363 | /* Data Protection, Write Protected */ | |||
1364 | const struct SCSISense sense_code_WRITE_PROTECTED = { | |||
1365 | .key = DATA_PROTECT0x07, .asc = 0x27, .ascq = 0x00 | |||
1366 | }; | |||
1367 | ||||
1368 | /* | |||
1369 | * scsi_build_sense | |||
1370 | * | |||
1371 | * Convert between fixed and descriptor sense buffers | |||
1372 | */ | |||
1373 | int scsi_build_sense(uint8_t *in_buf, int in_len, | |||
1374 | uint8_t *buf, int len, bool_Bool fixed) | |||
1375 | { | |||
1376 | bool_Bool fixed_in; | |||
1377 | SCSISense sense; | |||
1378 | if (!fixed && len < 8) { | |||
1379 | return 0; | |||
1380 | } | |||
1381 | ||||
1382 | if (in_len == 0) { | |||
1383 | sense.key = NO_SENSE0x00; | |||
1384 | sense.asc = 0; | |||
1385 | sense.ascq = 0; | |||
1386 | } else { | |||
1387 | fixed_in = (in_buf[0] & 2) == 0; | |||
1388 | ||||
1389 | if (fixed == fixed_in) { | |||
1390 | memcpy(buf, in_buf, MIN(len, in_len)(((len) < (in_len)) ? (len) : (in_len))); | |||
1391 | return MIN(len, in_len)(((len) < (in_len)) ? (len) : (in_len)); | |||
1392 | } | |||
1393 | ||||
1394 | if (fixed_in) { | |||
1395 | sense.key = in_buf[2]; | |||
1396 | sense.asc = in_buf[12]; | |||
1397 | sense.ascq = in_buf[13]; | |||
1398 | } else { | |||
1399 | sense.key = in_buf[1]; | |||
1400 | sense.asc = in_buf[2]; | |||
1401 | sense.ascq = in_buf[3]; | |||
1402 | } | |||
1403 | } | |||
1404 | ||||
1405 | memset(buf, 0, len); | |||
1406 | if (fixed) { | |||
1407 | /* Return fixed format sense buffer */ | |||
1408 | buf[0] = 0x70; | |||
1409 | buf[2] = sense.key; | |||
1410 | buf[7] = 10; | |||
1411 | buf[12] = sense.asc; | |||
1412 | buf[13] = sense.ascq; | |||
1413 | return MIN(len, SCSI_SENSE_LEN)(((len) < (18)) ? (len) : (18)); | |||
1414 | } else { | |||
1415 | /* Return descriptor format sense buffer */ | |||
1416 | buf[0] = 0x72; | |||
1417 | buf[1] = sense.key; | |||
1418 | buf[2] = sense.asc; | |||
1419 | buf[3] = sense.ascq; | |||
1420 | return 8; | |||
1421 | } | |||
1422 | } | |||
1423 | ||||
1424 | static const char *scsi_command_name(uint8_t cmd) | |||
1425 | { | |||
1426 | static const char *names[] = { | |||
1427 | [ TEST_UNIT_READY0x00 ] = "TEST_UNIT_READY", | |||
1428 | [ REWIND0x01 ] = "REWIND", | |||
1429 | [ REQUEST_SENSE0x03 ] = "REQUEST_SENSE", | |||
1430 | [ FORMAT_UNIT0x04 ] = "FORMAT_UNIT", | |||
1431 | [ READ_BLOCK_LIMITS0x05 ] = "READ_BLOCK_LIMITS", | |||
1432 | [ REASSIGN_BLOCKS0x07 ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS", | |||
1433 | /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */ | |||
1434 | [ READ_60x08 ] = "READ_6", | |||
1435 | [ WRITE_60x0a ] = "WRITE_6", | |||
1436 | [ SET_CAPACITY0x0b ] = "SET_CAPACITY", | |||
1437 | [ READ_REVERSE0x0f ] = "READ_REVERSE", | |||
1438 | [ WRITE_FILEMARKS0x10 ] = "WRITE_FILEMARKS", | |||
1439 | [ SPACE0x11 ] = "SPACE", | |||
1440 | [ INQUIRY0x12 ] = "INQUIRY", | |||
1441 | [ RECOVER_BUFFERED_DATA0x14 ] = "RECOVER_BUFFERED_DATA", | |||
1442 | [ MAINTENANCE_IN0xa3 ] = "MAINTENANCE_IN", | |||
1443 | [ MAINTENANCE_OUT0xa4 ] = "MAINTENANCE_OUT", | |||
1444 | [ MODE_SELECT0x15 ] = "MODE_SELECT", | |||
1445 | [ RESERVE0x16 ] = "RESERVE", | |||
1446 | [ RELEASE0x17 ] = "RELEASE", | |||
1447 | [ COPY0x18 ] = "COPY", | |||
1448 | [ ERASE0x19 ] = "ERASE", | |||
1449 | [ MODE_SENSE0x1a ] = "MODE_SENSE", | |||
1450 | [ START_STOP0x1b ] = "START_STOP/LOAD_UNLOAD", | |||
1451 | /* LOAD_UNLOAD and START_STOP use the same operation code */ | |||
1452 | [ RECEIVE_DIAGNOSTIC0x1c ] = "RECEIVE_DIAGNOSTIC", | |||
1453 | [ SEND_DIAGNOSTIC0x1d ] = "SEND_DIAGNOSTIC", | |||
1454 | [ ALLOW_MEDIUM_REMOVAL0x1e ] = "ALLOW_MEDIUM_REMOVAL", | |||
1455 | [ READ_CAPACITY_100x25 ] = "READ_CAPACITY_10", | |||
1456 | [ READ_100x28 ] = "READ_10", | |||
1457 | [ WRITE_100x2a ] = "WRITE_10", | |||
1458 | [ SEEK_100x2b ] = "SEEK_10/POSITION_TO_ELEMENT", | |||
1459 | /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */ | |||
1460 | [ WRITE_VERIFY_100x2e ] = "WRITE_VERIFY_10", | |||
1461 | [ VERIFY_100x2f ] = "VERIFY_10", | |||
1462 | [ SEARCH_HIGH0x30 ] = "SEARCH_HIGH", | |||
1463 | [ SEARCH_EQUAL0x31 ] = "SEARCH_EQUAL", | |||
1464 | [ SEARCH_LOW0x32 ] = "SEARCH_LOW", | |||
1465 | [ SET_LIMITS0x33 ] = "SET_LIMITS", | |||
1466 | [ PRE_FETCH0x34 ] = "PRE_FETCH/READ_POSITION", | |||
1467 | /* READ_POSITION and PRE_FETCH use the same operation code */ | |||
1468 | [ SYNCHRONIZE_CACHE0x35 ] = "SYNCHRONIZE_CACHE", | |||
1469 | [ LOCK_UNLOCK_CACHE0x36 ] = "LOCK_UNLOCK_CACHE", | |||
1470 | [ READ_DEFECT_DATA0x37 ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE", | |||
1471 | /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */ | |||
1472 | [ MEDIUM_SCAN0x38 ] = "MEDIUM_SCAN", | |||
1473 | [ COMPARE0x39 ] = "COMPARE", | |||
1474 | [ COPY_VERIFY0x3a ] = "COPY_VERIFY", | |||
1475 | [ WRITE_BUFFER0x3b ] = "WRITE_BUFFER", | |||
1476 | [ READ_BUFFER0x3c ] = "READ_BUFFER", | |||
1477 | [ UPDATE_BLOCK0x3d ] = "UPDATE_BLOCK", | |||
1478 | [ READ_LONG_100x3e ] = "READ_LONG_10", | |||
1479 | [ WRITE_LONG_100x3f ] = "WRITE_LONG_10", | |||
1480 | [ CHANGE_DEFINITION0x40 ] = "CHANGE_DEFINITION", | |||
1481 | [ WRITE_SAME_100x41 ] = "WRITE_SAME_10", | |||
1482 | [ UNMAP0x42 ] = "UNMAP", | |||
1483 | [ READ_TOC0x43 ] = "READ_TOC", | |||
1484 | [ REPORT_DENSITY_SUPPORT0x44 ] = "REPORT_DENSITY_SUPPORT", | |||
1485 | [ SANITIZE0x48 ] = "SANITIZE", | |||
1486 | [ GET_CONFIGURATION0x46 ] = "GET_CONFIGURATION", | |||
1487 | [ LOG_SELECT0x4c ] = "LOG_SELECT", | |||
1488 | [ LOG_SENSE0x4d ] = "LOG_SENSE", | |||
1489 | [ MODE_SELECT_100x55 ] = "MODE_SELECT_10", | |||
1490 | [ RESERVE_100x56 ] = "RESERVE_10", | |||
1491 | [ RELEASE_100x57 ] = "RELEASE_10", | |||
1492 | [ MODE_SENSE_100x5a ] = "MODE_SENSE_10", | |||
1493 | [ PERSISTENT_RESERVE_IN0x5e ] = "PERSISTENT_RESERVE_IN", | |||
1494 | [ PERSISTENT_RESERVE_OUT0x5f ] = "PERSISTENT_RESERVE_OUT", | |||
1495 | [ WRITE_FILEMARKS_160x80 ] = "WRITE_FILEMARKS_16", | |||
1496 | [ EXTENDED_COPY0x83 ] = "EXTENDED_COPY", | |||
1497 | [ ATA_PASSTHROUGH_160x85 ] = "ATA_PASSTHROUGH_16", | |||
1498 | [ ACCESS_CONTROL_IN0x86 ] = "ACCESS_CONTROL_IN", | |||
1499 | [ ACCESS_CONTROL_OUT0x87 ] = "ACCESS_CONTROL_OUT", | |||
1500 | [ READ_160x88 ] = "READ_16", | |||
1501 | [ COMPARE_AND_WRITE0x89 ] = "COMPARE_AND_WRITE", | |||
1502 | [ WRITE_160x8a ] = "WRITE_16", | |||
1503 | [ WRITE_VERIFY_160x8e ] = "WRITE_VERIFY_16", | |||
1504 | [ VERIFY_160x8f ] = "VERIFY_16", | |||
1505 | [ PRE_FETCH_160x90 ] = "PRE_FETCH_16", | |||
1506 | [ SYNCHRONIZE_CACHE_160x91 ] = "SPACE_16/SYNCHRONIZE_CACHE_16", | |||
1507 | /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */ | |||
1508 | [ LOCATE_160x92 ] = "LOCATE_16", | |||
1509 | [ WRITE_SAME_160x93 ] = "ERASE_16/WRITE_SAME_16", | |||
1510 | /* ERASE_16 and WRITE_SAME_16 use the same operation code */ | |||
1511 | [ SERVICE_ACTION_IN_160x9e ] = "SERVICE_ACTION_IN_16", | |||
1512 | [ WRITE_LONG_160x9f ] = "WRITE_LONG_16", | |||
1513 | [ REPORT_LUNS0xa0 ] = "REPORT_LUNS", | |||
1514 | [ ATA_PASSTHROUGH_120xa1 ] = "BLANK/ATA_PASSTHROUGH_12", | |||
1515 | [ MOVE_MEDIUM0xa5 ] = "MOVE_MEDIUM", | |||
1516 | [ EXCHANGE_MEDIUM0xa6 ] = "EXCHANGE MEDIUM", | |||
1517 | [ READ_120xa8 ] = "READ_12", | |||
1518 | [ WRITE_120xaa ] = "WRITE_12", | |||
1519 | [ ERASE_120xac ] = "ERASE_12/GET_PERFORMANCE", | |||
1520 | /* ERASE_12 and GET_PERFORMANCE use the same operation code */ | |||
1521 | [ SERVICE_ACTION_IN_120xab ] = "SERVICE_ACTION_IN_12", | |||
1522 | [ WRITE_VERIFY_120xae ] = "WRITE_VERIFY_12", | |||
1523 | [ VERIFY_120xaf ] = "VERIFY_12", | |||
1524 | [ SEARCH_HIGH_120xb0 ] = "SEARCH_HIGH_12", | |||
1525 | [ SEARCH_EQUAL_120xb1 ] = "SEARCH_EQUAL_12", | |||
1526 | [ SEARCH_LOW_120xb2 ] = "SEARCH_LOW_12", | |||
1527 | [ READ_ELEMENT_STATUS0xb8 ] = "READ_ELEMENT_STATUS", | |||
1528 | [ SEND_VOLUME_TAG0xb6 ] = "SEND_VOLUME_TAG/SET_STREAMING", | |||
1529 | /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */ | |||
1530 | [ READ_CD0xbe ] = "READ_CD", | |||
1531 | [ READ_DEFECT_DATA_120xb7 ] = "READ_DEFECT_DATA_12", | |||
1532 | [ READ_DVD_STRUCTURE0xad ] = "READ_DVD_STRUCTURE", | |||
1533 | [ RESERVE_TRACK0x53 ] = "RESERVE_TRACK", | |||
1534 | [ SEND_CUE_SHEET0x5d ] = "SEND_CUE_SHEET", | |||
1535 | [ SEND_DVD_STRUCTURE0xbf ] = "SEND_DVD_STRUCTURE", | |||
1536 | [ SET_CD_SPEED0xbb ] = "SET_CD_SPEED", | |||
1537 | [ SET_READ_AHEAD0xa7 ] = "SET_READ_AHEAD", | |||
1538 | [ ALLOW_OVERWRITE0x82 ] = "ALLOW_OVERWRITE", | |||
1539 | [ MECHANISM_STATUS0xbd ] = "MECHANISM_STATUS", | |||
1540 | }; | |||
1541 | ||||
1542 | if (cmd >= ARRAY_SIZE(names)(sizeof(names) / sizeof((names)[0])) || names[cmd] == NULL((void*)0)) | |||
1543 | return "*UNKNOWN*"; | |||
1544 | return names[cmd]; | |||
1545 | } | |||
1546 | ||||
1547 | SCSIRequest *scsi_req_ref(SCSIRequest *req) | |||
1548 | { | |||
1549 | assert(req->refcount > 0)((req->refcount > 0) ? (void) (0) : __assert_fail ("req->refcount > 0" , "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c", 1549 , __PRETTY_FUNCTION__)); | |||
1550 | req->refcount++; | |||
1551 | return req; | |||
1552 | } | |||
1553 | ||||
1554 | void scsi_req_unref(SCSIRequest *req) | |||
1555 | { | |||
1556 | assert(req->refcount > 0)((req->refcount > 0) ? (void) (0) : __assert_fail ("req->refcount > 0" , "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c", 1556 , __PRETTY_FUNCTION__)); | |||
1557 | if (--req->refcount == 0) { | |||
1558 | BusState *qbus = req->dev->qdev.parent_bus; | |||
1559 | SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, qbus)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSIBus, qbus)]; ({ const typeof(((SCSIBus *) 0)->qbus) *__mptr = (qbus); (SCSIBus *) ((char *) __mptr - __builtin_offsetof(SCSIBus, qbus));});})); | |||
1560 | ||||
1561 | if (bus->info->free_request && req->hba_private) { | |||
1562 | bus->info->free_request(bus, req->hba_private); | |||
1563 | } | |||
1564 | if (req->ops->free_req) { | |||
1565 | req->ops->free_req(req); | |||
1566 | } | |||
1567 | object_unref(OBJECT(req->dev)((Object *)(req->dev))); | |||
1568 | object_unref(OBJECT(qbus->parent)((Object *)(qbus->parent))); | |||
1569 | g_free(req); | |||
1570 | } | |||
1571 | } | |||
1572 | ||||
1573 | /* Tell the device that we finished processing this chunk of I/O. It | |||
1574 | will start the next chunk or complete the command. */ | |||
1575 | void scsi_req_continue(SCSIRequest *req) | |||
1576 | { | |||
1577 | if (req->io_canceled) { | |||
1578 | trace_scsi_req_continue_canceled(req->dev->id, req->lun, req->tag); | |||
1579 | return; | |||
1580 | } | |||
1581 | trace_scsi_req_continue(req->dev->id, req->lun, req->tag); | |||
1582 | if (req->cmd.mode == SCSI_XFER_TO_DEV) { | |||
1583 | req->ops->write_data(req); | |||
1584 | } else { | |||
1585 | req->ops->read_data(req); | |||
1586 | } | |||
1587 | } | |||
1588 | ||||
1589 | /* Called by the devices when data is ready for the HBA. The HBA should | |||
1590 | start a DMA operation to read or fill the device's data buffer. | |||
1591 | Once it completes, calling scsi_req_continue will restart I/O. */ | |||
1592 | void scsi_req_data(SCSIRequest *req, int len) | |||
1593 | { | |||
1594 | uint8_t *buf; | |||
1595 | if (req->io_canceled) { | |||
1596 | trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len); | |||
1597 | return; | |||
1598 | } | |||
1599 | trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); | |||
1600 | assert(req->cmd.mode != SCSI_XFER_NONE)((req->cmd.mode != SCSI_XFER_NONE) ? (void) (0) : __assert_fail ("req->cmd.mode != SCSI_XFER_NONE", "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 1600, __PRETTY_FUNCTION__)); | |||
1601 | if (!req->sg) { | |||
1602 | req->resid -= len; | |||
1603 | req->bus->info->transfer_data(req, len); | |||
1604 | return; | |||
1605 | } | |||
1606 | ||||
1607 | /* If the device calls scsi_req_data and the HBA specified a | |||
1608 | * scatter/gather list, the transfer has to happen in a single | |||
1609 | * step. */ | |||
1610 | assert(!req->dma_started)((!req->dma_started) ? (void) (0) : __assert_fail ("!req->dma_started" , "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c", 1610 , __PRETTY_FUNCTION__)); | |||
1611 | req->dma_started = true1; | |||
1612 | ||||
1613 | buf = scsi_req_get_buf(req); | |||
1614 | if (req->cmd.mode == SCSI_XFER_FROM_DEV) { | |||
1615 | req->resid = dma_buf_read(buf, len, req->sg); | |||
1616 | } else { | |||
1617 | req->resid = dma_buf_write(buf, len, req->sg); | |||
1618 | } | |||
1619 | scsi_req_continue(req); | |||
1620 | } | |||
1621 | ||||
1622 | void scsi_req_print(SCSIRequest *req) | |||
1623 | { | |||
1624 | FILE *fp = stderrstderr; | |||
1625 | int i; | |||
1626 | ||||
1627 | fprintf(fp, "[%s id=%d] %s", | |||
1628 | req->dev->qdev.parent_bus->name, | |||
1629 | req->dev->id, | |||
1630 | scsi_command_name(req->cmd.buf[0])); | |||
1631 | for (i = 1; i < req->cmd.len; i++) { | |||
1632 | fprintf(fp, " 0x%02x", req->cmd.buf[i]); | |||
1633 | } | |||
1634 | switch (req->cmd.mode) { | |||
1635 | case SCSI_XFER_NONE: | |||
1636 | fprintf(fp, " - none\n"); | |||
1637 | break; | |||
1638 | case SCSI_XFER_FROM_DEV: | |||
1639 | fprintf(fp, " - from-dev len=%zd\n", req->cmd.xfer); | |||
1640 | break; | |||
1641 | case SCSI_XFER_TO_DEV: | |||
1642 | fprintf(fp, " - to-dev len=%zd\n", req->cmd.xfer); | |||
1643 | break; | |||
1644 | default: | |||
1645 | fprintf(fp, " - Oops\n"); | |||
1646 | break; | |||
1647 | } | |||
1648 | } | |||
1649 | ||||
1650 | void scsi_req_complete(SCSIRequest *req, int status) | |||
1651 | { | |||
1652 | assert(req->status == -1)((req->status == -1) ? (void) (0) : __assert_fail ("req->status == -1" , "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c", 1652 , __PRETTY_FUNCTION__)); | |||
1653 | req->status = status; | |||
1654 | ||||
1655 | assert(req->sense_len <= sizeof(req->sense))((req->sense_len <= sizeof(req->sense)) ? (void) (0) : __assert_fail ("req->sense_len <= sizeof(req->sense)" , "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c", 1655 , __PRETTY_FUNCTION__)); | |||
1656 | if (status == GOOD0x00) { | |||
1657 | req->sense_len = 0; | |||
1658 | } | |||
1659 | ||||
1660 | if (req->sense_len) { | |||
1661 | memcpy(req->dev->sense, req->sense, req->sense_len); | |||
1662 | req->dev->sense_len = req->sense_len; | |||
1663 | req->dev->sense_is_ua = (req->ops == &reqops_unit_attention); | |||
1664 | } else { | |||
1665 | req->dev->sense_len = 0; | |||
1666 | req->dev->sense_is_ua = false0; | |||
1667 | } | |||
1668 | ||||
1669 | /* | |||
1670 | * Unit attention state is now stored in the device's sense buffer | |||
1671 | * if the HBA didn't do autosense. Clear the pending unit attention | |||
1672 | * flags. | |||
1673 | */ | |||
1674 | scsi_clear_unit_attention(req); | |||
1675 | ||||
1676 | scsi_req_ref(req); | |||
1677 | scsi_req_dequeue(req); | |||
1678 | req->bus->info->complete(req, req->status, req->resid); | |||
1679 | scsi_req_unref(req); | |||
1680 | } | |||
1681 | ||||
1682 | void scsi_req_cancel(SCSIRequest *req) | |||
1683 | { | |||
1684 | trace_scsi_req_cancel(req->dev->id, req->lun, req->tag); | |||
1685 | if (!req->enqueued) { | |||
1686 | return; | |||
1687 | } | |||
1688 | scsi_req_ref(req); | |||
1689 | scsi_req_dequeue(req); | |||
1690 | req->io_canceled = true1; | |||
1691 | if (req->ops->cancel_io) { | |||
1692 | req->ops->cancel_io(req); | |||
1693 | } | |||
1694 | if (req->bus->info->cancel) { | |||
1695 | req->bus->info->cancel(req); | |||
1696 | } | |||
1697 | scsi_req_unref(req); | |||
1698 | } | |||
1699 | ||||
1700 | void scsi_req_abort(SCSIRequest *req, int status) | |||
1701 | { | |||
1702 | if (!req->enqueued) { | |||
1703 | return; | |||
1704 | } | |||
1705 | scsi_req_ref(req); | |||
1706 | scsi_req_dequeue(req); | |||
1707 | req->io_canceled = true1; | |||
1708 | if (req->ops->cancel_io) { | |||
1709 | req->ops->cancel_io(req); | |||
1710 | } | |||
1711 | scsi_req_complete(req, status); | |||
1712 | scsi_req_unref(req); | |||
1713 | } | |||
1714 | ||||
1715 | static int scsi_ua_precedence(SCSISense sense) | |||
1716 | { | |||
1717 | if (sense.key != UNIT_ATTENTION0x06) { | |||
1718 | return INT_MAX2147483647; | |||
1719 | } | |||
1720 | if (sense.asc == 0x29 && sense.ascq == 0x04) { | |||
1721 | /* DEVICE INTERNAL RESET goes with POWER ON OCCURRED */ | |||
1722 | return 1; | |||
1723 | } else if (sense.asc == 0x3F && sense.ascq == 0x01) { | |||
1724 | /* MICROCODE HAS BEEN CHANGED goes with SCSI BUS RESET OCCURRED */ | |||
1725 | return 2; | |||
1726 | } else if (sense.asc == 0x29 && (sense.ascq == 0x05 || sense.ascq == 0x06)) { | |||
1727 | /* These two go with "all others". */ | |||
1728 | ; | |||
1729 | } else if (sense.asc == 0x29 && sense.ascq <= 0x07) { | |||
1730 | /* POWER ON, RESET OR BUS DEVICE RESET OCCURRED = 0 | |||
1731 | * POWER ON OCCURRED = 1 | |||
1732 | * SCSI BUS RESET OCCURRED = 2 | |||
1733 | * BUS DEVICE RESET FUNCTION OCCURRED = 3 | |||
1734 | * I_T NEXUS LOSS OCCURRED = 7 | |||
1735 | */ | |||
1736 | return sense.ascq; | |||
1737 | } else if (sense.asc == 0x2F && sense.ascq == 0x01) { | |||
1738 | /* COMMANDS CLEARED BY POWER LOSS NOTIFICATION */ | |||
1739 | return 8; | |||
1740 | } | |||
1741 | return (sense.asc << 8) | sense.ascq; | |||
1742 | } | |||
1743 | ||||
1744 | void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense) | |||
1745 | { | |||
1746 | int prec1, prec2; | |||
1747 | if (sense.key != UNIT_ATTENTION0x06) { | |||
1748 | return; | |||
1749 | } | |||
1750 | trace_scsi_device_set_ua(sdev->id, sdev->lun, sense.key, | |||
1751 | sense.asc, sense.ascq); | |||
1752 | ||||
1753 | /* | |||
1754 | * Override a pre-existing unit attention condition, except for a more | |||
1755 | * important reset condition. | |||
1756 | */ | |||
1757 | prec1 = scsi_ua_precedence(sdev->unit_attention); | |||
1758 | prec2 = scsi_ua_precedence(sense); | |||
1759 | if (prec2 < prec1) { | |||
1760 | sdev->unit_attention = sense; | |||
1761 | } | |||
1762 | } | |||
1763 | ||||
1764 | void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense) | |||
1765 | { | |||
1766 | SCSIRequest *req; | |||
1767 | ||||
1768 | while (!QTAILQ_EMPTY(&sdev->requests)((&sdev->requests)->tqh_first == ((void*)0))) { | |||
1769 | req = QTAILQ_FIRST(&sdev->requests)((&sdev->requests)->tqh_first); | |||
1770 | scsi_req_cancel(req); | |||
1771 | } | |||
1772 | ||||
1773 | scsi_device_set_ua(sdev, sense); | |||
1774 | } | |||
1775 | ||||
1776 | static char *scsibus_get_dev_path(DeviceState *dev) | |||
1777 | { | |||
1778 | SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSIDevice, qdev)]; ({ const typeof(((SCSIDevice *) 0)->qdev) *__mptr = (dev); (SCSIDevice *) ((char *) __mptr - __builtin_offsetof(SCSIDevice, qdev));});})); | |||
1779 | DeviceState *hba = dev->parent_bus->parent; | |||
1780 | char *id; | |||
1781 | char *path; | |||
1782 | ||||
1783 | id = qdev_get_dev_path(hba); | |||
1784 | if (id) { | |||
1785 | path = g_strdup_printf("%s/%d:%d:%d", id, d->channel, d->id, d->lun); | |||
1786 | } else { | |||
1787 | path = g_strdup_printf("%d:%d:%d", d->channel, d->id, d->lun); | |||
1788 | } | |||
1789 | g_free(id); | |||
1790 | return path; | |||
1791 | } | |||
1792 | ||||
1793 | static char *scsibus_get_fw_dev_path(DeviceState *dev) | |||
1794 | { | |||
1795 | SCSIDevice *d = SCSI_DEVICE(dev)((SCSIDevice *)object_dynamic_cast_assert(((Object *)((dev))) , ("scsi-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 1795, __func__)); | |||
1796 | return g_strdup_printf("channel@%x/%s@%x,%x", d->channel, | |||
1797 | qdev_fw_name(dev), d->id, d->lun); | |||
1798 | } | |||
1799 | ||||
1800 | SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun) | |||
1801 | { | |||
1802 | BusChild *kid; | |||
1803 | SCSIDevice *target_dev = NULL((void*)0); | |||
1804 | ||||
1805 | QTAILQ_FOREACH_REVERSE(kid, &bus->qbus.children, ChildrenHead, sibling)for ((kid) = (*(((struct ChildrenHead *)((&bus->qbus.children )->tqh_last))->tqh_last)); (kid); (kid) = (*(((struct ChildrenHead *)((kid)->sibling.tqe_prev))->tqh_last))) { | |||
1806 | DeviceState *qdev = kid->child; | |||
1807 | SCSIDevice *dev = SCSI_DEVICE(qdev)((SCSIDevice *)object_dynamic_cast_assert(((Object *)((qdev)) ), ("scsi-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 1807, __func__)); | |||
1808 | ||||
1809 | if (dev->channel == channel && dev->id == id) { | |||
1810 | if (dev->lun == lun) { | |||
1811 | return dev; | |||
1812 | } | |||
1813 | target_dev = dev; | |||
1814 | } | |||
1815 | } | |||
1816 | return target_dev; | |||
1817 | } | |||
1818 | ||||
1819 | /* SCSI request list. For simplicity, pv points to the whole device */ | |||
1820 | ||||
1821 | static void put_scsi_requests(QEMUFile *f, void *pv, size_t size) | |||
1822 | { | |||
1823 | SCSIDevice *s = pv; | |||
1824 | SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSIBus, qbus)]; ({ const typeof(((SCSIBus *) 0)->qbus) *__mptr = (s->qdev.parent_bus); (SCSIBus * ) ((char *) __mptr - __builtin_offsetof(SCSIBus, qbus));});}) ); | |||
1825 | SCSIRequest *req; | |||
1826 | ||||
1827 | QTAILQ_FOREACH(req, &s->requests, next)for ((req) = ((&s->requests)->tqh_first); (req); (req ) = ((req)->next.tqe_next)) { | |||
1828 | assert(!req->io_canceled)((!req->io_canceled) ? (void) (0) : __assert_fail ("!req->io_canceled" , "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c", 1828 , __PRETTY_FUNCTION__)); | |||
1829 | assert(req->status == -1)((req->status == -1) ? (void) (0) : __assert_fail ("req->status == -1" , "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c", 1829 , __PRETTY_FUNCTION__)); | |||
1830 | assert(req->enqueued)((req->enqueued) ? (void) (0) : __assert_fail ("req->enqueued" , "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c", 1830 , __PRETTY_FUNCTION__)); | |||
1831 | ||||
1832 | qemu_put_sbyteqemu_put_byte(f, req->retry ? 1 : 2); | |||
1833 | qemu_put_buffer(f, req->cmd.buf, sizeof(req->cmd.buf)); | |||
1834 | qemu_put_be32s(f, &req->tag); | |||
1835 | qemu_put_be32s(f, &req->lun); | |||
1836 | if (bus->info->save_request) { | |||
1837 | bus->info->save_request(f, req); | |||
1838 | } | |||
1839 | if (req->ops->save_request) { | |||
1840 | req->ops->save_request(f, req); | |||
1841 | } | |||
1842 | } | |||
1843 | qemu_put_sbyteqemu_put_byte(f, 0); | |||
1844 | } | |||
1845 | ||||
1846 | static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) | |||
1847 | { | |||
1848 | SCSIDevice *s = pv; | |||
1849 | SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSIBus, qbus)]; ({ const typeof(((SCSIBus *) 0)->qbus) *__mptr = (s->qdev.parent_bus); (SCSIBus * ) ((char *) __mptr - __builtin_offsetof(SCSIBus, qbus));});}) ); | |||
1850 | int8_t sbyte; | |||
1851 | ||||
1852 | while ((sbyte = qemu_get_sbyteqemu_get_byte(f)) > 0) { | |||
| ||||
1853 | uint8_t buf[SCSI_CMD_BUF_SIZE16]; | |||
1854 | uint32_t tag; | |||
1855 | uint32_t lun; | |||
1856 | SCSIRequest *req; | |||
1857 | ||||
1858 | qemu_get_buffer(f, buf, sizeof(buf)); | |||
1859 | qemu_get_be32s(f, &tag); | |||
1860 | qemu_get_be32s(f, &lun); | |||
1861 | req = scsi_req_new(s, tag, lun, buf, NULL((void*)0)); | |||
1862 | req->retry = (sbyte == 1); | |||
1863 | if (bus->info->load_request) { | |||
1864 | req->hba_private = bus->info->load_request(f, req); | |||
1865 | } | |||
1866 | if (req->ops->load_request) { | |||
1867 | req->ops->load_request(f, req); | |||
1868 | } | |||
1869 | ||||
1870 | /* Just restart it later. */ | |||
1871 | scsi_req_enqueue_internal(req); | |||
1872 | ||||
1873 | /* At this point, the request will be kept alive by the reference | |||
1874 | * added by scsi_req_enqueue_internal, so we can release our reference. | |||
1875 | * The HBA of course will add its own reference in the load_request | |||
1876 | * callback if it needs to hold on the SCSIRequest. | |||
1877 | */ | |||
1878 | scsi_req_unref(req); | |||
1879 | } | |||
1880 | ||||
1881 | return 0; | |||
1882 | } | |||
1883 | ||||
1884 | static int scsi_qdev_unplug(DeviceState *qdev) | |||
1885 | { | |||
1886 | SCSIDevice *dev = SCSI_DEVICE(qdev)((SCSIDevice *)object_dynamic_cast_assert(((Object *)((qdev)) ), ("scsi-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 1886, __func__)); | |||
1887 | SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus)( __extension__ ( { char __attribute__((unused)) offset_must_be_zero [ -__builtin_offsetof(SCSIBus, qbus)]; ({ const typeof(((SCSIBus *) 0)->qbus) *__mptr = (dev->qdev.parent_bus); (SCSIBus *) ((char *) __mptr - __builtin_offsetof(SCSIBus, qbus));}); })); | |||
1888 | ||||
1889 | if (bus->info->hot_unplug) { | |||
1890 | bus->info->hot_unplug(bus, dev); | |||
1891 | } | |||
1892 | return qdev_simple_unplug_cb(qdev); | |||
1893 | } | |||
1894 | ||||
1895 | static const VMStateInfo vmstate_info_scsi_requests = { | |||
1896 | .name = "scsi-requests", | |||
1897 | .get = get_scsi_requests, | |||
1898 | .put = put_scsi_requests, | |||
1899 | }; | |||
1900 | ||||
1901 | const VMStateDescription vmstate_scsi_device = { | |||
1902 | .name = "SCSIDevice", | |||
1903 | .version_id = 1, | |||
1904 | .minimum_version_id = 1, | |||
1905 | .minimum_version_id_old = 1, | |||
1906 | .fields = (VMStateField[]) { | |||
1907 | VMSTATE_UINT8(unit_attention.key, SCSIDevice){ .name = ("unit_attention.key"), .version_id = (0), .field_exists = (((void*)0)), .size = sizeof(uint8_t), .info = &(vmstate_info_uint8 ), .flags = VMS_SINGLE, .offset = (__builtin_offsetof(SCSIDevice , unit_attention.key) + ((uint8_t*)0 - (typeof(((SCSIDevice * )0)->unit_attention.key)*)0)), }, | |||
1908 | VMSTATE_UINT8(unit_attention.asc, SCSIDevice){ .name = ("unit_attention.asc"), .version_id = (0), .field_exists = (((void*)0)), .size = sizeof(uint8_t), .info = &(vmstate_info_uint8 ), .flags = VMS_SINGLE, .offset = (__builtin_offsetof(SCSIDevice , unit_attention.asc) + ((uint8_t*)0 - (typeof(((SCSIDevice * )0)->unit_attention.asc)*)0)), }, | |||
1909 | VMSTATE_UINT8(unit_attention.ascq, SCSIDevice){ .name = ("unit_attention.ascq"), .version_id = (0), .field_exists = (((void*)0)), .size = sizeof(uint8_t), .info = &(vmstate_info_uint8 ), .flags = VMS_SINGLE, .offset = (__builtin_offsetof(SCSIDevice , unit_attention.ascq) + ((uint8_t*)0 - (typeof(((SCSIDevice * )0)->unit_attention.ascq)*)0)), }, | |||
1910 | VMSTATE_BOOL(sense_is_ua, SCSIDevice){ .name = ("sense_is_ua"), .version_id = (0), .field_exists = (((void*)0)), .size = sizeof(_Bool), .info = &(vmstate_info_bool ), .flags = VMS_SINGLE, .offset = (__builtin_offsetof(SCSIDevice , sense_is_ua) + ((_Bool*)0 - (typeof(((SCSIDevice *)0)->sense_is_ua )*)0)), }, | |||
1911 | VMSTATE_UINT8_ARRAY(sense, SCSIDevice, SCSI_SENSE_BUF_SIZE){ .name = ("sense"), .version_id = (0), .num = (96), .info = & (vmstate_info_uint8), .size = sizeof(uint8_t), .flags = VMS_ARRAY , .offset = (__builtin_offsetof(SCSIDevice, sense) + ((uint8_t (*)[96])0 - (typeof(((SCSIDevice *)0)->sense)*)0)), }, | |||
1912 | VMSTATE_UINT32(sense_len, SCSIDevice){ .name = ("sense_len"), .version_id = (0), .field_exists = ( ((void*)0)), .size = sizeof(uint32_t), .info = &(vmstate_info_uint32 ), .flags = VMS_SINGLE, .offset = (__builtin_offsetof(SCSIDevice , sense_len) + ((uint32_t*)0 - (typeof(((SCSIDevice *)0)-> sense_len)*)0)), }, | |||
1913 | { | |||
1914 | .name = "requests", | |||
1915 | .version_id = 0, | |||
1916 | .field_exists = NULL((void*)0), | |||
1917 | .size = 0, /* ouch */ | |||
1918 | .info = &vmstate_info_scsi_requests, | |||
1919 | .flags = VMS_SINGLE, | |||
1920 | .offset = 0, | |||
1921 | }, | |||
1922 | VMSTATE_END_OF_LIST(){} | |||
1923 | } | |||
1924 | }; | |||
1925 | ||||
1926 | static void scsi_device_class_init(ObjectClass *klass, void *data) | |||
1927 | { | |||
1928 | DeviceClass *k = DEVICE_CLASS(klass)((DeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/scsi/scsi-bus.c" , 1928, __func__)); | |||
1929 | set_bit(DEVICE_CATEGORY_STORAGE, k->categories); | |||
1930 | k->bus_type = TYPE_SCSI_BUS"SCSI"; | |||
1931 | k->init = scsi_qdev_init; | |||
1932 | k->unplug = scsi_qdev_unplug; | |||
1933 | k->exit = scsi_qdev_exit; | |||
1934 | k->props = scsi_props; | |||
1935 | } | |||
1936 | ||||
1937 | static const TypeInfo scsi_device_type_info = { | |||
1938 | .name = TYPE_SCSI_DEVICE"scsi-device", | |||
1939 | .parent = TYPE_DEVICE"device", | |||
1940 | .instance_size = sizeof(SCSIDevice), | |||
1941 | .abstract = true1, | |||
1942 | .class_size = sizeof(SCSIDeviceClass), | |||
1943 | .class_init = scsi_device_class_init, | |||
1944 | }; | |||
1945 | ||||
1946 | static void scsi_register_types(void) | |||
1947 | { | |||
1948 | type_register_static(&scsi_bus_info); | |||
1949 | type_register_static(&scsi_device_type_info); | |||
1950 | } | |||
1951 | ||||
1952 | type_init(scsi_register_types)static void __attribute__((constructor)) do_qemu_init_scsi_register_types (void) { register_module_init(scsi_register_types, MODULE_INIT_QOM ); } |