Revision 5c6c0e51 hw/scsi-disk.c
b/hw/scsi-disk.c | ||
---|---|---|
86 | 86 |
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type); |
87 | 87 |
static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf); |
88 | 88 |
|
89 |
static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag,
|
|
89 |
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
|
|
90 | 90 |
uint32_t lun) |
91 | 91 |
{ |
92 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); |
|
92 | 93 |
SCSIRequest *req; |
93 | 94 |
SCSIDiskReq *r; |
94 | 95 |
|
95 | 96 |
req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun); |
96 | 97 |
r = DO_UPCAST(SCSIDiskReq, req, req); |
97 | 98 |
r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE); |
98 |
return r; |
|
99 |
return req;
|
|
99 | 100 |
} |
100 | 101 |
|
101 | 102 |
static void scsi_free_request(SCSIRequest *req) |
... | ... | |
105 | 106 |
qemu_vfree(r->iov.iov_base); |
106 | 107 |
} |
107 | 108 |
|
108 |
static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag) |
|
109 |
{ |
|
110 |
return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag)); |
|
111 |
} |
|
112 |
|
|
113 | 109 |
static void scsi_disk_clear_sense(SCSIDiskState *s) |
114 | 110 |
{ |
115 | 111 |
memset(&s->sense, 0, sizeof(s->sense)); |
... | ... | |
138 | 134 |
} |
139 | 135 |
|
140 | 136 |
/* Cancel a pending data transfer. */ |
141 |
static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
|
|
137 |
static void scsi_cancel_io(SCSIRequest *req)
|
|
142 | 138 |
{ |
143 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); |
|
144 |
SCSIDiskReq *r; |
|
145 |
DPRINTF("Cancel tag=0x%x\n", tag); |
|
146 |
r = scsi_find_request(s, tag); |
|
147 |
if (r) { |
|
148 |
if (r->req.aiocb) |
|
149 |
bdrv_aio_cancel(r->req.aiocb); |
|
150 |
r->req.aiocb = NULL; |
|
151 |
scsi_req_dequeue(&r->req); |
|
139 |
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
|
140 |
|
|
141 |
DPRINTF("Cancel tag=0x%x\n", req->tag); |
|
142 |
if (r->req.aiocb) { |
|
143 |
bdrv_aio_cancel(r->req.aiocb); |
|
152 | 144 |
} |
145 |
r->req.aiocb = NULL; |
|
146 |
scsi_req_dequeue(&r->req); |
|
153 | 147 |
} |
154 | 148 |
|
155 | 149 |
static void scsi_read_complete(void * opaque, int ret) |
... | ... | |
174 | 168 |
} |
175 | 169 |
|
176 | 170 |
|
177 |
static void scsi_read_request(SCSIDiskReq *r) |
|
171 |
/* Read more data from scsi device into buffer. */ |
|
172 |
static void scsi_read_data(SCSIRequest *req) |
|
178 | 173 |
{ |
174 |
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
|
179 | 175 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
180 | 176 |
uint32_t n; |
181 | 177 |
|
... | ... | |
207 | 203 |
} |
208 | 204 |
} |
209 | 205 |
|
210 |
/* Read more data from scsi device into buffer. */ |
|
211 |
static void scsi_read_data(SCSIDevice *d, uint32_t tag) |
|
212 |
{ |
|
213 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); |
|
214 |
SCSIDiskReq *r; |
|
215 |
|
|
216 |
r = scsi_find_request(s, tag); |
|
217 |
if (!r) { |
|
218 |
BADF("Bad read tag 0x%x\n", tag); |
|
219 |
/* ??? This is the wrong error. */ |
|
220 |
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); |
|
221 |
return; |
|
222 |
} |
|
223 |
|
|
224 |
scsi_read_request(r); |
|
225 |
} |
|
226 |
|
|
227 | 206 |
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type) |
228 | 207 |
{ |
229 | 208 |
int is_read = (type == SCSI_REQ_STATUS_RETRY_READ); |
... | ... | |
285 | 264 |
} |
286 | 265 |
} |
287 | 266 |
|
288 |
static void scsi_write_request(SCSIDiskReq *r)
|
|
267 |
static int scsi_write_data(SCSIRequest *req)
|
|
289 | 268 |
{ |
269 |
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
|
290 | 270 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
291 | 271 |
uint32_t n; |
292 | 272 |
|
... | ... | |
305 | 285 |
/* Invoke completion routine to fetch data from host. */ |
306 | 286 |
scsi_write_complete(r, 0); |
307 | 287 |
} |
308 |
} |
|
309 |
|
|
310 |
/* Write data to a scsi device. Returns nonzero on failure. |
|
311 |
The transfer may complete asynchronously. */ |
|
312 |
static int scsi_write_data(SCSIDevice *d, uint32_t tag) |
|
313 |
{ |
|
314 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); |
|
315 |
SCSIDiskReq *r; |
|
316 |
|
|
317 |
DPRINTF("Write data tag=0x%x\n", tag); |
|
318 |
r = scsi_find_request(s, tag); |
|
319 |
if (!r) { |
|
320 |
BADF("Bad write tag 0x%x\n", tag); |
|
321 |
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); |
|
322 |
return 1; |
|
323 |
} |
|
324 |
|
|
325 |
scsi_write_request(r); |
|
326 | 288 |
|
327 | 289 |
return 0; |
328 | 290 |
} |
... | ... | |
347 | 309 |
|
348 | 310 |
switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) { |
349 | 311 |
case SCSI_REQ_STATUS_RETRY_READ: |
350 |
scsi_read_request(r);
|
|
312 |
scsi_read_data(&r->req);
|
|
351 | 313 |
break; |
352 | 314 |
case SCSI_REQ_STATUS_RETRY_WRITE: |
353 |
scsi_write_request(r);
|
|
315 |
scsi_write_data(&r->req);
|
|
354 | 316 |
break; |
355 | 317 |
case SCSI_REQ_STATUS_RETRY_FLUSH: |
356 | 318 |
ret = scsi_disk_emulate_command(r, r->iov.iov_base); |
... | ... | |
376 | 338 |
} |
377 | 339 |
|
378 | 340 |
/* Return a pointer to the data buffer. */ |
379 |
static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
|
|
341 |
static uint8_t *scsi_get_buf(SCSIRequest *req)
|
|
380 | 342 |
{ |
381 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); |
|
382 |
SCSIDiskReq *r; |
|
343 |
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
|
383 | 344 |
|
384 |
r = scsi_find_request(s, tag); |
|
385 |
if (!r) { |
|
386 |
BADF("Bad buffer tag 0x%x\n", tag); |
|
387 |
return NULL; |
|
388 |
} |
|
389 | 345 |
return (uint8_t *)r->iov.iov_base; |
390 | 346 |
} |
391 | 347 |
|
... | ... | |
1029 | 985 |
(eg. disk reads), negative for transfers to the device (eg. disk writes), |
1030 | 986 |
and zero if the command does not transfer any data. */ |
1031 | 987 |
|
1032 |
static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, |
|
1033 |
uint8_t *buf, int lun) |
|
988 |
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) |
|
1034 | 989 |
{ |
1035 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); |
|
990 |
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
|
991 |
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); |
|
1036 | 992 |
int32_t len; |
1037 | 993 |
int is_write; |
1038 | 994 |
uint8_t command; |
1039 | 995 |
uint8_t *outbuf; |
1040 |
SCSIDiskReq *r; |
|
1041 | 996 |
int rc; |
1042 | 997 |
|
998 |
scsi_req_enqueue(req); |
|
1043 | 999 |
command = buf[0]; |
1044 |
r = scsi_find_request(s, tag); |
|
1045 |
if (r) { |
|
1046 |
BADF("Tag 0x%x already in use\n", tag); |
|
1047 |
scsi_cancel_io(d, tag); |
|
1048 |
} |
|
1049 |
/* ??? Tags are not unique for different luns. We only implement a |
|
1050 |
single lun, so this should not matter. */ |
|
1051 |
r = scsi_new_request(s, tag, lun); |
|
1052 | 1000 |
outbuf = (uint8_t *)r->iov.iov_base; |
1053 | 1001 |
is_write = 0; |
1054 | 1002 |
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); |
... | ... | |
1067 | 1015 |
} |
1068 | 1016 |
#endif |
1069 | 1017 |
|
1070 |
if (lun || buf[1] >> 5) { |
|
1018 |
if (req->lun || buf[1] >> 5) {
|
|
1071 | 1019 |
/* Only LUN 0 supported. */ |
1072 |
DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
|
|
1020 |
DPRINTF("Unimplemented LUN %d\n", req->lun ? req->lun : buf[1] >> 5);
|
|
1073 | 1021 |
if (command != REQUEST_SENSE && command != INQUIRY) |
1074 | 1022 |
goto fail; |
1075 | 1023 |
} |
... | ... | |
1095 | 1043 |
case REZERO_UNIT: |
1096 | 1044 |
rc = scsi_disk_emulate_command(r, outbuf); |
1097 | 1045 |
if (rc < 0) { |
1098 |
scsi_req_unref(&r->req); |
|
1099 | 1046 |
return 0; |
1100 | 1047 |
} |
1101 | 1048 |
|
... | ... | |
1105 | 1052 |
case READ_10: |
1106 | 1053 |
case READ_12: |
1107 | 1054 |
case READ_16: |
1108 |
len = r->req.cmd.xfer / d->blocksize;
|
|
1055 |
len = r->req.cmd.xfer / s->qdev.blocksize;
|
|
1109 | 1056 |
DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len); |
1110 | 1057 |
if (r->req.cmd.lba > s->max_lba) |
1111 | 1058 |
goto illegal_lba; |
... | ... | |
1119 | 1066 |
case WRITE_VERIFY: |
1120 | 1067 |
case WRITE_VERIFY_12: |
1121 | 1068 |
case WRITE_VERIFY_16: |
1122 |
len = r->req.cmd.xfer / d->blocksize;
|
|
1069 |
len = r->req.cmd.xfer / s->qdev.blocksize;
|
|
1123 | 1070 |
DPRINTF("Write %s(sector %" PRId64 ", count %d)\n", |
1124 | 1071 |
(command & 0xe) == 0xe ? "And Verify " : "", |
1125 | 1072 |
r->req.cmd.lba, len); |
... | ... | |
1154 | 1101 |
} |
1155 | 1102 |
break; |
1156 | 1103 |
case WRITE_SAME_16: |
1157 |
len = r->req.cmd.xfer / d->blocksize;
|
|
1104 |
len = r->req.cmd.xfer / s->qdev.blocksize;
|
|
1158 | 1105 |
|
1159 | 1106 |
DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n", |
1160 | 1107 |
r->req.cmd.lba, len); |
... | ... | |
1182 | 1129 |
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); |
1183 | 1130 |
fail: |
1184 | 1131 |
scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST); |
1185 |
scsi_req_unref(&r->req); |
|
1186 | 1132 |
return 0; |
1187 | 1133 |
illegal_lba: |
1188 | 1134 |
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); |
1189 |
scsi_req_unref(&r->req); |
|
1190 | 1135 |
return 0; |
1191 | 1136 |
} |
1192 | 1137 |
if (r->sector_count == 0 && r->iov.iov_len == 0) { |
... | ... | |
1199 | 1144 |
if (!r->sector_count) |
1200 | 1145 |
r->sector_count = -1; |
1201 | 1146 |
} |
1202 |
scsi_req_unref(&r->req); |
|
1203 | 1147 |
return len; |
1204 | 1148 |
} |
1205 | 1149 |
|
... | ... | |
1213 | 1157 |
bdrv_aio_cancel(r->req.aiocb); |
1214 | 1158 |
} |
1215 | 1159 |
scsi_req_dequeue(&r->req); |
1160 |
scsi_req_unref(&r->req); |
|
1216 | 1161 |
} |
1217 | 1162 |
} |
1218 | 1163 |
|
... | ... | |
1325 | 1270 |
.qdev.reset = scsi_disk_reset, |
1326 | 1271 |
.init = scsi_hd_initfn, |
1327 | 1272 |
.destroy = scsi_destroy, |
1273 |
.alloc_req = scsi_new_request, |
|
1328 | 1274 |
.free_req = scsi_free_request, |
1329 | 1275 |
.send_command = scsi_send_command, |
1330 | 1276 |
.read_data = scsi_read_data, |
... | ... | |
1344 | 1290 |
.qdev.reset = scsi_disk_reset, |
1345 | 1291 |
.init = scsi_cd_initfn, |
1346 | 1292 |
.destroy = scsi_destroy, |
1293 |
.alloc_req = scsi_new_request, |
|
1347 | 1294 |
.free_req = scsi_free_request, |
1348 | 1295 |
.send_command = scsi_send_command, |
1349 | 1296 |
.read_data = scsi_read_data, |
... | ... | |
1362 | 1309 |
.qdev.reset = scsi_disk_reset, |
1363 | 1310 |
.init = scsi_disk_initfn, |
1364 | 1311 |
.destroy = scsi_destroy, |
1312 |
.alloc_req = scsi_new_request, |
|
1365 | 1313 |
.free_req = scsi_free_request, |
1366 | 1314 |
.send_command = scsi_send_command, |
1367 | 1315 |
.read_data = scsi_read_data, |
Also available in: Unified diff