root / hw / scsi-bus.c @ 9c8255e1
History | View | Annotate | Download (32.4 kB)
1 |
#include "hw.h" |
---|---|
2 |
#include "qemu-error.h" |
3 |
#include "scsi.h" |
4 |
#include "scsi-defs.h" |
5 |
#include "qdev.h" |
6 |
#include "blockdev.h" |
7 |
#include "trace.h" |
8 |
|
9 |
static char *scsibus_get_fw_dev_path(DeviceState *dev); |
10 |
static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf); |
11 |
static int scsi_build_sense(uint8_t *in_buf, int in_len, |
12 |
uint8_t *buf, int len, bool fixed); |
13 |
|
14 |
static struct BusInfo scsi_bus_info = { |
15 |
.name = "SCSI",
|
16 |
.size = sizeof(SCSIBus),
|
17 |
.get_fw_dev_path = scsibus_get_fw_dev_path, |
18 |
.props = (Property[]) { |
19 |
DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1), |
20 |
DEFINE_PROP_UINT32("lun", SCSIDevice, lun, 0), |
21 |
DEFINE_PROP_END_OF_LIST(), |
22 |
}, |
23 |
}; |
24 |
static int next_scsi_bus; |
25 |
|
26 |
/* Create a scsi bus, and attach devices to it. */
|
27 |
void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev, |
28 |
const SCSIBusOps *ops)
|
29 |
{ |
30 |
qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL);
|
31 |
bus->busnr = next_scsi_bus++; |
32 |
bus->tcq = tcq; |
33 |
bus->ndev = ndev; |
34 |
bus->ops = ops; |
35 |
bus->qbus.allow_hotplug = 1;
|
36 |
} |
37 |
|
38 |
static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base) |
39 |
{ |
40 |
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); |
41 |
SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base); |
42 |
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus); |
43 |
int rc = -1; |
44 |
|
45 |
if (dev->id == -1) { |
46 |
for (dev->id = 0; dev->id < bus->ndev; dev->id++) { |
47 |
if (bus->devs[dev->id] == NULL) |
48 |
break;
|
49 |
} |
50 |
} |
51 |
if (dev->id >= bus->ndev) {
|
52 |
error_report("bad scsi device id: %d", dev->id);
|
53 |
goto err;
|
54 |
} |
55 |
|
56 |
if (bus->devs[dev->id]) {
|
57 |
qdev_free(&bus->devs[dev->id]->qdev); |
58 |
} |
59 |
bus->devs[dev->id] = dev; |
60 |
|
61 |
dev->info = info; |
62 |
QTAILQ_INIT(&dev->requests); |
63 |
rc = dev->info->init(dev); |
64 |
if (rc != 0) { |
65 |
bus->devs[dev->id] = NULL;
|
66 |
} |
67 |
|
68 |
err:
|
69 |
return rc;
|
70 |
} |
71 |
|
72 |
static int scsi_qdev_exit(DeviceState *qdev) |
73 |
{ |
74 |
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); |
75 |
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus); |
76 |
|
77 |
assert(bus->devs[dev->id] != NULL);
|
78 |
if (bus->devs[dev->id]->info->destroy) {
|
79 |
bus->devs[dev->id]->info->destroy(bus->devs[dev->id]); |
80 |
} |
81 |
bus->devs[dev->id] = NULL;
|
82 |
return 0; |
83 |
} |
84 |
|
85 |
void scsi_qdev_register(SCSIDeviceInfo *info)
|
86 |
{ |
87 |
info->qdev.bus_info = &scsi_bus_info; |
88 |
info->qdev.init = scsi_qdev_init; |
89 |
info->qdev.unplug = qdev_simple_unplug_cb; |
90 |
info->qdev.exit = scsi_qdev_exit; |
91 |
qdev_register(&info->qdev); |
92 |
} |
93 |
|
94 |
/* handle legacy '-drive if=scsi,...' cmd line args */
|
95 |
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, |
96 |
int unit, bool removable) |
97 |
{ |
98 |
const char *driver; |
99 |
DeviceState *dev; |
100 |
|
101 |
driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk"; |
102 |
dev = qdev_create(&bus->qbus, driver); |
103 |
qdev_prop_set_uint32(dev, "scsi-id", unit);
|
104 |
if (qdev_prop_exists(dev, "removable")) { |
105 |
qdev_prop_set_bit(dev, "removable", removable);
|
106 |
} |
107 |
if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) { |
108 |
qdev_free(dev); |
109 |
return NULL; |
110 |
} |
111 |
if (qdev_init(dev) < 0) |
112 |
return NULL; |
113 |
return DO_UPCAST(SCSIDevice, qdev, dev);
|
114 |
} |
115 |
|
116 |
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
|
117 |
{ |
118 |
Location loc; |
119 |
DriveInfo *dinfo; |
120 |
int res = 0, unit; |
121 |
|
122 |
loc_push_none(&loc); |
123 |
for (unit = 0; unit < bus->ndev; unit++) { |
124 |
dinfo = drive_get(IF_SCSI, bus->busnr, unit); |
125 |
if (dinfo == NULL) { |
126 |
continue;
|
127 |
} |
128 |
qemu_opts_loc_restore(dinfo->opts); |
129 |
if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false)) { |
130 |
res = -1;
|
131 |
break;
|
132 |
} |
133 |
} |
134 |
loc_pop(&loc); |
135 |
return res;
|
136 |
} |
137 |
|
138 |
/* SCSIReqOps implementation for invalid commands. */
|
139 |
|
140 |
static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf)
|
141 |
{ |
142 |
scsi_req_build_sense(req, SENSE_CODE(INVALID_OPCODE)); |
143 |
scsi_req_complete(req, CHECK_CONDITION); |
144 |
return 0; |
145 |
} |
146 |
|
147 |
struct SCSIReqOps reqops_invalid_opcode = {
|
148 |
.size = sizeof(SCSIRequest),
|
149 |
.send_command = scsi_invalid_command |
150 |
}; |
151 |
|
152 |
/* SCSIReqOps implementation for unit attention conditions. */
|
153 |
|
154 |
static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
|
155 |
{ |
156 |
if (req->dev && req->dev->unit_attention.key == UNIT_ATTENTION) {
|
157 |
scsi_req_build_sense(req, req->dev->unit_attention); |
158 |
} else if (req->bus->unit_attention.key == UNIT_ATTENTION) { |
159 |
scsi_req_build_sense(req, req->bus->unit_attention); |
160 |
} |
161 |
scsi_req_complete(req, CHECK_CONDITION); |
162 |
return 0; |
163 |
} |
164 |
|
165 |
struct SCSIReqOps reqops_unit_attention = {
|
166 |
.size = sizeof(SCSIRequest),
|
167 |
.send_command = scsi_unit_attention |
168 |
}; |
169 |
|
170 |
/* SCSIReqOps implementation for REPORT LUNS and for commands sent to
|
171 |
an invalid LUN. */
|
172 |
|
173 |
typedef struct SCSITargetReq SCSITargetReq; |
174 |
|
175 |
struct SCSITargetReq {
|
176 |
SCSIRequest req; |
177 |
int len;
|
178 |
uint8_t buf[64];
|
179 |
}; |
180 |
|
181 |
static void store_lun(uint8_t *outbuf, int lun) |
182 |
{ |
183 |
if (lun < 256) { |
184 |
outbuf[1] = lun;
|
185 |
return;
|
186 |
} |
187 |
outbuf[1] = (lun & 255); |
188 |
outbuf[0] = (lun >> 8) | 0x40; |
189 |
} |
190 |
|
191 |
static bool scsi_target_emulate_report_luns(SCSITargetReq *r) |
192 |
{ |
193 |
int len;
|
194 |
if (r->req.cmd.xfer < 16) { |
195 |
return false; |
196 |
} |
197 |
if (r->req.cmd.buf[2] > 2) { |
198 |
return false; |
199 |
} |
200 |
len = MIN(sizeof r->buf, r->req.cmd.xfer);
|
201 |
memset(r->buf, 0, len);
|
202 |
if (r->req.dev->lun != 0) { |
203 |
r->buf[3] = 16; |
204 |
r->len = 24;
|
205 |
store_lun(&r->buf[16], r->req.dev->lun);
|
206 |
} else {
|
207 |
r->buf[3] = 8; |
208 |
r->len = 16;
|
209 |
} |
210 |
return true; |
211 |
} |
212 |
|
213 |
static bool scsi_target_emulate_inquiry(SCSITargetReq *r) |
214 |
{ |
215 |
assert(r->req.dev->lun != r->req.lun); |
216 |
if (r->req.cmd.buf[1] & 0x2) { |
217 |
/* Command support data - optional, not implemented */
|
218 |
return false; |
219 |
} |
220 |
|
221 |
if (r->req.cmd.buf[1] & 0x1) { |
222 |
/* Vital product data */
|
223 |
uint8_t page_code = r->req.cmd.buf[2];
|
224 |
if (r->req.cmd.xfer < 4) { |
225 |
return false; |
226 |
} |
227 |
|
228 |
r->buf[r->len++] = page_code ; /* this page */
|
229 |
r->buf[r->len++] = 0x00;
|
230 |
|
231 |
switch (page_code) {
|
232 |
case 0x00: /* Supported page codes, mandatory */ |
233 |
{ |
234 |
int pages;
|
235 |
pages = r->len++; |
236 |
r->buf[r->len++] = 0x00; /* list of supported pages (this page) */ |
237 |
r->buf[pages] = r->len - pages - 1; /* number of pages */ |
238 |
break;
|
239 |
} |
240 |
default:
|
241 |
return false; |
242 |
} |
243 |
/* done with EVPD */
|
244 |
assert(r->len < sizeof(r->buf));
|
245 |
r->len = MIN(r->req.cmd.xfer, r->len); |
246 |
return true; |
247 |
} |
248 |
|
249 |
/* Standard INQUIRY data */
|
250 |
if (r->req.cmd.buf[2] != 0) { |
251 |
return false; |
252 |
} |
253 |
|
254 |
/* PAGE CODE == 0 */
|
255 |
if (r->req.cmd.xfer < 5) { |
256 |
return -1; |
257 |
} |
258 |
|
259 |
r->len = MIN(r->req.cmd.xfer, 36);
|
260 |
memset(r->buf, 0, r->len);
|
261 |
if (r->req.lun != 0) { |
262 |
r->buf[0] = TYPE_NO_LUN;
|
263 |
} else {
|
264 |
r->buf[0] = TYPE_NOT_PRESENT | TYPE_INACTIVE;
|
265 |
r->buf[2] = 5; /* Version */ |
266 |
r->buf[3] = 2 | 0x10; /* HiSup, response data format */ |
267 |
r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */ |
268 |
r->buf[7] = 0x10 | (r->req.bus->tcq ? 0x02 : 0); /* Sync, TCQ. */ |
269 |
memcpy(&r->buf[8], "QEMU ", 8); |
270 |
memcpy(&r->buf[16], "QEMU TARGET ", 16); |
271 |
strncpy((char *) &r->buf[32], QEMU_VERSION, 4); |
272 |
} |
273 |
return true; |
274 |
} |
275 |
|
276 |
static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
|
277 |
{ |
278 |
SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req); |
279 |
|
280 |
switch (buf[0]) { |
281 |
case REPORT_LUNS:
|
282 |
if (!scsi_target_emulate_report_luns(r)) {
|
283 |
goto illegal_request;
|
284 |
} |
285 |
break;
|
286 |
case INQUIRY:
|
287 |
if (!scsi_target_emulate_inquiry(r)) {
|
288 |
goto illegal_request;
|
289 |
} |
290 |
break;
|
291 |
case REQUEST_SENSE:
|
292 |
if (req->cmd.xfer < 4) { |
293 |
goto illegal_request;
|
294 |
} |
295 |
r->len = scsi_device_get_sense(r->req.dev, r->buf, |
296 |
MIN(req->cmd.xfer, sizeof r->buf),
|
297 |
(req->cmd.buf[1] & 1) == 0); |
298 |
break;
|
299 |
default:
|
300 |
scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED)); |
301 |
scsi_req_complete(req, CHECK_CONDITION); |
302 |
return 0; |
303 |
illegal_request:
|
304 |
scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD)); |
305 |
scsi_req_complete(req, CHECK_CONDITION); |
306 |
return 0; |
307 |
} |
308 |
|
309 |
if (!r->len) {
|
310 |
scsi_req_complete(req, GOOD); |
311 |
} |
312 |
return r->len;
|
313 |
} |
314 |
|
315 |
static void scsi_target_read_data(SCSIRequest *req) |
316 |
{ |
317 |
SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req); |
318 |
uint32_t n; |
319 |
|
320 |
n = r->len; |
321 |
if (n > 0) { |
322 |
r->len = 0;
|
323 |
scsi_req_data(&r->req, n); |
324 |
} else {
|
325 |
scsi_req_complete(&r->req, GOOD); |
326 |
} |
327 |
} |
328 |
|
329 |
static uint8_t *scsi_target_get_buf(SCSIRequest *req)
|
330 |
{ |
331 |
SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req); |
332 |
|
333 |
return r->buf;
|
334 |
} |
335 |
|
336 |
struct SCSIReqOps reqops_target_command = {
|
337 |
.size = sizeof(SCSITargetReq),
|
338 |
.send_command = scsi_target_send_command, |
339 |
.read_data = scsi_target_read_data, |
340 |
.get_buf = scsi_target_get_buf, |
341 |
}; |
342 |
|
343 |
|
344 |
SCSIRequest *scsi_req_alloc(SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag, |
345 |
uint32_t lun, void *hba_private)
|
346 |
{ |
347 |
SCSIRequest *req; |
348 |
|
349 |
req = g_malloc0(reqops->size); |
350 |
req->refcount = 1;
|
351 |
req->bus = scsi_bus_from_device(d); |
352 |
req->dev = d; |
353 |
req->tag = tag; |
354 |
req->lun = lun; |
355 |
req->hba_private = hba_private; |
356 |
req->status = -1;
|
357 |
req->sense_len = 0;
|
358 |
req->ops = reqops; |
359 |
trace_scsi_req_alloc(req->dev->id, req->lun, req->tag); |
360 |
return req;
|
361 |
} |
362 |
|
363 |
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, |
364 |
uint8_t *buf, void *hba_private)
|
365 |
{ |
366 |
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus); |
367 |
SCSIRequest *req; |
368 |
SCSICommand cmd; |
369 |
|
370 |
if (scsi_req_parse(&cmd, d, buf) != 0) { |
371 |
trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]);
|
372 |
req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private); |
373 |
} else {
|
374 |
trace_scsi_req_parsed(d->id, lun, tag, buf[0],
|
375 |
cmd.mode, cmd.xfer); |
376 |
if (cmd.lba != -1) { |
377 |
trace_scsi_req_parsed_lba(d->id, lun, tag, buf[0],
|
378 |
cmd.lba); |
379 |
} |
380 |
|
381 |
if ((d->unit_attention.key == UNIT_ATTENTION ||
|
382 |
bus->unit_attention.key == UNIT_ATTENTION) && |
383 |
(buf[0] != INQUIRY &&
|
384 |
buf[0] != REPORT_LUNS &&
|
385 |
buf[0] != GET_CONFIGURATION &&
|
386 |
buf[0] != GET_EVENT_STATUS_NOTIFICATION)) {
|
387 |
req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun, |
388 |
hba_private); |
389 |
} else if (lun != d->lun || |
390 |
buf[0] == REPORT_LUNS ||
|
391 |
buf[0] == REQUEST_SENSE) {
|
392 |
req = scsi_req_alloc(&reqops_target_command, d, tag, lun, |
393 |
hba_private); |
394 |
} else {
|
395 |
req = d->info->alloc_req(d, tag, lun, hba_private); |
396 |
} |
397 |
} |
398 |
|
399 |
req->cmd = cmd; |
400 |
switch (buf[0]) { |
401 |
case INQUIRY:
|
402 |
trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]); |
403 |
break;
|
404 |
case TEST_UNIT_READY:
|
405 |
trace_scsi_test_unit_ready(d->id, lun, tag); |
406 |
break;
|
407 |
case REPORT_LUNS:
|
408 |
trace_scsi_report_luns(d->id, lun, tag); |
409 |
break;
|
410 |
case REQUEST_SENSE:
|
411 |
trace_scsi_request_sense(d->id, lun, tag); |
412 |
break;
|
413 |
default:
|
414 |
break;
|
415 |
} |
416 |
|
417 |
return req;
|
418 |
} |
419 |
|
420 |
uint8_t *scsi_req_get_buf(SCSIRequest *req) |
421 |
{ |
422 |
return req->ops->get_buf(req);
|
423 |
} |
424 |
|
425 |
static void scsi_clear_unit_attention(SCSIRequest *req) |
426 |
{ |
427 |
SCSISense *ua; |
428 |
if (req->dev->unit_attention.key != UNIT_ATTENTION &&
|
429 |
req->bus->unit_attention.key != UNIT_ATTENTION) { |
430 |
return;
|
431 |
} |
432 |
|
433 |
/*
|
434 |
* If an INQUIRY command enters the enabled command state,
|
435 |
* the device server shall [not] clear any unit attention condition;
|
436 |
* See also MMC-6, paragraphs 6.5 and 6.6.2.
|
437 |
*/
|
438 |
if (req->cmd.buf[0] == INQUIRY || |
439 |
req->cmd.buf[0] == GET_CONFIGURATION ||
|
440 |
req->cmd.buf[0] == GET_EVENT_STATUS_NOTIFICATION) {
|
441 |
return;
|
442 |
} |
443 |
|
444 |
if (req->dev->unit_attention.key == UNIT_ATTENTION) {
|
445 |
ua = &req->dev->unit_attention; |
446 |
} else {
|
447 |
ua = &req->bus->unit_attention; |
448 |
} |
449 |
|
450 |
/*
|
451 |
* If a REPORT LUNS command enters the enabled command state, [...]
|
452 |
* the device server shall clear any pending unit attention condition
|
453 |
* with an additional sense code of REPORTED LUNS DATA HAS CHANGED.
|
454 |
*/
|
455 |
if (req->cmd.buf[0] == REPORT_LUNS && |
456 |
!(ua->asc == SENSE_CODE(REPORTED_LUNS_CHANGED).asc && |
457 |
ua->ascq == SENSE_CODE(REPORTED_LUNS_CHANGED).ascq)) { |
458 |
return;
|
459 |
} |
460 |
|
461 |
*ua = SENSE_CODE(NO_SENSE); |
462 |
} |
463 |
|
464 |
int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len) |
465 |
{ |
466 |
int ret;
|
467 |
|
468 |
assert(len >= 14);
|
469 |
if (!req->sense_len) {
|
470 |
return 0; |
471 |
} |
472 |
|
473 |
ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true);
|
474 |
|
475 |
/*
|
476 |
* FIXME: clearing unit attention conditions upon autosense should be done
|
477 |
* only if the UA_INTLCK_CTRL field in the Control mode page is set to 00b
|
478 |
* (SAM-5, 5.14).
|
479 |
*
|
480 |
* We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and
|
481 |
* 10b for HBAs that do not support it (do not call scsi_req_get_sense).
|
482 |
* In the latter case, scsi_req_complete clears unit attention conditions
|
483 |
* after moving them to the device's sense buffer.
|
484 |
*/
|
485 |
scsi_clear_unit_attention(req); |
486 |
return ret;
|
487 |
} |
488 |
|
489 |
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed) |
490 |
{ |
491 |
return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed);
|
492 |
} |
493 |
|
494 |
void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
|
495 |
{ |
496 |
trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag, |
497 |
sense.key, sense.asc, sense.ascq); |
498 |
memset(req->sense, 0, 18); |
499 |
req->sense[0] = 0xf0; |
500 |
req->sense[2] = sense.key;
|
501 |
req->sense[12] = sense.asc;
|
502 |
req->sense[13] = sense.ascq;
|
503 |
req->sense_len = 18;
|
504 |
} |
505 |
|
506 |
int32_t scsi_req_enqueue(SCSIRequest *req) |
507 |
{ |
508 |
int32_t rc; |
509 |
|
510 |
assert(!req->enqueued); |
511 |
scsi_req_ref(req); |
512 |
req->enqueued = true;
|
513 |
QTAILQ_INSERT_TAIL(&req->dev->requests, req, next); |
514 |
|
515 |
scsi_req_ref(req); |
516 |
rc = req->ops->send_command(req, req->cmd.buf); |
517 |
scsi_req_unref(req); |
518 |
return rc;
|
519 |
} |
520 |
|
521 |
static void scsi_req_dequeue(SCSIRequest *req) |
522 |
{ |
523 |
trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag); |
524 |
if (req->enqueued) {
|
525 |
QTAILQ_REMOVE(&req->dev->requests, req, next); |
526 |
req->enqueued = false;
|
527 |
scsi_req_unref(req); |
528 |
} |
529 |
} |
530 |
|
531 |
static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) |
532 |
{ |
533 |
switch (buf[0] >> 5) { |
534 |
case 0: |
535 |
cmd->xfer = buf[4];
|
536 |
cmd->len = 6;
|
537 |
/* length 0 means 256 blocks */
|
538 |
if (cmd->xfer == 0) { |
539 |
cmd->xfer = 256;
|
540 |
} |
541 |
break;
|
542 |
case 1: |
543 |
case 2: |
544 |
cmd->xfer = buf[8] | (buf[7] << 8); |
545 |
cmd->len = 10;
|
546 |
break;
|
547 |
case 4: |
548 |
cmd->xfer = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24); |
549 |
cmd->len = 16;
|
550 |
break;
|
551 |
case 5: |
552 |
cmd->xfer = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24); |
553 |
cmd->len = 12;
|
554 |
break;
|
555 |
default:
|
556 |
return -1; |
557 |
} |
558 |
|
559 |
switch (buf[0]) { |
560 |
case TEST_UNIT_READY:
|
561 |
case REWIND:
|
562 |
case START_STOP:
|
563 |
case SEEK_6:
|
564 |
case WRITE_FILEMARKS:
|
565 |
case SPACE:
|
566 |
case RESERVE:
|
567 |
case RELEASE:
|
568 |
case ERASE:
|
569 |
case ALLOW_MEDIUM_REMOVAL:
|
570 |
case VERIFY_10:
|
571 |
case SEEK_10:
|
572 |
case SYNCHRONIZE_CACHE:
|
573 |
case LOCK_UNLOCK_CACHE:
|
574 |
case LOAD_UNLOAD:
|
575 |
case SET_CD_SPEED:
|
576 |
case SET_LIMITS:
|
577 |
case WRITE_LONG_10:
|
578 |
case MOVE_MEDIUM:
|
579 |
case UPDATE_BLOCK:
|
580 |
cmd->xfer = 0;
|
581 |
break;
|
582 |
case MODE_SENSE:
|
583 |
break;
|
584 |
case WRITE_SAME_10:
|
585 |
cmd->xfer = 1;
|
586 |
break;
|
587 |
case READ_CAPACITY_10:
|
588 |
cmd->xfer = 8;
|
589 |
break;
|
590 |
case READ_BLOCK_LIMITS:
|
591 |
cmd->xfer = 6;
|
592 |
break;
|
593 |
case READ_POSITION:
|
594 |
cmd->xfer = 20;
|
595 |
break;
|
596 |
case SEND_VOLUME_TAG:
|
597 |
cmd->xfer *= 40;
|
598 |
break;
|
599 |
case MEDIUM_SCAN:
|
600 |
cmd->xfer *= 8;
|
601 |
break;
|
602 |
case WRITE_10:
|
603 |
case WRITE_VERIFY_10:
|
604 |
case WRITE_6:
|
605 |
case WRITE_12:
|
606 |
case WRITE_VERIFY_12:
|
607 |
case WRITE_16:
|
608 |
case WRITE_VERIFY_16:
|
609 |
cmd->xfer *= dev->blocksize; |
610 |
break;
|
611 |
case READ_10:
|
612 |
case READ_6:
|
613 |
case READ_REVERSE:
|
614 |
case RECOVER_BUFFERED_DATA:
|
615 |
case READ_12:
|
616 |
case READ_16:
|
617 |
cmd->xfer *= dev->blocksize; |
618 |
break;
|
619 |
case INQUIRY:
|
620 |
cmd->xfer = buf[4] | (buf[3] << 8); |
621 |
break;
|
622 |
case MAINTENANCE_OUT:
|
623 |
case MAINTENANCE_IN:
|
624 |
if (dev->type == TYPE_ROM) {
|
625 |
/* GPCMD_REPORT_KEY and GPCMD_SEND_KEY from multi media commands */
|
626 |
cmd->xfer = buf[9] | (buf[8] << 8); |
627 |
} |
628 |
break;
|
629 |
} |
630 |
return 0; |
631 |
} |
632 |
|
633 |
static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) |
634 |
{ |
635 |
switch (buf[0]) { |
636 |
/* stream commands */
|
637 |
case READ_6:
|
638 |
case READ_REVERSE:
|
639 |
case RECOVER_BUFFERED_DATA:
|
640 |
case WRITE_6:
|
641 |
cmd->len = 6;
|
642 |
cmd->xfer = buf[4] | (buf[3] << 8) | (buf[2] << 16); |
643 |
if (buf[1] & 0x01) { /* fixed */ |
644 |
cmd->xfer *= dev->blocksize; |
645 |
} |
646 |
break;
|
647 |
case REWIND:
|
648 |
case START_STOP:
|
649 |
cmd->len = 6;
|
650 |
cmd->xfer = 0;
|
651 |
break;
|
652 |
/* generic commands */
|
653 |
default:
|
654 |
return scsi_req_length(cmd, dev, buf);
|
655 |
} |
656 |
return 0; |
657 |
} |
658 |
|
659 |
static void scsi_cmd_xfer_mode(SCSICommand *cmd) |
660 |
{ |
661 |
switch (cmd->buf[0]) { |
662 |
case WRITE_6:
|
663 |
case WRITE_10:
|
664 |
case WRITE_VERIFY_10:
|
665 |
case WRITE_12:
|
666 |
case WRITE_VERIFY_12:
|
667 |
case WRITE_16:
|
668 |
case WRITE_VERIFY_16:
|
669 |
case COPY:
|
670 |
case COPY_VERIFY:
|
671 |
case COMPARE:
|
672 |
case CHANGE_DEFINITION:
|
673 |
case LOG_SELECT:
|
674 |
case MODE_SELECT:
|
675 |
case MODE_SELECT_10:
|
676 |
case SEND_DIAGNOSTIC:
|
677 |
case WRITE_BUFFER:
|
678 |
case FORMAT_UNIT:
|
679 |
case REASSIGN_BLOCKS:
|
680 |
case SEARCH_EQUAL:
|
681 |
case SEARCH_HIGH:
|
682 |
case SEARCH_LOW:
|
683 |
case UPDATE_BLOCK:
|
684 |
case WRITE_LONG_10:
|
685 |
case WRITE_SAME_10:
|
686 |
case SEARCH_HIGH_12:
|
687 |
case SEARCH_EQUAL_12:
|
688 |
case SEARCH_LOW_12:
|
689 |
case MEDIUM_SCAN:
|
690 |
case SEND_VOLUME_TAG:
|
691 |
case PERSISTENT_RESERVE_OUT:
|
692 |
case MAINTENANCE_OUT:
|
693 |
cmd->mode = SCSI_XFER_TO_DEV; |
694 |
break;
|
695 |
default:
|
696 |
if (cmd->xfer)
|
697 |
cmd->mode = SCSI_XFER_FROM_DEV; |
698 |
else {
|
699 |
cmd->mode = SCSI_XFER_NONE; |
700 |
} |
701 |
break;
|
702 |
} |
703 |
} |
704 |
|
705 |
static uint64_t scsi_cmd_lba(SCSICommand *cmd)
|
706 |
{ |
707 |
uint8_t *buf = cmd->buf; |
708 |
uint64_t lba; |
709 |
|
710 |
switch (buf[0] >> 5) { |
711 |
case 0: |
712 |
lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) | |
713 |
(((uint64_t) buf[1] & 0x1f) << 16); |
714 |
break;
|
715 |
case 1: |
716 |
case 2: |
717 |
lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) | |
718 |
((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24); |
719 |
break;
|
720 |
case 4: |
721 |
lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) | |
722 |
((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) | |
723 |
((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) | |
724 |
((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56); |
725 |
break;
|
726 |
case 5: |
727 |
lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) | |
728 |
((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24); |
729 |
break;
|
730 |
default:
|
731 |
lba = -1;
|
732 |
|
733 |
} |
734 |
return lba;
|
735 |
} |
736 |
|
737 |
int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
|
738 |
{ |
739 |
int rc;
|
740 |
|
741 |
if (dev->type == TYPE_TAPE) {
|
742 |
rc = scsi_req_stream_length(cmd, dev, buf); |
743 |
} else {
|
744 |
rc = scsi_req_length(cmd, dev, buf); |
745 |
} |
746 |
if (rc != 0) |
747 |
return rc;
|
748 |
|
749 |
memcpy(cmd->buf, buf, cmd->len); |
750 |
scsi_cmd_xfer_mode(cmd); |
751 |
cmd->lba = scsi_cmd_lba(cmd); |
752 |
return 0; |
753 |
} |
754 |
|
755 |
/*
|
756 |
* Predefined sense codes
|
757 |
*/
|
758 |
|
759 |
/* No sense data available */
|
760 |
const struct SCSISense sense_code_NO_SENSE = { |
761 |
.key = NO_SENSE , .asc = 0x00 , .ascq = 0x00 |
762 |
}; |
763 |
|
764 |
/* LUN not ready, Manual intervention required */
|
765 |
const struct SCSISense sense_code_LUN_NOT_READY = { |
766 |
.key = NOT_READY, .asc = 0x04, .ascq = 0x03 |
767 |
}; |
768 |
|
769 |
/* LUN not ready, Medium not present */
|
770 |
const struct SCSISense sense_code_NO_MEDIUM = { |
771 |
.key = NOT_READY, .asc = 0x3a, .ascq = 0x00 |
772 |
}; |
773 |
|
774 |
/* Hardware error, internal target failure */
|
775 |
const struct SCSISense sense_code_TARGET_FAILURE = { |
776 |
.key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00 |
777 |
}; |
778 |
|
779 |
/* Illegal request, invalid command operation code */
|
780 |
const struct SCSISense sense_code_INVALID_OPCODE = { |
781 |
.key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00 |
782 |
}; |
783 |
|
784 |
/* Illegal request, LBA out of range */
|
785 |
const struct SCSISense sense_code_LBA_OUT_OF_RANGE = { |
786 |
.key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00 |
787 |
}; |
788 |
|
789 |
/* Illegal request, Invalid field in CDB */
|
790 |
const struct SCSISense sense_code_INVALID_FIELD = { |
791 |
.key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00 |
792 |
}; |
793 |
|
794 |
/* Illegal request, LUN not supported */
|
795 |
const struct SCSISense sense_code_LUN_NOT_SUPPORTED = { |
796 |
.key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00 |
797 |
}; |
798 |
|
799 |
/* Illegal request, Saving parameters not supported */
|
800 |
const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = { |
801 |
.key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00 |
802 |
}; |
803 |
|
804 |
/* Illegal request, Incompatible medium installed */
|
805 |
const struct SCSISense sense_code_INCOMPATIBLE_MEDIUM = { |
806 |
.key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00 |
807 |
}; |
808 |
|
809 |
/* Command aborted, I/O process terminated */
|
810 |
const struct SCSISense sense_code_IO_ERROR = { |
811 |
.key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06 |
812 |
}; |
813 |
|
814 |
/* Command aborted, I_T Nexus loss occurred */
|
815 |
const struct SCSISense sense_code_I_T_NEXUS_LOSS = { |
816 |
.key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07 |
817 |
}; |
818 |
|
819 |
/* Command aborted, Logical Unit failure */
|
820 |
const struct SCSISense sense_code_LUN_FAILURE = { |
821 |
.key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01 |
822 |
}; |
823 |
|
824 |
/* Unit attention, Power on, reset or bus device reset occurred */
|
825 |
const struct SCSISense sense_code_RESET = { |
826 |
.key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00 |
827 |
}; |
828 |
|
829 |
/* Unit attention, Medium may have changed */
|
830 |
const struct SCSISense sense_code_MEDIUM_CHANGED = { |
831 |
.key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00 |
832 |
}; |
833 |
|
834 |
/* Unit attention, Reported LUNs data has changed */
|
835 |
const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = { |
836 |
.key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e |
837 |
}; |
838 |
|
839 |
/* Unit attention, Device internal reset */
|
840 |
const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = { |
841 |
.key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04 |
842 |
}; |
843 |
|
844 |
/*
|
845 |
* scsi_build_sense
|
846 |
*
|
847 |
* Convert between fixed and descriptor sense buffers
|
848 |
*/
|
849 |
int scsi_build_sense(uint8_t *in_buf, int in_len, |
850 |
uint8_t *buf, int len, bool fixed) |
851 |
{ |
852 |
bool fixed_in;
|
853 |
SCSISense sense; |
854 |
if (!fixed && len < 8) { |
855 |
return 0; |
856 |
} |
857 |
|
858 |
if (in_len == 0) { |
859 |
sense.key = NO_SENSE; |
860 |
sense.asc = 0;
|
861 |
sense.ascq = 0;
|
862 |
} else {
|
863 |
fixed_in = (in_buf[0] & 2) == 0; |
864 |
|
865 |
if (fixed == fixed_in) {
|
866 |
memcpy(buf, in_buf, MIN(len, in_len)); |
867 |
return MIN(len, in_len);
|
868 |
} |
869 |
|
870 |
if (fixed_in) {
|
871 |
sense.key = in_buf[2];
|
872 |
sense.asc = in_buf[12];
|
873 |
sense.ascq = in_buf[13];
|
874 |
} else {
|
875 |
sense.key = in_buf[1];
|
876 |
sense.asc = in_buf[2];
|
877 |
sense.ascq = in_buf[3];
|
878 |
} |
879 |
} |
880 |
|
881 |
memset(buf, 0, len);
|
882 |
if (fixed) {
|
883 |
/* Return fixed format sense buffer */
|
884 |
buf[0] = 0xf0; |
885 |
buf[2] = sense.key;
|
886 |
buf[7] = 7; |
887 |
buf[12] = sense.asc;
|
888 |
buf[13] = sense.ascq;
|
889 |
return MIN(len, 18); |
890 |
} else {
|
891 |
/* Return descriptor format sense buffer */
|
892 |
buf[0] = 0x72; |
893 |
buf[1] = sense.key;
|
894 |
buf[2] = sense.asc;
|
895 |
buf[3] = sense.ascq;
|
896 |
return 8; |
897 |
} |
898 |
} |
899 |
|
900 |
static const char *scsi_command_name(uint8_t cmd) |
901 |
{ |
902 |
static const char *names[] = { |
903 |
[ TEST_UNIT_READY ] = "TEST_UNIT_READY",
|
904 |
[ REWIND ] = "REWIND",
|
905 |
[ REQUEST_SENSE ] = "REQUEST_SENSE",
|
906 |
[ FORMAT_UNIT ] = "FORMAT_UNIT",
|
907 |
[ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS",
|
908 |
[ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS",
|
909 |
[ READ_6 ] = "READ_6",
|
910 |
[ WRITE_6 ] = "WRITE_6",
|
911 |
[ SEEK_6 ] = "SEEK_6",
|
912 |
[ READ_REVERSE ] = "READ_REVERSE",
|
913 |
[ WRITE_FILEMARKS ] = "WRITE_FILEMARKS",
|
914 |
[ SPACE ] = "SPACE",
|
915 |
[ INQUIRY ] = "INQUIRY",
|
916 |
[ RECOVER_BUFFERED_DATA ] = "RECOVER_BUFFERED_DATA",
|
917 |
[ MAINTENANCE_IN ] = "MAINTENANCE_IN",
|
918 |
[ MAINTENANCE_OUT ] = "MAINTENANCE_OUT",
|
919 |
[ MODE_SELECT ] = "MODE_SELECT",
|
920 |
[ RESERVE ] = "RESERVE",
|
921 |
[ RELEASE ] = "RELEASE",
|
922 |
[ COPY ] = "COPY",
|
923 |
[ ERASE ] = "ERASE",
|
924 |
[ MODE_SENSE ] = "MODE_SENSE",
|
925 |
[ START_STOP ] = "START_STOP",
|
926 |
[ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC",
|
927 |
[ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC",
|
928 |
[ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL",
|
929 |
[ READ_CAPACITY_10 ] = "READ_CAPACITY_10",
|
930 |
[ READ_10 ] = "READ_10",
|
931 |
[ WRITE_10 ] = "WRITE_10",
|
932 |
[ SEEK_10 ] = "SEEK_10",
|
933 |
[ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10",
|
934 |
[ VERIFY_10 ] = "VERIFY_10",
|
935 |
[ SEARCH_HIGH ] = "SEARCH_HIGH",
|
936 |
[ SEARCH_EQUAL ] = "SEARCH_EQUAL",
|
937 |
[ SEARCH_LOW ] = "SEARCH_LOW",
|
938 |
[ SET_LIMITS ] = "SET_LIMITS",
|
939 |
[ PRE_FETCH ] = "PRE_FETCH",
|
940 |
/* READ_POSITION and PRE_FETCH use the same operation code */
|
941 |
[ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE",
|
942 |
[ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE",
|
943 |
[ READ_DEFECT_DATA ] = "READ_DEFECT_DATA",
|
944 |
[ MEDIUM_SCAN ] = "MEDIUM_SCAN",
|
945 |
[ COMPARE ] = "COMPARE",
|
946 |
[ COPY_VERIFY ] = "COPY_VERIFY",
|
947 |
[ WRITE_BUFFER ] = "WRITE_BUFFER",
|
948 |
[ READ_BUFFER ] = "READ_BUFFER",
|
949 |
[ UPDATE_BLOCK ] = "UPDATE_BLOCK",
|
950 |
[ READ_LONG_10 ] = "READ_LONG_10",
|
951 |
[ WRITE_LONG_10 ] = "WRITE_LONG_10",
|
952 |
[ CHANGE_DEFINITION ] = "CHANGE_DEFINITION",
|
953 |
[ WRITE_SAME_10 ] = "WRITE_SAME_10",
|
954 |
[ UNMAP ] = "UNMAP",
|
955 |
[ READ_TOC ] = "READ_TOC",
|
956 |
[ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT",
|
957 |
[ GET_CONFIGURATION ] = "GET_CONFIGURATION",
|
958 |
[ LOG_SELECT ] = "LOG_SELECT",
|
959 |
[ LOG_SENSE ] = "LOG_SENSE",
|
960 |
[ MODE_SELECT_10 ] = "MODE_SELECT_10",
|
961 |
[ RESERVE_10 ] = "RESERVE_10",
|
962 |
[ RELEASE_10 ] = "RELEASE_10",
|
963 |
[ MODE_SENSE_10 ] = "MODE_SENSE_10",
|
964 |
[ PERSISTENT_RESERVE_IN ] = "PERSISTENT_RESERVE_IN",
|
965 |
[ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT",
|
966 |
[ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16",
|
967 |
[ EXTENDED_COPY ] = "EXTENDED_COPY",
|
968 |
[ ATA_PASSTHROUGH ] = "ATA_PASSTHROUGH",
|
969 |
[ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN",
|
970 |
[ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT",
|
971 |
[ READ_16 ] = "READ_16",
|
972 |
[ COMPARE_AND_WRITE ] = "COMPARE_AND_WRITE",
|
973 |
[ WRITE_16 ] = "WRITE_16",
|
974 |
[ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16",
|
975 |
[ VERIFY_16 ] = "VERIFY_16",
|
976 |
[ SYNCHRONIZE_CACHE_16 ] = "SYNCHRONIZE_CACHE_16",
|
977 |
[ LOCATE_16 ] = "LOCATE_16",
|
978 |
[ WRITE_SAME_16 ] = "WRITE_SAME_16",
|
979 |
[ ERASE_16 ] = "ERASE_16",
|
980 |
[ SERVICE_ACTION_IN ] = "SERVICE_ACTION_IN",
|
981 |
[ WRITE_LONG_16 ] = "WRITE_LONG_16",
|
982 |
[ REPORT_LUNS ] = "REPORT_LUNS",
|
983 |
[ BLANK ] = "BLANK",
|
984 |
[ MAINTENANCE_IN ] = "MAINTENANCE_IN",
|
985 |
[ MAINTENANCE_OUT ] = "MAINTENANCE_OUT",
|
986 |
[ MOVE_MEDIUM ] = "MOVE_MEDIUM",
|
987 |
[ LOAD_UNLOAD ] = "LOAD_UNLOAD",
|
988 |
[ READ_12 ] = "READ_12",
|
989 |
[ WRITE_12 ] = "WRITE_12",
|
990 |
[ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12",
|
991 |
[ VERIFY_12 ] = "VERIFY_12",
|
992 |
[ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12",
|
993 |
[ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12",
|
994 |
[ SEARCH_LOW_12 ] = "SEARCH_LOW_12",
|
995 |
[ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS",
|
996 |
[ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG",
|
997 |
[ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12",
|
998 |
[ SET_CD_SPEED ] = "SET_CD_SPEED",
|
999 |
}; |
1000 |
|
1001 |
if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) |
1002 |
return "*UNKNOWN*"; |
1003 |
return names[cmd];
|
1004 |
} |
1005 |
|
1006 |
SCSIRequest *scsi_req_ref(SCSIRequest *req) |
1007 |
{ |
1008 |
req->refcount++; |
1009 |
return req;
|
1010 |
} |
1011 |
|
1012 |
void scsi_req_unref(SCSIRequest *req)
|
1013 |
{ |
1014 |
if (--req->refcount == 0) { |
1015 |
if (req->ops->free_req) {
|
1016 |
req->ops->free_req(req); |
1017 |
} |
1018 |
g_free(req); |
1019 |
} |
1020 |
} |
1021 |
|
1022 |
/* Tell the device that we finished processing this chunk of I/O. It
|
1023 |
will start the next chunk or complete the command. */
|
1024 |
void scsi_req_continue(SCSIRequest *req)
|
1025 |
{ |
1026 |
trace_scsi_req_continue(req->dev->id, req->lun, req->tag); |
1027 |
if (req->cmd.mode == SCSI_XFER_TO_DEV) {
|
1028 |
req->ops->write_data(req); |
1029 |
} else {
|
1030 |
req->ops->read_data(req); |
1031 |
} |
1032 |
} |
1033 |
|
1034 |
/* Called by the devices when data is ready for the HBA. The HBA should
|
1035 |
start a DMA operation to read or fill the device's data buffer.
|
1036 |
Once it completes, calling scsi_req_continue will restart I/O. */
|
1037 |
void scsi_req_data(SCSIRequest *req, int len) |
1038 |
{ |
1039 |
trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); |
1040 |
req->bus->ops->transfer_data(req, len); |
1041 |
} |
1042 |
|
1043 |
void scsi_req_print(SCSIRequest *req)
|
1044 |
{ |
1045 |
FILE *fp = stderr; |
1046 |
int i;
|
1047 |
|
1048 |
fprintf(fp, "[%s id=%d] %s",
|
1049 |
req->dev->qdev.parent_bus->name, |
1050 |
req->dev->id, |
1051 |
scsi_command_name(req->cmd.buf[0]));
|
1052 |
for (i = 1; i < req->cmd.len; i++) { |
1053 |
fprintf(fp, " 0x%02x", req->cmd.buf[i]);
|
1054 |
} |
1055 |
switch (req->cmd.mode) {
|
1056 |
case SCSI_XFER_NONE:
|
1057 |
fprintf(fp, " - none\n");
|
1058 |
break;
|
1059 |
case SCSI_XFER_FROM_DEV:
|
1060 |
fprintf(fp, " - from-dev len=%zd\n", req->cmd.xfer);
|
1061 |
break;
|
1062 |
case SCSI_XFER_TO_DEV:
|
1063 |
fprintf(fp, " - to-dev len=%zd\n", req->cmd.xfer);
|
1064 |
break;
|
1065 |
default:
|
1066 |
fprintf(fp, " - Oops\n");
|
1067 |
break;
|
1068 |
} |
1069 |
} |
1070 |
|
1071 |
void scsi_req_complete(SCSIRequest *req, int status) |
1072 |
{ |
1073 |
assert(req->status == -1);
|
1074 |
req->status = status; |
1075 |
|
1076 |
assert(req->sense_len < sizeof(req->sense));
|
1077 |
if (status == GOOD) {
|
1078 |
req->sense_len = 0;
|
1079 |
} |
1080 |
|
1081 |
if (req->sense_len) {
|
1082 |
memcpy(req->dev->sense, req->sense, req->sense_len); |
1083 |
} |
1084 |
req->dev->sense_len = req->sense_len; |
1085 |
|
1086 |
/*
|
1087 |
* Unit attention state is now stored in the device's sense buffer
|
1088 |
* if the HBA didn't do autosense. Clear the pending unit attention
|
1089 |
* flags.
|
1090 |
*/
|
1091 |
scsi_clear_unit_attention(req); |
1092 |
|
1093 |
scsi_req_ref(req); |
1094 |
scsi_req_dequeue(req); |
1095 |
req->bus->ops->complete(req, req->status); |
1096 |
scsi_req_unref(req); |
1097 |
} |
1098 |
|
1099 |
void scsi_req_cancel(SCSIRequest *req)
|
1100 |
{ |
1101 |
if (req->ops->cancel_io) {
|
1102 |
req->ops->cancel_io(req); |
1103 |
} |
1104 |
scsi_req_ref(req); |
1105 |
scsi_req_dequeue(req); |
1106 |
if (req->bus->ops->cancel) {
|
1107 |
req->bus->ops->cancel(req); |
1108 |
} |
1109 |
scsi_req_unref(req); |
1110 |
} |
1111 |
|
1112 |
void scsi_req_abort(SCSIRequest *req, int status) |
1113 |
{ |
1114 |
if (req->ops->cancel_io) {
|
1115 |
req->ops->cancel_io(req); |
1116 |
} |
1117 |
scsi_req_complete(req, status); |
1118 |
} |
1119 |
|
1120 |
void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
|
1121 |
{ |
1122 |
SCSIRequest *req; |
1123 |
|
1124 |
while (!QTAILQ_EMPTY(&sdev->requests)) {
|
1125 |
req = QTAILQ_FIRST(&sdev->requests); |
1126 |
scsi_req_cancel(req); |
1127 |
} |
1128 |
sdev->unit_attention = sense; |
1129 |
} |
1130 |
|
1131 |
static char *scsibus_get_fw_dev_path(DeviceState *dev) |
1132 |
{ |
1133 |
SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev); |
1134 |
SCSIBus *bus = scsi_bus_from_device(d); |
1135 |
char path[100]; |
1136 |
int i;
|
1137 |
|
1138 |
for (i = 0; i < bus->ndev; i++) { |
1139 |
if (bus->devs[i] == d) {
|
1140 |
break;
|
1141 |
} |
1142 |
} |
1143 |
|
1144 |
assert(i != bus->ndev); |
1145 |
|
1146 |
snprintf(path, sizeof(path), "%s@%x", qdev_fw_name(dev), i); |
1147 |
|
1148 |
return strdup(path);
|
1149 |
} |