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