Revision a1f0cce2
b/hw/scsi-bus.c | ||
---|---|---|
154 | 154 |
QTAILQ_INSERT_TAIL(&req->dev->requests, req, next); |
155 | 155 |
} |
156 | 156 |
|
157 |
void scsi_req_dequeue(SCSIRequest *req) |
|
157 |
static void scsi_req_dequeue(SCSIRequest *req)
|
|
158 | 158 |
{ |
159 | 159 |
trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag); |
160 | 160 |
if (req->enqueued) { |
... | ... | |
391 | 391 |
return 0; |
392 | 392 |
} |
393 | 393 |
|
394 |
/* |
|
395 |
* Predefined sense codes |
|
396 |
*/ |
|
397 |
|
|
398 |
/* No sense data available */ |
|
399 |
const struct SCSISense sense_code_NO_SENSE = { |
|
400 |
.key = NO_SENSE , .asc = 0x00 , .ascq = 0x00 |
|
401 |
}; |
|
402 |
|
|
403 |
/* LUN not ready, Manual intervention required */ |
|
404 |
const struct SCSISense sense_code_LUN_NOT_READY = { |
|
405 |
.key = NOT_READY, .asc = 0x04, .ascq = 0x03 |
|
406 |
}; |
|
407 |
|
|
408 |
/* LUN not ready, Medium not present */ |
|
409 |
const struct SCSISense sense_code_NO_MEDIUM = { |
|
410 |
.key = NOT_READY, .asc = 0x3a, .ascq = 0x00 |
|
411 |
}; |
|
412 |
|
|
413 |
/* Hardware error, internal target failure */ |
|
414 |
const struct SCSISense sense_code_TARGET_FAILURE = { |
|
415 |
.key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00 |
|
416 |
}; |
|
417 |
|
|
418 |
/* Illegal request, invalid command operation code */ |
|
419 |
const struct SCSISense sense_code_INVALID_OPCODE = { |
|
420 |
.key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00 |
|
421 |
}; |
|
422 |
|
|
423 |
/* Illegal request, LBA out of range */ |
|
424 |
const struct SCSISense sense_code_LBA_OUT_OF_RANGE = { |
|
425 |
.key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00 |
|
426 |
}; |
|
427 |
|
|
428 |
/* Illegal request, Invalid field in CDB */ |
|
429 |
const struct SCSISense sense_code_INVALID_FIELD = { |
|
430 |
.key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00 |
|
431 |
}; |
|
432 |
|
|
433 |
/* Illegal request, LUN not supported */ |
|
434 |
const struct SCSISense sense_code_LUN_NOT_SUPPORTED = { |
|
435 |
.key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00 |
|
436 |
}; |
|
437 |
|
|
438 |
/* Command aborted, I/O process terminated */ |
|
439 |
const struct SCSISense sense_code_IO_ERROR = { |
|
440 |
.key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06 |
|
441 |
}; |
|
442 |
|
|
443 |
/* Command aborted, I_T Nexus loss occurred */ |
|
444 |
const struct SCSISense sense_code_I_T_NEXUS_LOSS = { |
|
445 |
.key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07 |
|
446 |
}; |
|
447 |
|
|
448 |
/* Command aborted, Logical Unit failure */ |
|
449 |
const struct SCSISense sense_code_LUN_FAILURE = { |
|
450 |
.key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01 |
|
451 |
}; |
|
452 |
|
|
453 |
/* |
|
454 |
* scsi_build_sense |
|
455 |
* |
|
456 |
* Build a sense buffer |
|
457 |
*/ |
|
458 |
int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed) |
|
459 |
{ |
|
460 |
if (!fixed && len < 8) { |
|
461 |
return 0; |
|
462 |
} |
|
463 |
|
|
464 |
memset(buf, 0, len); |
|
465 |
if (fixed) { |
|
466 |
/* Return fixed format sense buffer */ |
|
467 |
buf[0] = 0xf0; |
|
468 |
buf[2] = sense.key; |
|
469 |
buf[7] = 7; |
|
470 |
buf[12] = sense.asc; |
|
471 |
buf[13] = sense.ascq; |
|
472 |
return MIN(len, 18); |
|
473 |
} else { |
|
474 |
/* Return descriptor format sense buffer */ |
|
475 |
buf[0] = 0x72; |
|
476 |
buf[1] = sense.key; |
|
477 |
buf[2] = sense.asc; |
|
478 |
buf[3] = sense.ascq; |
|
479 |
return 8; |
|
480 |
} |
|
481 |
} |
|
482 |
|
|
394 | 483 |
static const char *scsi_command_name(uint8_t cmd) |
395 | 484 |
{ |
396 | 485 |
static const char *names[] = { |
b/hw/scsi-disk.c | ||
---|---|---|
49 | 49 |
|
50 | 50 |
typedef struct SCSIDiskState SCSIDiskState; |
51 | 51 |
|
52 |
typedef struct SCSISense { |
|
53 |
uint8_t key; |
|
54 |
} SCSISense; |
|
55 |
|
|
56 | 52 |
typedef struct SCSIDiskReq { |
57 | 53 |
SCSIRequest req; |
58 | 54 |
/* ??? We should probably keep track of whether the data transfer is |
... | ... | |
111 | 107 |
memset(&s->sense, 0, sizeof(s->sense)); |
112 | 108 |
} |
113 | 109 |
|
114 |
static void scsi_disk_set_sense(SCSIDiskState *s, uint8_t key) |
|
115 |
{ |
|
116 |
s->sense.key = key; |
|
117 |
} |
|
118 |
|
|
119 |
static void scsi_req_set_status(SCSIDiskReq *r, int status, int sense_code) |
|
110 |
static void scsi_req_set_status(SCSIDiskReq *r, int status, SCSISense sense) |
|
120 | 111 |
{ |
121 | 112 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
122 | 113 |
|
123 | 114 |
r->req.status = status; |
124 |
scsi_disk_set_sense(s, sense_code);
|
|
115 |
s->sense = sense;
|
|
125 | 116 |
} |
126 | 117 |
|
127 | 118 |
/* Helper function for command completion. */ |
128 |
static void scsi_command_complete(SCSIDiskReq *r, int status, int sense)
|
|
119 |
static void scsi_command_complete(SCSIDiskReq *r, int status, SCSISense sense)
|
|
129 | 120 |
{ |
130 |
DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", |
|
131 |
r->req.tag, status, sense); |
|
121 |
DPRINTF("Command complete tag=0x%x status=%d sense=%d/%d/%d\n",
|
|
122 |
r->req.tag, status, sense.key, sense.asc, sense.ascq);
|
|
132 | 123 |
scsi_req_set_status(r, status, sense); |
133 | 124 |
scsi_req_complete(&r->req); |
134 | 125 |
} |
... | ... | |
182 | 173 |
} |
183 | 174 |
DPRINTF("Read sector_count=%d\n", r->sector_count); |
184 | 175 |
if (r->sector_count == 0) { |
185 |
scsi_command_complete(r, GOOD, NO_SENSE);
|
|
176 |
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
186 | 177 |
return; |
187 | 178 |
} |
188 | 179 |
|
... | ... | |
225 | 216 |
if (type == SCSI_REQ_STATUS_RETRY_READ) { |
226 | 217 |
scsi_req_data(&r->req, 0); |
227 | 218 |
} |
228 |
scsi_command_complete(r, CHECK_CONDITION, |
|
229 |
HARDWARE_ERROR); |
|
219 |
if (error == ENOMEM) { |
|
220 |
scsi_command_complete(r, CHECK_CONDITION, |
|
221 |
SENSE_CODE(TARGET_FAILURE)); |
|
222 |
} else { |
|
223 |
scsi_command_complete(r, CHECK_CONDITION, |
|
224 |
SENSE_CODE(IO_ERROR)); |
|
225 |
} |
|
230 | 226 |
bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read); |
231 | 227 |
} |
232 | 228 |
|
... | ... | |
251 | 247 |
r->sector += n; |
252 | 248 |
r->sector_count -= n; |
253 | 249 |
if (r->sector_count == 0) { |
254 |
scsi_command_complete(r, GOOD, NO_SENSE);
|
|
250 |
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
255 | 251 |
} else { |
256 | 252 |
len = r->sector_count * 512; |
257 | 253 |
if (len > SCSI_DMA_BUF_SIZE) { |
... | ... | |
278 | 274 |
r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n, |
279 | 275 |
scsi_write_complete, r); |
280 | 276 |
if (r->req.aiocb == NULL) { |
281 |
scsi_write_complete(r, -EIO);
|
|
277 |
scsi_write_complete(r, -ENOMEM);
|
|
282 | 278 |
} |
283 | 279 |
} else { |
284 | 280 |
/* Invoke completion routine to fetch data from host. */ |
... | ... | |
316 | 312 |
case SCSI_REQ_STATUS_RETRY_FLUSH: |
317 | 313 |
ret = scsi_disk_emulate_command(r, r->iov.iov_base); |
318 | 314 |
if (ret == 0) { |
319 |
scsi_command_complete(r, GOOD, NO_SENSE);
|
|
315 |
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
320 | 316 |
} |
321 | 317 |
} |
322 | 318 |
} |
... | ... | |
815 | 811 |
case REQUEST_SENSE: |
816 | 812 |
if (req->cmd.xfer < 4) |
817 | 813 |
goto illegal_request; |
818 |
memset(outbuf, 0, 4); |
|
819 |
buflen = 4; |
|
820 |
if (s->sense.key == NOT_READY && req->cmd.xfer >= 18) { |
|
821 |
memset(outbuf, 0, 18); |
|
822 |
buflen = 18; |
|
823 |
outbuf[7] = 10; |
|
824 |
/* asc 0x3a, ascq 0: Medium not present */ |
|
825 |
outbuf[12] = 0x3a; |
|
826 |
outbuf[13] = 0; |
|
827 |
} |
|
828 |
outbuf[0] = 0xf0; |
|
829 |
outbuf[1] = 0; |
|
830 |
outbuf[2] = s->sense.key; |
|
814 |
buflen = scsi_build_sense(s->sense, outbuf, req->cmd.xfer, |
|
815 |
req->cmd.xfer > 13); |
|
831 | 816 |
scsi_disk_clear_sense(s); |
832 | 817 |
break; |
833 | 818 |
case INQUIRY: |
... | ... | |
965 | 950 |
} |
966 | 951 |
break; |
967 | 952 |
default: |
968 |
goto illegal_request; |
|
953 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE)); |
|
954 |
return -1; |
|
969 | 955 |
} |
970 |
scsi_req_set_status(r, GOOD, NO_SENSE);
|
|
956 |
scsi_req_set_status(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
971 | 957 |
return buflen; |
972 | 958 |
|
973 | 959 |
not_ready: |
974 |
scsi_command_complete(r, CHECK_CONDITION, NOT_READY); |
|
960 |
if (!bdrv_is_inserted(s->bs)) { |
|
961 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(NO_MEDIUM)); |
|
962 |
} else { |
|
963 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LUN_NOT_READY)); |
|
964 |
} |
|
975 | 965 |
return -1; |
976 | 966 |
|
977 | 967 |
illegal_request: |
978 |
scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
|
|
968 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
|
|
979 | 969 |
return -1; |
980 | 970 |
} |
981 | 971 |
|
... | ... | |
1002 | 992 |
|
1003 | 993 |
if (scsi_req_parse(&r->req, buf) != 0) { |
1004 | 994 |
BADF("Unsupported command length, command %x\n", command); |
1005 |
goto fail; |
|
995 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE)); |
|
996 |
return 0; |
|
1006 | 997 |
} |
1007 | 998 |
#ifdef DEBUG_SCSI |
1008 | 999 |
{ |
... | ... | |
1017 | 1008 |
if (req->lun || buf[1] >> 5) { |
1018 | 1009 |
/* Only LUN 0 supported. */ |
1019 | 1010 |
DPRINTF("Unimplemented LUN %d\n", req->lun ? req->lun : buf[1] >> 5); |
1020 |
if (command != REQUEST_SENSE && command != INQUIRY) |
|
1021 |
goto fail; |
|
1011 |
if (command != REQUEST_SENSE && command != INQUIRY) { |
|
1012 |
scsi_command_complete(r, CHECK_CONDITION, |
|
1013 |
SENSE_CODE(LUN_NOT_SUPPORTED)); |
|
1014 |
return 0; |
|
1015 |
} |
|
1022 | 1016 |
} |
1023 | 1017 |
switch (command) { |
1024 | 1018 |
case TEST_UNIT_READY: |
... | ... | |
1126 | 1120 |
break; |
1127 | 1121 |
default: |
1128 | 1122 |
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); |
1123 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE)); |
|
1124 |
return 0; |
|
1129 | 1125 |
fail: |
1130 |
scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
|
|
1126 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
|
|
1131 | 1127 |
return 0; |
1132 | 1128 |
illegal_lba: |
1133 |
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
|
|
1129 |
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LBA_OUT_OF_RANGE));
|
|
1134 | 1130 |
return 0; |
1135 | 1131 |
} |
1136 | 1132 |
if (r->sector_count == 0 && r->iov.iov_len == 0) { |
1137 |
scsi_command_complete(r, GOOD, NO_SENSE);
|
|
1133 |
scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
|
|
1138 | 1134 |
} |
1139 | 1135 |
len = r->sector_count * 512 + r->iov.iov_len; |
1140 | 1136 |
if (is_write) { |
b/hw/scsi-generic.c | ||
---|---|---|
66 | 66 |
uint8_t senselen; |
67 | 67 |
}; |
68 | 68 |
|
69 |
static void scsi_set_sense(SCSIGenericState *s, SCSISense sense) |
|
70 |
{ |
|
71 |
s->senselen = scsi_build_sense(sense, s->sensebuf, SCSI_SENSE_BUF_SIZE, 0); |
|
72 |
s->driver_status = SG_ERR_DRIVER_SENSE; |
|
73 |
} |
|
74 |
|
|
75 |
static void scsi_clear_sense(SCSIGenericState *s) |
|
76 |
{ |
|
77 |
memset(s->sensebuf, 0, SCSI_SENSE_BUF_SIZE); |
|
78 |
s->senselen = 0; |
|
79 |
s->driver_status = 0; |
|
80 |
} |
|
81 |
|
|
69 | 82 |
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) |
70 | 83 |
{ |
71 | 84 |
SCSIRequest *req; |
... | ... | |
92 | 105 |
if (s->driver_status & SG_ERR_DRIVER_SENSE) |
93 | 106 |
s->senselen = r->io_header.sb_len_wr; |
94 | 107 |
|
95 |
if (ret != 0) |
|
96 |
r->req.status = BUSY; |
|
97 |
else { |
|
108 |
if (ret != 0) { |
|
109 |
switch (ret) { |
|
110 |
case -EINVAL: |
|
111 |
r->req.status = CHECK_CONDITION; |
|
112 |
scsi_set_sense(s, SENSE_CODE(INVALID_FIELD)); |
|
113 |
break; |
|
114 |
case -ENOMEM: |
|
115 |
r->req.status = CHECK_CONDITION; |
|
116 |
scsi_set_sense(s, SENSE_CODE(TARGET_FAILURE)); |
|
117 |
break; |
|
118 |
default: |
|
119 |
r->req.status = CHECK_CONDITION; |
|
120 |
scsi_set_sense(s, SENSE_CODE(IO_ERROR)); |
|
121 |
break; |
|
122 |
} |
|
123 |
} else { |
|
98 | 124 |
if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) { |
99 | 125 |
r->req.status = BUSY; |
100 | 126 |
BADF("Driver Timeout\n"); |
... | ... | |
144 | 170 |
r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r); |
145 | 171 |
if (r->req.aiocb == NULL) { |
146 | 172 |
BADF("execute_command: read failed !\n"); |
147 |
return -1;
|
|
173 |
return -ENOMEM;
|
|
148 | 174 |
} |
149 | 175 |
|
150 | 176 |
return 0; |
... | ... | |
198 | 224 |
r->buf[0], r->buf[1], r->buf[2], r->buf[3], |
199 | 225 |
r->buf[4], r->buf[5], r->buf[6], r->buf[7]); |
200 | 226 |
scsi_req_data(&r->req, s->senselen); |
227 |
/* Clear sensebuf after REQUEST_SENSE */ |
|
228 |
scsi_clear_sense(s); |
|
201 | 229 |
return; |
202 | 230 |
} |
203 | 231 |
|
204 | 232 |
ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete); |
205 |
if (ret == -1) {
|
|
206 |
scsi_command_complete(r, -EINVAL);
|
|
233 |
if (ret < 0) {
|
|
234 |
scsi_command_complete(r, ret);
|
|
207 | 235 |
return; |
208 | 236 |
} |
209 | 237 |
} |
... | ... | |
246 | 274 |
} |
247 | 275 |
|
248 | 276 |
ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete); |
249 |
if (ret == -1) {
|
|
250 |
scsi_command_complete(r, -EINVAL);
|
|
277 |
if (ret < 0) {
|
|
278 |
scsi_command_complete(r, ret);
|
|
251 | 279 |
return 1; |
252 | 280 |
} |
253 | 281 |
|
... | ... | |
296 | 324 |
if (cmd[0] != REQUEST_SENSE && |
297 | 325 |
(req->lun != s->lun || (cmd[1] >> 5) != s->lun)) { |
298 | 326 |
DPRINTF("Unimplemented LUN %d\n", req->lun ? req->lun : cmd[1] >> 5); |
299 |
|
|
300 |
s->sensebuf[0] = 0x70; |
|
301 |
s->sensebuf[1] = 0x00; |
|
302 |
s->sensebuf[2] = ILLEGAL_REQUEST; |
|
303 |
s->sensebuf[3] = 0x00; |
|
304 |
s->sensebuf[4] = 0x00; |
|
305 |
s->sensebuf[5] = 0x00; |
|
306 |
s->sensebuf[6] = 0x00; |
|
307 |
s->senselen = 7; |
|
308 |
s->driver_status = SG_ERR_DRIVER_SENSE; |
|
327 |
scsi_set_sense(s, SENSE_CODE(LUN_NOT_SUPPORTED)); |
|
309 | 328 |
r->req.status = CHECK_CONDITION; |
310 | 329 |
scsi_req_complete(&r->req); |
311 | 330 |
return 0; |
... | ... | |
313 | 332 |
|
314 | 333 |
if (-1 == scsi_req_parse(&r->req, cmd)) { |
315 | 334 |
BADF("Unsupported command length, command %x\n", cmd[0]); |
316 |
scsi_req_dequeue(&r->req); |
|
317 |
scsi_req_unref(&r->req); |
|
335 |
scsi_command_complete(r, -EINVAL); |
|
318 | 336 |
return 0; |
319 | 337 |
} |
320 | 338 |
scsi_req_fixup(&r->req); |
... | ... | |
338 | 356 |
r->buflen = 0; |
339 | 357 |
r->buf = NULL; |
340 | 358 |
ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete); |
341 |
if (ret == -1) { |
|
342 |
scsi_command_complete(r, -EINVAL); |
|
359 |
if (ret < 0) { |
|
360 |
scsi_command_complete(r, ret); |
|
361 |
return 0; |
|
343 | 362 |
} |
344 | 363 |
return 0; |
345 | 364 |
} |
b/hw/scsi.h | ||
---|---|---|
27 | 27 |
SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */ |
28 | 28 |
}; |
29 | 29 |
|
30 |
typedef struct SCSISense { |
|
31 |
uint8_t key; |
|
32 |
uint8_t asc; |
|
33 |
uint8_t ascq; |
|
34 |
} SCSISense; |
|
35 |
|
|
30 | 36 |
struct SCSIRequest { |
31 | 37 |
SCSIBus *bus; |
32 | 38 |
SCSIDevice *dev; |
... | ... | |
104 | 110 |
int unit, bool removable); |
105 | 111 |
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus); |
106 | 112 |
|
113 |
/* |
|
114 |
* Predefined sense codes |
|
115 |
*/ |
|
116 |
|
|
117 |
/* No sense data available */ |
|
118 |
extern const struct SCSISense sense_code_NO_SENSE; |
|
119 |
/* LUN not ready, Manual intervention required */ |
|
120 |
extern const struct SCSISense sense_code_LUN_NOT_READY; |
|
121 |
/* LUN not ready, Medium not present */ |
|
122 |
extern const struct SCSISense sense_code_NO_MEDIUM; |
|
123 |
/* Hardware error, internal target failure */ |
|
124 |
extern const struct SCSISense sense_code_TARGET_FAILURE; |
|
125 |
/* Illegal request, invalid command operation code */ |
|
126 |
extern const struct SCSISense sense_code_INVALID_OPCODE; |
|
127 |
/* Illegal request, LBA out of range */ |
|
128 |
extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE; |
|
129 |
/* Illegal request, Invalid field in CDB */ |
|
130 |
extern const struct SCSISense sense_code_INVALID_FIELD; |
|
131 |
/* Illegal request, LUN not supported */ |
|
132 |
extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED; |
|
133 |
/* Command aborted, I/O process terminated */ |
|
134 |
extern const struct SCSISense sense_code_IO_ERROR; |
|
135 |
/* Command aborted, I_T Nexus loss occurred */ |
|
136 |
extern const struct SCSISense sense_code_I_T_NEXUS_LOSS; |
|
137 |
/* Command aborted, Logical Unit failure */ |
|
138 |
extern const struct SCSISense sense_code_LUN_FAILURE; |
|
139 |
|
|
140 |
#define SENSE_CODE(x) sense_code_ ## x |
|
141 |
|
|
142 |
int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed); |
|
143 |
int scsi_sense_valid(SCSISense sense); |
|
144 |
|
|
107 | 145 |
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun); |
108 | 146 |
void scsi_req_enqueue(SCSIRequest *req); |
109 | 147 |
void scsi_req_free(SCSIRequest *req); |
110 |
void scsi_req_dequeue(SCSIRequest *req); |
|
111 | 148 |
SCSIRequest *scsi_req_ref(SCSIRequest *req); |
112 | 149 |
void scsi_req_unref(SCSIRequest *req); |
113 | 150 |
|
Also available in: Unified diff