Commit ed7ec840 authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'bonzini/scsi.2' into staging

Conflicts:
	hw/usb-msd.c
parents f590f4c4 1455084e
Loading
Loading
Loading
Loading
+70 −49
Original line number Diff line number Diff line
@@ -61,10 +61,11 @@ struct ESPState {
    int32_t ti_size;
    uint32_t ti_rptr, ti_wptr;
    uint8_t ti_buf[TI_BUFSZ];
    uint32_t sense;
    uint32_t status;
    uint32_t dma;
    SCSIBus bus;
    SCSIDevice *current_dev;
    SCSIRequest *current_req;
    uint8_t cmdbuf[TI_BUFSZ];
    uint32_t cmdlen;
    uint32_t do_cmd;
@@ -187,6 +188,17 @@ static void esp_dma_enable(void *opaque, int irq, int level)
    }
}

static void esp_request_cancelled(SCSIRequest *req)
{
    ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);

    if (req == s->current_req) {
        scsi_req_unref(s->current_req);
        s->current_req = NULL;
        s->current_dev = NULL;
    }
}

static uint32_t get_cmd(ESPState *s, uint8_t *buf)
{
    uint32_t dmalen;
@@ -209,7 +221,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)

    if (s->current_dev) {
        /* Started a new command before the old one finished.  Cancel it.  */
        s->current_dev->info->cancel_io(s->current_dev, 0);
        scsi_req_cancel(s->current_req);
        s->async_len = 0;
    }

@@ -232,7 +244,8 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)

    DPRINTF("do_busid_cmd: busid 0x%x\n", busid);
    lun = busid & 7;
    datalen = s->current_dev->info->send_command(s->current_dev, 0, buf, lun);
    s->current_req = scsi_req_new(s->current_dev, 0, lun);
    datalen = scsi_req_enqueue(s->current_req, buf);
    s->ti_size = datalen;
    if (datalen != 0) {
        s->rregs[ESP_RSTAT] = STAT_TC;
@@ -240,11 +253,10 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
        s->dma_counter = 0;
        if (datalen > 0) {
            s->rregs[ESP_RSTAT] |= STAT_DI;
            s->current_dev->info->read_data(s->current_dev, 0);
        } else {
            s->rregs[ESP_RSTAT] |= STAT_DO;
            s->current_dev->info->write_data(s->current_dev, 0);
        }
        scsi_req_continue(s->current_req);
    }
    s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
    s->rregs[ESP_RSEQ] = SEQ_CD;
@@ -306,8 +318,8 @@ static void handle_satn_stop(ESPState *s)

