?? scsi-generic.c
字號:
/* * Generic SCSI Device support * * Copyright (c) 2007 Bull S.A.S. * Based on code by Paul Brook * Based on code by Fabrice Bellard * * Written by Laurent Vivier <Laurent.Vivier@bull.net> * * This code is licenced under the LGPL. * */#include "qemu-common.h"#include "block.h"#include "scsi-disk.h"#ifndef __linux__SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq, scsi_completionfn completion, void *opaque){ return NULL;}#else /* __linux__ *///#define DEBUG_SCSI#ifdef DEBUG_SCSI#define DPRINTF(fmt, args...) \do { printf("scsi-generic: " fmt , ##args); } while (0)#else#define DPRINTF(fmt, args...) do {} while(0)#endif#define BADF(fmt, args...) \do { fprintf(stderr, "scsi-generic: " fmt , ##args); } while (0)#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <scsi/sg.h>#include <scsi/scsi.h>#define LOAD_UNLOAD 0xa6#define SET_CD_SPEED 0xbb#define BLANK 0xa1#define SCSI_CMD_BUF_SIZE 16#define SCSI_SENSE_BUF_SIZE 32#define SG_ERR_DRIVER_TIMEOUT 0x06#define SG_ERR_DRIVER_SENSE 0x08#ifndef MAX_UINT#define MAX_UINT ((unsigned int)-1)#endiftypedef struct SCSIRequest { BlockDriverAIOCB *aiocb; struct SCSIRequest *next; SCSIDeviceState *dev; uint32_t tag; uint8_t cmd[SCSI_CMD_BUF_SIZE]; int cmdlen; uint8_t *buf; int buflen; int len; sg_io_hdr_t io_header;} SCSIRequest;struct SCSIDeviceState{ SCSIRequest *requests; BlockDriverState *bdrv; int blocksize; int lun; scsi_completionfn completion; void *opaque; int driver_status; uint8_t sensebuf[SCSI_SENSE_BUF_SIZE];};/* Global pool of SCSIRequest structures. */static SCSIRequest *free_requests = NULL;static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag){ SCSIRequest *r; if (free_requests) { r = free_requests; free_requests = r->next; } else { r = qemu_malloc(sizeof(SCSIRequest)); r->buf = NULL; r->buflen = 0; } r->dev = s; r->tag = tag; memset(r->cmd, 0, sizeof(r->cmd)); memset(&r->io_header, 0, sizeof(r->io_header)); r->cmdlen = 0; r->len = 0; r->aiocb = NULL; /* link */ r->next = s->requests; s->requests = r; return r;}static void scsi_remove_request(SCSIRequest *r){ SCSIRequest *last; SCSIDeviceState *s = r->dev; if (s->requests == r) { s->requests = r->next; } else { last = s->requests; while (last && last->next != r) last = last->next; if (last) { last->next = r->next; } else { BADF("Orphaned request\n"); } } r->next = free_requests; free_requests = r;}static SCSIRequest *scsi_find_request(SCSIDeviceState *s, uint32_t tag){ SCSIRequest *r; r = s->requests; while (r && r->tag != tag) r = r->next; return r;}/* Helper function for command completion. */static void scsi_command_complete(void *opaque, int ret){ SCSIRequest *r = (SCSIRequest *)opaque; SCSIDeviceState *s = r->dev; uint32_t tag; int sense; s->driver_status = r->io_header.driver_status; if (ret != 0) sense = HARDWARE_ERROR; else { if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) { sense = HARDWARE_ERROR; BADF("Driver Timeout\n"); } else if ((s->driver_status & SG_ERR_DRIVER_SENSE) == 0) sense = NO_SENSE; else sense = s->sensebuf[2] & 0x0f; } DPRINTF("Command complete 0x%p tag=0x%x sense=%d\n", r, r->tag, sense); tag = r->tag; scsi_remove_request(r); s->completion(s->opaque, SCSI_REASON_DONE, tag, sense);}/* Cancel a pending data transfer. */static void scsi_cancel_io(SCSIDevice *d, uint32_t tag){ DPRINTF("scsi_cancel_io 0x%x\n", tag); SCSIDeviceState *s = d->state; SCSIRequest *r; DPRINTF("Cancel tag=0x%x\n", tag); r = scsi_find_request(s, tag); if (r) { if (r->aiocb) bdrv_aio_cancel(r->aiocb); r->aiocb = NULL; scsi_remove_request(r); }}static int execute_command(BlockDriverState *bdrv, SCSIRequest *r, int direction, BlockDriverCompletionFunc *complete){ r->io_header.interface_id = 'S'; r->io_header.dxfer_direction = direction; r->io_header.dxferp = r->buf; r->io_header.dxfer_len = r->buflen; r->io_header.cmdp = r->cmd; r->io_header.cmd_len = r->cmdlen; r->io_header.mx_sb_len = sizeof(r->dev->sensebuf); r->io_header.sbp = r->dev->sensebuf; r->io_header.timeout = MAX_UINT; r->io_header.usr_ptr = r; r->io_header.flags |= SG_FLAG_DIRECT_IO; if (bdrv_pwrite(bdrv, -1, &r->io_header, sizeof(r->io_header)) == -1) { BADF("execute_command: write failed ! (%d)\n", errno); return -1; } if (complete == NULL) { int ret; r->aiocb = NULL; while ((ret = bdrv_pread(bdrv, -1, &r->io_header, sizeof(r->io_header))) == -1 && errno == EINTR); if (ret == -1) { BADF("execute_command: read failed !\n"); return -1; } return 0; } r->aiocb = bdrv_aio_read(bdrv, 0, (uint8_t*)&r->io_header, -(int64_t)sizeof(r->io_header), complete, r); if (r->aiocb == NULL) { BADF("execute_command: read failed !\n"); return -1; } return 0;}static void scsi_read_complete(void * opaque, int ret){ SCSIRequest *r = (SCSIRequest *)opaque; SCSIDeviceState *s = r->dev; int len; if (ret) { DPRINTF("IO error\n"); scsi_command_complete(r, ret); return; } len = r->io_header.dxfer_len - r->io_header.resid; DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, len); r->len = -1; s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);}/* Read more data from scsi device into buffer. */static void scsi_read_data(SCSIDevice *d, uint32_t tag){ SCSIDeviceState *s = d->state; SCSIRequest *r; int ret; DPRINTF("scsi_read_data 0x%x\n", tag); r = scsi_find_request(s, tag); if (!r) { BADF("Bad read tag 0x%x\n", tag); /* ??? This is the wrong error. */ scsi_command_complete(r, -EINVAL); return; } if (r->len == -1) { scsi_command_complete(r, 0); return; } if (r->cmd[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE) { memcpy(r->buf, s->sensebuf, 16); r->io_header.driver_status = 0; r->len = -1; s->completion(s->opaque, SCSI_REASON_DATA, r->tag, 16); return; } ret = execute_command(s->bdrv, r, SG_DXFER_FROM_DEV, scsi_read_complete); if (ret == -1) { scsi_command_complete(r, -EINVAL); return; }}static void scsi_write_complete(void * opaque, int ret){ SCSIRequest *r = (SCSIRequest *)opaque; DPRINTF("scsi_write_complete() ret = %d\n", ret); if (ret) { DPRINTF("IO error\n"); scsi_command_complete(r, ret); return; } scsi_command_complete(r, ret);}/* Write data to a scsi device. Returns nonzero on failure. The transfer may complete asynchronously. */static int scsi_write_data(SCSIDevice *d, uint32_t tag){ SCSIDeviceState *s = d->state; SCSIRequest *r; int ret; DPRINTF("scsi_write_data 0x%x\n", tag); r = scsi_find_request(s, tag); if (!r) { BADF("Bad write tag 0x%x\n", tag); /* ??? This is the wrong error. */ scsi_command_complete(r, -EINVAL); return 0; } if (r->len == 0) { r->len = r->buflen; s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->len); return 0; } ret = execute_command(s->bdrv, r, SG_DXFER_TO_DEV, scsi_write_complete);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -