Revision 8869e103 hw/scsi-generic.c
b/hw/scsi-generic.c | ||
---|---|---|
46 | 46 |
#define MAX_UINT ((unsigned int)-1) |
47 | 47 |
#endif |
48 | 48 |
|
49 |
typedef struct SCSIGenericState SCSIGenericState; |
|
50 |
|
|
51 | 49 |
typedef struct SCSIGenericReq { |
52 | 50 |
SCSIRequest req; |
53 | 51 |
uint8_t *buf; |
... | ... | |
56 | 54 |
sg_io_hdr_t io_header; |
57 | 55 |
} SCSIGenericReq; |
58 | 56 |
|
59 |
struct SCSIGenericState |
|
60 |
{ |
|
61 |
SCSIDevice qdev; |
|
62 |
BlockDriverState *bs; |
|
63 |
}; |
|
64 |
|
|
65 | 57 |
static void scsi_free_request(SCSIRequest *req) |
66 | 58 |
{ |
67 | 59 |
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); |
... | ... | |
174 | 166 |
static void scsi_read_data(SCSIRequest *req) |
175 | 167 |
{ |
176 | 168 |
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); |
177 |
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
|
|
169 |
SCSIDevice *s = r->req.dev;
|
|
178 | 170 |
int ret; |
179 | 171 |
|
180 | 172 |
DPRINTF("scsi_read_data 0x%x\n", req->tag); |
... | ... | |
183 | 175 |
return; |
184 | 176 |
} |
185 | 177 |
|
186 |
ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete); |
|
178 |
ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
|
|
187 | 179 |
if (ret < 0) { |
188 | 180 |
scsi_command_complete(r, ret); |
189 |
return; |
|
190 | 181 |
} |
191 | 182 |
} |
192 | 183 |
|
193 | 184 |
static void scsi_write_complete(void * opaque, int ret) |
194 | 185 |
{ |
195 | 186 |
SCSIGenericReq *r = (SCSIGenericReq *)opaque; |
196 |
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
|
|
187 |
SCSIDevice *s = r->req.dev;
|
|
197 | 188 |
|
198 | 189 |
DPRINTF("scsi_write_complete() ret = %d\n", ret); |
199 | 190 |
r->req.aiocb = NULL; |
... | ... | |
204 | 195 |
} |
205 | 196 |
|
206 | 197 |
if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && |
207 |
s->qdev.type == TYPE_TAPE) {
|
|
208 |
s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
|
|
209 |
DPRINTF("block size %d\n", s->qdev.blocksize);
|
|
198 |
s->type == TYPE_TAPE) { |
|
199 |
s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; |
|
200 |
DPRINTF("block size %d\n", s->blocksize); |
|
210 | 201 |
} |
211 | 202 |
|
212 | 203 |
scsi_command_complete(r, ret); |
... | ... | |
216 | 207 |
The transfer may complete asynchronously. */ |
217 | 208 |
static void scsi_write_data(SCSIRequest *req) |
218 | 209 |
{ |
219 |
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev); |
|
220 | 210 |
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); |
211 |
SCSIDevice *s = r->req.dev; |
|
221 | 212 |
int ret; |
222 | 213 |
|
223 | 214 |
DPRINTF("scsi_write_data 0x%x\n", req->tag); |
... | ... | |
227 | 218 |
return; |
228 | 219 |
} |
229 | 220 |
|
230 |
ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete); |
|
221 |
ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
|
|
231 | 222 |
if (ret < 0) { |
232 | 223 |
scsi_command_complete(r, ret); |
233 | 224 |
} |
... | ... | |
261 | 252 |
|
262 | 253 |
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) |
263 | 254 |
{ |
264 |
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev); |
|
265 | 255 |
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); |
256 |
SCSIDevice *s = r->req.dev; |
|
266 | 257 |
int ret; |
267 | 258 |
|
268 | 259 |
scsi_req_fixup(&r->req); |
... | ... | |
285 | 276 |
g_free(r->buf); |
286 | 277 |
r->buflen = 0; |
287 | 278 |
r->buf = NULL; |
288 |
ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete); |
|
279 |
ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
|
|
289 | 280 |
if (ret < 0) { |
290 | 281 |
scsi_command_complete(r, ret); |
291 | 282 |
return 0; |
... | ... | |
373 | 364 |
|
374 | 365 |
static void scsi_generic_reset(DeviceState *dev) |
375 | 366 |
{ |
376 |
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
|
|
367 |
SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
|
|
377 | 368 |
|
378 |
scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
|
|
369 |
scsi_device_purge_requests(s, SENSE_CODE(RESET));
|
|
379 | 370 |
} |
380 | 371 |
|
381 |
static void scsi_destroy(SCSIDevice *d)
|
|
372 |
static void scsi_destroy(SCSIDevice *s)
|
|
382 | 373 |
{ |
383 |
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); |
|
384 |
|
|
385 |
scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE)); |
|
386 |
blockdev_mark_auto_del(s->qdev.conf.bs); |
|
374 |
scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE)); |
|
375 |
blockdev_mark_auto_del(s->conf.bs); |
|
387 | 376 |
} |
388 | 377 |
|
389 |
static int scsi_generic_initfn(SCSIDevice *dev)
|
|
378 |
static int scsi_generic_initfn(SCSIDevice *s)
|
|
390 | 379 |
{ |
391 |
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev); |
|
392 | 380 |
int sg_version; |
393 | 381 |
struct sg_scsi_id scsiid; |
394 | 382 |
|
395 |
if (!s->qdev.conf.bs) {
|
|
383 |
if (!s->conf.bs) { |
|
396 | 384 |
error_report("scsi-generic: drive property not set"); |
397 | 385 |
return -1; |
398 | 386 |
} |
399 |
s->bs = s->qdev.conf.bs; |
|
400 | 387 |
|
401 | 388 |
/* check we are really using a /dev/sg* file */ |
402 |
if (!bdrv_is_sg(s->bs)) { |
|
389 |
if (!bdrv_is_sg(s->conf.bs)) {
|
|
403 | 390 |
error_report("scsi-generic: not /dev/sg*"); |
404 | 391 |
return -1; |
405 | 392 |
} |
406 | 393 |
|
407 |
if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) { |
|
394 |
if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
|
|
408 | 395 |
error_report("Device doesn't support drive option werror"); |
409 | 396 |
return -1; |
410 | 397 |
} |
411 |
if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) { |
|
398 |
if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) {
|
|
412 | 399 |
error_report("Device doesn't support drive option rerror"); |
413 | 400 |
return -1; |
414 | 401 |
} |
415 | 402 |
|
416 | 403 |
/* check we are using a driver managing SG_IO (version 3 and after */ |
417 |
if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 || |
|
404 |
if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
|
|
418 | 405 |
sg_version < 30000) { |
419 | 406 |
error_report("scsi-generic: scsi generic interface too old"); |
420 | 407 |
return -1; |
421 | 408 |
} |
422 | 409 |
|
423 | 410 |
/* get LUN of the /dev/sg? */ |
424 |
if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) { |
|
411 |
if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
|
|
425 | 412 |
error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed"); |
426 | 413 |
return -1; |
427 | 414 |
} |
428 | 415 |
|
429 | 416 |
/* define device state */ |
430 |
s->qdev.type = scsiid.scsi_type; |
|
431 |
DPRINTF("device type %d\n", s->qdev.type); |
|
432 |
if (s->qdev.type == TYPE_TAPE) { |
|
433 |
s->qdev.blocksize = get_stream_blocksize(s->bs); |
|
434 |
if (s->qdev.blocksize == -1) |
|
435 |
s->qdev.blocksize = 0; |
|
417 |
s->type = scsiid.scsi_type; |
|
418 |
DPRINTF("device type %d\n", s->type); |
|
419 |
if (s->type == TYPE_TAPE) { |
|
420 |
s->blocksize = get_stream_blocksize(s->conf.bs); |
|
421 |
if (s->blocksize == -1) { |
|
422 |
s->blocksize = 0; |
|
423 |
} |
|
436 | 424 |
} else { |
437 |
s->qdev.blocksize = get_blocksize(s->bs);
|
|
425 |
s->blocksize = get_blocksize(s->conf.bs);
|
|
438 | 426 |
/* removable media returns 0 if not present */ |
439 |
if (s->qdev.blocksize <= 0) { |
|
440 |
if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM) |
|
441 |
s->qdev.blocksize = 2048; |
|
442 |
else |
|
443 |
s->qdev.blocksize = 512; |
|
427 |
if (s->blocksize <= 0) { |
|
428 |
if (s->type == TYPE_ROM || s->type == TYPE_WORM) { |
|
429 |
s->blocksize = 2048; |
|
430 |
} else { |
|
431 |
s->blocksize = 512; |
|
432 |
} |
|
444 | 433 |
} |
445 | 434 |
} |
446 |
DPRINTF("block size %d\n", s->qdev.blocksize); |
|
435 |
|
|
436 |
DPRINTF("block size %d\n", s->blocksize); |
|
447 | 437 |
return 0; |
448 | 438 |
} |
449 | 439 |
|
... | ... | |
469 | 459 |
static SCSIDeviceInfo scsi_generic_info = { |
470 | 460 |
.qdev.name = "scsi-generic", |
471 | 461 |
.qdev.desc = "pass through generic scsi device (/dev/sg*)", |
472 |
.qdev.size = sizeof(SCSIGenericState),
|
|
462 |
.qdev.size = sizeof(SCSIDevice),
|
|
473 | 463 |
.qdev.reset = scsi_generic_reset, |
474 | 464 |
.init = scsi_generic_initfn, |
475 | 465 |
.destroy = scsi_destroy, |
476 | 466 |
.alloc_req = scsi_new_request, |
477 | 467 |
.qdev.props = (Property[]) { |
478 |
DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
|
|
468 |
DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
|
|
479 | 469 |
DEFINE_PROP_END_OF_LIST(), |
480 | 470 |
}, |
481 | 471 |
}; |
Also available in: Unified diff