static void write_response(ESPState *s)
{
    DPRINTF("Transfer status (sense=%d)\n", s->sense);
    s->ti_buf[0] = s->sense;
    DPRINTF("Transfer status (status=%d)\n", s->status);
    s->ti_buf[0] = s->status;
    s->ti_buf[1] = 0;
    if (s->dma) {
        s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
@@ -370,46 +382,50 @@ static void esp_do_dma(ESPState *s)
    else
        s->ti_size -= len;
    if (s->async_len == 0) {
        if (to_device) {
            // ti_size is negative
            s->current_dev->info->write_data(s->current_dev, 0);
        } else {
            s->current_dev->info->read_data(s->current_dev, 0);
        scsi_req_continue(s->current_req);
        /* If there is still data to be read from the device then
           complete the DMA operation immediately.  Otherwise defer
           until the scsi layer has completed.  */
            if (s->dma_left == 0 && s->ti_size > 0) {
                esp_dma_done(s);
        if (to_device || s->dma_left != 0 || s->ti_size == 0) {
            return;
        }
    }
    } else {

    /* Partially filled a scsi buffer. Complete immediately.  */
    esp_dma_done(s);
}
}

static void esp_command_complete(SCSIBus *bus, int reason, uint32_t tag,
                                 uint32_t arg)
static void esp_command_complete(SCSIRequest *req, uint32_t status)
{
    ESPState *s = DO_UPCAST(ESPState, busdev.qdev, bus->qbus.parent);
    ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);

    if (reason == SCSI_REASON_DONE) {
    DPRINTF("SCSI Command complete\n");
        if (s->ti_size != 0)
    if (s->ti_size != 0) {
        DPRINTF("SCSI command completed unexpectedly\n");
    }
    s->ti_size = 0;
    s->dma_left = 0;
    s->async_len = 0;
        if (arg)
    if (status) {
        DPRINTF("Command failed\n");
        s->sense = arg;
    }
    s->status = status;
    s->rregs[ESP_RSTAT] = STAT_ST;
    esp_dma_done(s);
    if (s->current_req) {
        scsi_req_unref(s->current_req);
        s->current_req = NULL;
        s->current_dev = NULL;
    } else {
    }
}

static void esp_transfer_data(SCSIRequest *req, uint32_t len)
{
    ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);

    DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
        s->async_len = arg;
        s->async_buf = s->current_dev->info->get_buf(s->current_dev, 0);
    s->async_len = len;
    s->async_buf = scsi_req_get_buf(req);
    if (s->dma_left) {
        esp_do_dma(s);
    } else if (s->dma_counter != 0 && s->ti_size <= 0) {
@@ -418,7 +434,6 @@ static void esp_command_complete(SCSIBus *bus, int reason, uint32_t tag,
        esp_dma_done(s);
    }
}
}

static void handle_ti(ESPState *s)
{
@@ -678,7 +693,7 @@ static const VMStateDescription vmstate_esp = {
        VMSTATE_UINT32(ti_rptr, ESPState),
        VMSTATE_UINT32(ti_wptr, ESPState),
        VMSTATE_BUFFER(ti_buf, ESPState),
        VMSTATE_UINT32(sense, ESPState),
        VMSTATE_UINT32(status, ESPState),
        VMSTATE_UINT32(dma, ESPState),
        VMSTATE_BUFFER(cmdbuf, ESPState),
        VMSTATE_UINT32(cmdlen, ESPState),
@@ -714,6 +729,12 @@ void esp_init(target_phys_addr_t espaddr, int it_shift,
    *dma_enable = qdev_get_gpio_in(dev, 1);
}

static const struct SCSIBusOps esp_scsi_ops = {
    .transfer_data = esp_transfer_data,
    .complete = esp_command_complete,
    .cancel = esp_request_cancelled
};

static int esp_init1(SysBusDevice *dev)
{
    ESPState *s = FROM_SYSBUS(ESPState, dev);
@@ -728,7 +749,7 @@ static int esp_init1(SysBusDevice *dev)

    qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2);

    scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, esp_command_complete);
    scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, &esp_scsi_ops);
    return scsi_bus_legacy_handle_cmdline(&s->bus);
}

+123 −77
Original line number Diff line number Diff line
@@ -174,6 +174,7 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
#define LSI_TAG_VALID     (1 << 16)

typedef struct lsi_request {
    SCSIRequest *req;
    uint32_t tag;
    uint32_t dma_len;
    uint8_t *dma_buf;
@@ -567,11 +568,9 @@ static void lsi_do_dma(LSIState *s, int out)
    s->csbc += count;
    s->dnad += count;
    s->dbc -= count;

     if (s->current->dma_buf == NULL) {
        s->current->dma_buf = dev->info->get_buf(dev, s->current->tag);
        s->current->dma_buf = scsi_req_get_buf(s->current->req);
    }

    /* ??? Set SFBR to first data byte.  */
    if (out) {
        cpu_physical_memory_read(addr, s->current->dma_buf, count);
@@ -581,13 +580,7 @@ static void lsi_do_dma(LSIState *s, int out)
    s->current->dma_len -= count;
    if (s->current->dma_len == 0) {
        s->current->dma_buf = NULL;
        if (out) {
            /* Write the data.  */
            dev->info->write_data(dev, s->current->tag);
        } else {
            /* Request any remaining data.  */
            dev->info->read_data(dev, s->current->tag);
        }
        scsi_req_continue(s->current->req);
    } else {
        s->current->dma_buf += count;
        lsi_resume_script(s);
@@ -652,18 +645,55 @@ static void lsi_reselect(LSIState *s, lsi_request *p)
    }
}

/* Record that data is available for a queued command.  Returns zero if
   the device was reselected, nonzero if the IO is deferred.  */
static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
{
    lsi_request *p;

    QTAILQ_FOREACH(p, &s->queue, next) {
        if (p->tag == tag) {
            return p;
        }
    }

    return NULL;
}

static void lsi_request_cancelled(SCSIRequest *req)
{
    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
    lsi_request *p;

    if (s->current && req == s->current->req) {
        scsi_req_unref(req);
        qemu_free(s->current);
        s->current = NULL;
        return;
    }

    p = lsi_find_by_tag(s, req->tag);
    if (p) {
        QTAILQ_REMOVE(&s->queue, p, next);
        scsi_req_unref(req);
        qemu_free(p);
    }
}

/* Record that data is available for a queued command.  Returns zero if
   the device was reselected, nonzero if the IO is deferred.  */
static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t len)
{
    lsi_request *p;

    p = lsi_find_by_tag(s, tag);
    if (!p) {
        BADF("IO with unknown tag %d\n", tag);
        return 1;
    }

    if (p->pending) {
        BADF("Multiple IO pending for tag %d\n", tag);
    }
            p->pending = arg;
    p->pending = len;
    /* Reselect if waiting for it, or if reselection triggers an IRQ
       and the bus is free.
       Since no interrupt stacking is implemented in the emulation, it
@@ -677,26 +707,20 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
        return 0;
    } else {
        DPRINTF("Queueing IO tag=0x%x\n", tag);
                p->pending = arg;
        p->pending = len;
        return 1;
    }
}
    }
    BADF("IO with unknown tag %d\n", tag);
    return 1;
}

/* Callback to indicate that the SCSI layer has completed a transfer.  */
static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
                                 uint32_t arg)
 /* Callback to indicate that the SCSI layer has completed a command.  */
static void lsi_command_complete(SCSIRequest *req, uint32_t status)
{
    LSIState *s = DO_UPCAST(LSIState, dev.qdev, bus->qbus.parent);
    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
    int out;

    out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
    if (reason == SCSI_REASON_DONE) {
        DPRINTF("Command complete status=%d\n", (int)arg);
        s->status = arg;
    DPRINTF("Command complete status=%d\n", (int)status);
    s->status = status;
    s->command_complete = 2;
    if (s->waiting && s->dbc != 0) {
        /* Raise phase mismatch for short transfers.  */
@@ -705,31 +729,41 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
        lsi_set_phase(s, PHASE_ST);
    }

    if (s->current && req == s->current->req) {
        scsi_req_unref(s->current->req);
        qemu_free(s->current);
        s->current = NULL;

    }
    lsi_resume_script(s);
        return;
}

    if (s->waiting == 1 || !s->current || tag != s->current->tag ||
 /* Callback to indicate that the SCSI layer has completed a transfer.  */
static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
{
    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
    int out;

    if (s->waiting == 1 || !s->current || req->tag != s->current->tag ||
        (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
        if (lsi_queue_tag(s, tag, arg))
        if (lsi_queue_tag(s, req->tag, len)) {
            return;
        }
    }

    out = (s->sstat1 & PHASE_MASK) == PHASE_DO;

    /* host adapter (re)connected */
    DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg);
    s->current->dma_len = arg;
    DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, len);
    s->current->dma_len = len;
    s->command_complete = 1;
    if (!s->waiting)
        return;
    if (s->waiting) {
        if (s->waiting == 1 || s->dbc == 0) {
            lsi_resume_script(s);
        } else {
            lsi_do_dma(s, out);
        }
    }
}

static void lsi_do_command(LSIState *s)
{
@@ -755,16 +789,17 @@ static void lsi_do_command(LSIState *s)
    assert(s->current == NULL);
    s->current = qemu_mallocz(sizeof(lsi_request));
    s->current->tag = s->select_tag;
    s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun);

    n = dev->info->send_command(dev, s->current->tag, buf, s->current_lun);
    n = scsi_req_enqueue(s->current->req, buf);
    if (n) {
        if (n > 0) {
            lsi_set_phase(s, PHASE_DI);
        dev->info->read_data(dev, s->current->tag);
        } else if (n < 0) {
            lsi_set_phase(s, PHASE_DO);
        dev->info->write_data(dev, s->current->tag);
        }

        scsi_req_continue(s->current->req);
    }
    if (!s->command_complete) {
        if (n) {
            /* Command did not complete immediately so disconnect.  */
@@ -855,13 +890,15 @@ static void lsi_do_msgout(LSIState *s)
    int len;
    uint32_t current_tag;
    SCSIDevice *current_dev;
    lsi_request *p, *p_next;
    lsi_request *current_req, *p, *p_next;
    int id;

    if (s->current) {
        current_tag = s->current->tag;
        current_req = s->current;
    } else {
        current_tag = s->select_tag;
        current_req = lsi_find_by_tag(s, current_tag);
    }
    id = (current_tag >> 8) & 0xf;
    current_dev = s->bus.devs[id];
@@ -913,7 +950,9 @@ static void lsi_do_msgout(LSIState *s)
        case 0x0d:
            /* The ABORT TAG message clears the current I/O process only. */
            DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag);
            current_dev->info->cancel_io(current_dev, current_tag);
            if (current_req) {
                scsi_req_cancel(current_req->req);
            }
            lsi_disconnect(s);
            break;
        case 0x06:
@@ -936,7 +975,9 @@ static void lsi_do_msgout(LSIState *s)
            }

            /* clear the current I/O process */
            current_dev->info->cancel_io(current_dev, current_tag);
            if (s->current) {
                scsi_req_cancel(s->current->req);
            }

            /* As the current implemented devices scsi_disk and scsi_generic
               only support one LUN, we don't need to keep track of LUNs.
@@ -948,8 +989,7 @@ static void lsi_do_msgout(LSIState *s)
            id = current_tag & 0x0000ff00;
            QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
                if ((p->tag & 0x0000ff00) == id) {
                    current_dev->info->cancel_io(current_dev, p->tag);
                    QTAILQ_REMOVE(&s->queue, p, next);
                    scsi_req_cancel(p->req);
                }
            }

@@ -2205,6 +2245,12 @@ static int lsi_scsi_uninit(PCIDevice *d)
    return 0;
}

static const struct SCSIBusOps lsi_scsi_ops = {
    .transfer_data = lsi_transfer_data,
    .complete = lsi_command_complete,
    .cancel = lsi_request_cancelled
};

static int lsi_scsi_init(PCIDevice *dev)
{
    LSIState *s = DO_UPCAST(LSIState, dev, dev);
@@ -2241,7 +2287,7 @@ static int lsi_scsi_init(PCIDevice *dev)
                           PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
    QTAILQ_INIT(&s->queue);

    scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, lsi_command_complete);
    scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, &lsi_scsi_ops);
    if (!dev->qdev.hotplugged) {
        return scsi_bus_legacy_handle_cmdline(&s->bus);
    }
+200 −20
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
#include "scsi-defs.h"
#include "qdev.h"
#include "blockdev.h"
#include "trace.h"

static char *scsibus_get_fw_dev_path(DeviceState *dev);

@@ -20,13 +21,13 @@ static int next_scsi_bus;

/* Create a scsi bus, and attach devices to it.  */
void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
                  scsi_completionfn complete)
                  const SCSIBusOps *ops)
{
    qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL);
    bus->busnr = next_scsi_bus++;
    bus->tcq = tcq;
    bus->ndev = ndev;
    bus->complete = complete;
    bus->ops = ops;
    bus->qbus.allow_hotplug = 1;
}

@@ -135,42 +136,60 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l
    SCSIRequest *req;

    req = qemu_mallocz(size);
    req->refcount = 1;
    req->bus = scsi_bus_from_device(d);
    req->dev = d;
    req->tag = tag;
    req->lun = lun;
    req->status = -1;
    req->enqueued = true;
    QTAILQ_INSERT_TAIL(&d->requests, req, next);
    trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
    return req;
}

SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag)
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun)
{
    SCSIRequest *req;
    return d->info->alloc_req(d, tag, lun);
}

    QTAILQ_FOREACH(req, &d->requests, next) {
        if (req->tag == tag) {
            return req;
uint8_t *scsi_req_get_buf(SCSIRequest *req)
{
    return req->dev->info->get_buf(req);
}

int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
{
    if (req->dev->info->get_sense) {
        return req->dev->info->get_sense(req, buf, len);
    } else {
        return 0;
    }
    return NULL;
}

int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf)
{
    int32_t rc;

    assert(!req->enqueued);
    scsi_req_ref(req);
    req->enqueued = true;
    QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);

    scsi_req_ref(req);
    rc = req->dev->info->send_command(req, buf);
    scsi_req_unref(req);
    return rc;
}

static void scsi_req_dequeue(SCSIRequest *req)
{
    trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag);
    if (req->enqueued) {
        QTAILQ_REMOVE(&req->dev->requests, req, next);
        req->enqueued = false;
        scsi_req_unref(req);
    }
}

void scsi_req_free(SCSIRequest *req)
{
    scsi_req_dequeue(req);
    qemu_free(req);
}

static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
{
    switch (cmd[0] >> 5) {
@@ -195,6 +214,7 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
        req->cmd.len = 12;
        break;
    default:
        trace_scsi_req_parse_bad(req->dev->id, req->lun, req->tag, cmd[0]);
        return -1;
    }

@@ -392,9 +412,100 @@ int scsi_req_parse(SCSIRequest *req, uint8_t *buf)
    memcpy(req->cmd.buf, buf, req->cmd.len);
    scsi_req_xfer_mode(req);
    req->cmd.lba = scsi_req_lba(req);
    trace_scsi_req_parsed(req->dev->id, req->lun, req->tag, buf[0],
                          req->cmd.mode, req->cmd.xfer, req->cmd.lba);
    return 0;
}

/*
 * Predefined sense codes
 */

/* No sense data available */
const struct SCSISense sense_code_NO_SENSE = {
    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
};

/* LUN not ready, Manual intervention required */
const struct SCSISense sense_code_LUN_NOT_READY = {
    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
};

/* LUN not ready, Medium not present */
const struct SCSISense sense_code_NO_MEDIUM = {
    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
};

/* Hardware error, internal target failure */
const struct SCSISense sense_code_TARGET_FAILURE = {
    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
};

/* Illegal request, invalid command operation code */
const struct SCSISense sense_code_INVALID_OPCODE = {
    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
};

/* Illegal request, LBA out of range */
const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
};

/* Illegal request, Invalid field in CDB */
const struct SCSISense sense_code_INVALID_FIELD = {
    .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
};

/* Illegal request, LUN not supported */
const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
    .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
};

/* Command aborted, I/O process terminated */
const struct SCSISense sense_code_IO_ERROR = {
    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
};

/* Command aborted, I_T Nexus loss occurred */
const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
};

/* Command aborted, Logical Unit failure */
const struct SCSISense sense_code_LUN_FAILURE = {
    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
};

/*
 * scsi_build_sense
 *
 * Build a sense buffer
 */
int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed)
{
    if (!fixed && len < 8) {
        return 0;
    }

    memset(buf, 0, len);
    if (fixed) {
        /* Return fixed format sense buffer */
        buf[0] = 0xf0;
        buf[2] = sense.key;
        buf[7] = 7;
        buf[12] = sense.asc;
        buf[13] = sense.ascq;
        return MIN(len, 18);
    } else {
        /* Return descriptor format sense buffer */
        buf[0] = 0x72;
        buf[1] = sense.key;
        buf[2] = sense.asc;
        buf[3] = sense.ascq;
        return 8;
    }
}

static const char *scsi_command_name(uint8_t cmd)
{
    static const char *names[] = {
@@ -489,6 +600,43 @@ static const char *scsi_command_name(uint8_t cmd)
    return names[cmd];
}

SCSIRequest *scsi_req_ref(SCSIRequest *req)
{
    req->refcount++;
    return req;
}

void scsi_req_unref(SCSIRequest *req)
{
    if (--req->refcount == 0) {
        if (req->dev->info->free_req) {
            req->dev->info->free_req(req);
        }
        qemu_free(req);
    }
}

/* Tell the device that we finished processing this chunk of I/O.  It
   will start the next chunk or complete the command.  */
void scsi_req_continue(SCSIRequest *req)
{
    trace_scsi_req_continue(req->dev->id, req->lun, req->tag);
    if (req->cmd.mode == SCSI_XFER_TO_DEV) {
        req->dev->info->write_data(req);
    } else {
        req->dev->info->read_data(req);
    }
}

/* Called by the devices when data is ready for the HBA.  The HBA should
   start a DMA operation to read or fill the device's data buffer.
   Once it completes, calling scsi_req_continue will restart I/O.  */
void scsi_req_data(SCSIRequest *req, int len)
{
    trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
    req->bus->ops->transfer_data(req, len);
}

void scsi_req_print(SCSIRequest *req)
{
    FILE *fp = stderr;
@@ -520,10 +668,42 @@ void scsi_req_print(SCSIRequest *req)
void scsi_req_complete(SCSIRequest *req)
{
    assert(req->status != -1);
    scsi_req_ref(req);
    scsi_req_dequeue(req);
    req->bus->complete(req->bus, SCSI_REASON_DONE,
                       req->tag,
                       req->status);
    req->bus->ops->complete(req, req->status);
    scsi_req_unref(req);
}

void scsi_req_cancel(SCSIRequest *req)
{
    if (req->dev && req->dev->info->cancel_io) {
        req->dev->info->cancel_io(req);
    }
    scsi_req_ref(req);
    scsi_req_dequeue(req);
    if (req->bus->ops->cancel) {
        req->bus->ops->cancel(req);
    }
    scsi_req_unref(req);
}

void scsi_req_abort(SCSIRequest *req, int status)
{
    req->status = status;
    if (req->dev && req->dev->info->cancel_io) {
        req->dev->info->cancel_io(req);
    }
    scsi_req_complete(req);
}

void scsi_device_purge_requests(SCSIDevice *sdev)
{
    SCSIRequest *req;

    while (!QTAILQ_EMPTY(&sdev->requests)) {
        req = QTAILQ_FIRST(&sdev->requests);
        scsi_req_cancel(req);
    }
}

static char *scsibus_get_fw_dev_path(DeviceState *dev)
+114 −157

File changed.

Preview size limit exceeded, changes collapsed.

+107 −116

File changed.

Preview size limit exceeded, changes collapsed.

Loading