Commit message: scsi: lsi: exit infinite loop while executing script (CVE-2019-12068)

When executing script in lsi_execute_script(), the LSI scsi adapter
emulator advances 's->dsp' index to read next opcode. This can lead
to an infinite loop if the next opcode is empty. Move the existing
loop exit after 10k iterations so that it covers no-op opcodes as
well.

Reported-by: Bugs SysSec <bugs-syssec@rub.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
CVE: CVE-2019-12068
CWE: CWE-835
Vulnerability description: In QEMU 1:4.1-1, 1:2.1+dfsg-12+deb8u6, 1:2.8+dfsg-6+deb9u8, 1:3.1+dfsg-8~deb10u1, 1:3.1+dfsg-8+deb10u2, and 1:2.1+dfsg-12+deb8u12 (fixed), when executing script in lsi_execute_script(), the LSI scsi adapter emulator advances 's->dsp' index to read next opcode. This can lead to an infinite loop if the next opcode is empty. Move the existing loop exit after 10k iterations so that it covers no-op opcodes as well.

Project: qemu
File: lsi53c895a.c

static lsi_request *get_pending_req(LSIState *s)
{
    lsi_request *p;

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

Project: qemu
File: lsi53c895a.c

static void lsi_bad_phase(LSIState *s, int out, int new_phase)
{
    /* Trigger a phase mismatch.  */
    if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
        if ((s->ccntl0 & LSI_CCNTL0_PMJCTL)) {
            s->dsp = out ? s->pmjad1 : s->pmjad2;
        } else {
            s->dsp = (s->scntl2 & LSI_SCNTL2_WSR ? s->pmjad2 : s->pmjad1);
        }
        trace_lsi_bad_phase_jump(s->dsp);
    } else {
        trace_lsi_bad_phase_interrupt();
        lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
        lsi_stop_script(s);
    }
    lsi_set_phase(s, new_phase);
}

Project: qemu
File: lsi53c895a.c

static void lsi_bad_selection(LSIState *s, uint32_t id)
{
    trace_lsi_bad_selection(id);
    lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
    lsi_disconnect(s);
}

Project: qemu
File: lsi53c895a.c

static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
{
    LSIState *s = LSI53C895A(req->bus->qbus.parent);
    int out;

    out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
    trace_lsi_command_complete(status);
    s->status = status;
    s->command_complete = 2;
    if (s->waiting && s->dbc != 0) {
        /* Raise phase mismatch for short transfers.  */
        lsi_bad_phase(s, out, PHASE_ST);
    } else {
        lsi_set_phase(s, PHASE_ST);
    }

    if (req->hba_private == s->current) {
        req->hba_private = NULL;
        lsi_request_free(s, s->current);
        scsi_req_unref(req);
    }
    lsi_resume_script(s);
}

Project: qemu
File: lsi53c895a.c

static void lsi_disconnect(LSIState *s)
{
    s->scntl1 &= ~LSI_SCNTL1_CON;
    s->sstat1 &= ~PHASE_MASK;
    s->sbcl = 0;
}

Project: qemu
File: lsi53c895a.c

static int lsi_dma_40bit(LSIState *s)
{
    if ((s->ccntl1 & LSI_CCNTL1_40BIT) == LSI_CCNTL1_40BIT)
        return 1;
    return 0;
}

Project: qemu
File: lsi53c895a.c

static int lsi_dma_64bit(LSIState *s)
{
    if ((s->ccntl1 & LSI_CCNTL1_EN64DBMV) == LSI_CCNTL1_EN64DBMV)
        return 1;
    return 0;
}

Project: qemu
File: lsi53c895a.c

static int lsi_dma_ti64bit(LSIState *s)
{
    if ((s->ccntl1 & LSI_CCNTL1_EN64TIBMV) == LSI_CCNTL1_EN64TIBMV)
        return 1;
    return 0;
}

Project: qemu
File: lsi53c895a.c

static void lsi_do_command(LSIState *s)
{
    SCSIDevice *dev;
    uint8_t buf[16];
    uint32_t id;
    int n;

    trace_lsi_do_command(s->dbc);
    if (s->dbc > 16)
        s->dbc = 16;
    pci_dma_read(PCI_DEVICE(s), s->dnad, buf, s->dbc);
    s->sfbr = buf[0];
    s->command_complete = 0;

    id = (s->select_tag >> 8) & 0xf;
    dev = scsi_device_find(&s->bus, 0, id, s->current_lun);
    if (!dev) {
        lsi_bad_selection(s, id);
        return;
    }

    assert(s->current == NULL);
    s->current = g_new0(lsi_request, 1);
    s->current->tag = s->select_tag;
    s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun, buf,
                                   s->current);

    n = scsi_req_enqueue(s->current->req);
    if (n) {
        if (n > 0) {
            lsi_set_phase(s, PHASE_DI);
        } else if (n < 0) {
            lsi_set_phase(s, PHASE_DO);
        }
        scsi_req_continue(s->current->req);
    }
    if (!s->command_complete) {
        if (n) {
            /* Command did not complete immediately so disconnect.  */
            lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
            lsi_add_msg_byte(s, 4); /* DISCONNECT */
            /* wait data */
            lsi_set_phase(s, PHASE_MI);
            s->msg_action = LSI_MSG_ACTION_DISCONNECT;
            lsi_queue_command(s);
        } else {
            /* wait command complete */
            lsi_set_phase(s, PHASE_DI);
        }
    }
}

Project: qemu
File: lsi53c895a.c

static void lsi_do_dma(LSIState *s, int out)
{
    uint32_t count;
    dma_addr_t addr;
    SCSIDevice *dev;

    assert(s->current);
    if (!s->current->dma_len) {
        /* Wait until data is available.  */
        trace_lsi_do_dma_unavailable();
        return;
    }

    dev = s->current->req->dev;
    assert(dev);

    count = s->dbc;
    if (count > s->current->dma_len)
        count = s->current->dma_len;

    addr = s->dnad;
    /* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
    if (lsi_dma_40bit(s) || lsi_dma_ti64bit(s))
        addr |= ((uint64_t)s->dnad64 << 32);
    else if (s->dbms)
        addr |= ((uint64_t)s->dbms << 32);
    else if (s->sbms)
        addr |= ((uint64_t)s->sbms << 32);

    trace_lsi_do_dma(addr, count);
    s->csbc += count;
    s->dnad += count;
    s->dbc -= count;
     if (s->current->dma_buf == NULL) {
        s->current->dma_buf = scsi_req_get_buf(s->current->req);
    }
    /* ??? Set SFBR to first data byte.  */
    if (out) {
        lsi_mem_read(s, addr, s->current->dma_buf, count);
    } else {
        lsi_mem_write(s, addr, s->current->dma_buf, count);
    }
    s->current->dma_len -= count;
    if (s->current->dma_len == 0) {
        s->current->dma_buf = NULL;
        scsi_req_continue(s->current->req);
    } else {
        s->current->dma_buf += count;
        lsi_resume_script(s);
    }
}

Project: qemu
File: lsi53c895a.c

static void lsi_do_msgin(LSIState *s)
{
    uint8_t len;
    trace_lsi_do_msgin(s->dbc, s->msg_len);
    s->sfbr = s->msg[0];
    len = s->msg_len;
    assert(len > 0 && len <= LSI_MAX_MSGIN_LEN);
    if (len > s->dbc)
        len = s->dbc;
    pci_dma_write(PCI_DEVICE(s), s->dnad, s->msg, len);
    /* Linux drivers rely on the last byte being in the SIDL.  */
    s->sidl = s->msg[len - 1];
    s->msg_len -= len;
    if (s->msg_len) {
        memmove(s->msg, s->msg + len, s->msg_len);
    } else {
        /* ??? Check if ATN (not yet implemented) is asserted and maybe
           switch to PHASE_MO.  */
        switch (s->msg_action) {
        case LSI_MSG_ACTION_COMMAND:
            lsi_set_phase(s, PHASE_CMD);
            break;
        case LSI_MSG_ACTION_DISCONNECT:
            lsi_disconnect(s);
            break;
        case LSI_MSG_ACTION_DOUT:
            lsi_set_phase(s, PHASE_DO);
            break;
        case LSI_MSG_ACTION_DIN:
            lsi_set_phase(s, PHASE_DI);
            break;
        default:
            abort();
        }
    }
}

Project: qemu
File: lsi53c895a.c

static void lsi_do_msgout(LSIState *s)
{
    uint8_t msg;
    int len;
    uint32_t current_tag;
    lsi_request *current_req, *p, *p_next;

    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);
    }

    trace_lsi_do_msgout(s->dbc);
    while (s->dbc) {
        msg = lsi_get_msgbyte(s);
        s->sfbr = msg;

        switch (msg) {
        case 0x04:
            trace_lsi_do_msgout_disconnect();
            lsi_disconnect(s);
            break;
        case 0x08:
            trace_lsi_do_msgout_noop();
            lsi_set_phase(s, PHASE_CMD);
            break;
        case 0x01:
            len = lsi_get_msgbyte(s);
            msg = lsi_get_msgbyte(s);
            (void)len; /* avoid a warning about unused variable*/
            trace_lsi_do_msgout_extended(msg, len);
            switch (msg) {
            case 1:
                trace_lsi_do_msgout_ignored("SDTR");
                lsi_skip_msgbytes(s, 2);
                break;
            case 3:
                trace_lsi_do_msgout_ignored("WDTR");
                lsi_skip_msgbytes(s, 1);
                break;
            case 4:
                trace_lsi_do_msgout_ignored("PPR");
                lsi_skip_msgbytes(s, 5);
                break;
            default:
                goto bad;
            }
            break;
        case 0x20: /* SIMPLE queue */
            s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
            trace_lsi_do_msgout_simplequeue(s->select_tag & 0xff);
            break;
        case 0x21: /* HEAD of queue */
            qemu_log_mask(LOG_UNIMP, "lsi_scsi: HEAD queue not implemented\n");
            s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
            break;
        case 0x22: /* ORDERED queue */
            qemu_log_mask(LOG_UNIMP,
                          "lsi_scsi: ORDERED queue not implemented\n");
            s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
            break;
        case 0x0d:
            /* The ABORT TAG message clears the current I/O process only. */
            trace_lsi_do_msgout_abort(current_tag);
            if (current_req) {
                scsi_req_cancel(current_req->req);
            }
            lsi_disconnect(s);
            break;
        case 0x06:
        case 0x0e:
        case 0x0c:
            /* The ABORT message clears all I/O processes for the selecting
               initiator on the specified logical unit of the target. */
            if (msg == 0x06) {
                trace_lsi_do_msgout_abort(current_tag);
            }
            /* The CLEAR QUEUE message clears all I/O processes for all
               initiators on the specified logical unit of the target. */
            if (msg == 0x0e) {
                trace_lsi_do_msgout_clearqueue(current_tag);
            }
            /* The BUS DEVICE RESET message clears all I/O processes for all
               initiators on all logical units of the target. */
            if (msg == 0x0c) {
                trace_lsi_do_msgout_busdevicereset(current_tag);
            }

            /* clear the current I/O process */
            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.
               Clearing I/O processes for other initiators could be possible
               for scsi_generic by sending a SG_SCSI_RESET to the /dev/sgX
               device, but this is currently not implemented (and seems not
               to be really necessary). So let's simply clear all queued
               commands for the current device: */
            QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
                if ((p->tag & 0x0000ff00) == (current_tag & 0x0000ff00)) {
                    scsi_req_cancel(p->req);
                }
            }

            lsi_disconnect(s);
            break;
        default:
            if ((msg & 0x80) == 0) {
                goto bad;
            }
            s->current_lun = msg & 7;
            trace_lsi_do_msgout_select(s->current_lun);
            lsi_set_phase(s, PHASE_CMD);
            break;
        }
    }
    return;
bad:
    qemu_log_mask(LOG_UNIMP, "Unimplemented message 0x%02x\n", msg);
    lsi_set_phase(s, PHASE_MI);
    lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */
    s->msg_action = LSI_MSG_ACTION_COMMAND;
}

Project: qemu
File: lsi53c895a.c

static void lsi_do_status(LSIState *s)
{
    uint8_t status;
    trace_lsi_do_status(s->dbc, s->status);
    if (s->dbc != 1) {
        trace_lsi_do_status_error();
    }
    s->dbc = 1;
    status = s->status;
    s->sfbr = status;
    pci_dma_write(PCI_DEVICE(s), s->dnad, &status, 1);
    lsi_set_phase(s, PHASE_MI);
    s->msg_action = LSI_MSG_ACTION_DISCONNECT;
    lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
}

Project: qemu
File: lsi53c895a.c

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;
}

Project: qemu
File: lsi53c895a.c

static uint8_t lsi_get_msgbyte(LSIState *s)
{
    uint8_t data;
    pci_dma_read(PCI_DEVICE(s), s->dnad, &data, 1);
    s->dnad++;
    s->dbc--;
    return data;
}

Project: qemu
File: lsi53c895a.c

static inline int lsi_irq_on_rsl(LSIState *s)
{
    return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE);
}

Project: qemu
File: lsi53c895a.c

static inline void lsi_mem_read(LSIState *s, dma_addr_t addr,
                               void *buf, dma_addr_t len)
{
    if (s->dmode & LSI_DMODE_SIOM) {
        address_space_read(&s->pci_io_as, addr, MEMTXATTRS_UNSPECIFIED,
                           buf, len);
    } else {
        pci_dma_read(PCI_DEVICE(s), addr, buf, len);
    }
}

Project: qemu
File: lsi53c895a.c

static inline void lsi_mem_write(LSIState *s, dma_addr_t addr,
                                const void *buf, dma_addr_t len)
{
    if (s->dmode & LSI_DMODE_DIOM) {
        address_space_write(&s->pci_io_as, addr, MEMTXATTRS_UNSPECIFIED,
                            buf, len);
    } else {
        pci_dma_write(PCI_DEVICE(s), addr, buf, len);
    }
}

Project: qemu
File: lsi53c895a.c

static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
{
    int n;
    uint8_t buf[LSI_BUF_SIZE];

    trace_lsi_memcpy(dest, src, count);
    while (count) {
        n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count;
        lsi_mem_read(s, src, buf, n);
        lsi_mem_write(s, dest, buf, n);
        src += n;
        dest += n;
        count -= n;
    }
}

Project: qemu
File: lsi53c895a.c

static void lsi_queue_command(LSIState *s)
{
    lsi_request *p = s->current;

    trace_lsi_queue_command(p->tag);
    assert(s->current != NULL);
    assert(s->current->dma_len == 0);
    QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
    s->current = NULL;

    p->pending = 0;
    p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
}

Project: qemu
File: lsi53c895a.c

static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
{
    lsi_request *p = req->hba_private;

    if (p->pending) {
        trace_lsi_queue_req_error(p);
    }
    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
       is also required that there are no pending interrupts waiting
       for service from the device driver. */
    if (s->waiting == LSI_WAIT_RESELECT ||
        (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
         !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
        /* Reselect device.  */
        lsi_reselect(s, p);
        return 0;
    } else {
        trace_lsi_queue_req(p->tag);
        p->pending = len;
        return 1;
    }
}

Project: qemu
File: lsi53c895a.c

static void lsi_request_cancelled(SCSIRequest *req)
{
    LSIState *s = LSI53C895A(req->bus->qbus.parent);
    lsi_request *p = req->hba_private;

    req->hba_private = NULL;
    lsi_request_free(s, p);
    scsi_req_unref(req);
}

Project: qemu
File: lsi53c895a.c

static void lsi_request_free(LSIState *s, lsi_request *p)
{
    if (p == s->current) {
        s->current = NULL;
    } else {
        QTAILQ_REMOVE(&s->queue, p, next);
    }
    g_free(p);
}

Project: qemu
File: lsi53c895a.c

static void lsi_reselect(LSIState *s, lsi_request *p)
{
    int id;

    assert(s->current == NULL);
    QTAILQ_REMOVE(&s->queue, p, next);
    s->current = p;

    id = (p->tag >> 8) & 0xf;
    s->ssid = id | 0x80;
    /* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
    if (!(s->dcntl & LSI_DCNTL_COM)) {
        s->sfbr = 1 << (id & 0x7);
    }
    trace_lsi_reselect(id);
    s->scntl1 |= LSI_SCNTL1_CON;
    lsi_set_phase(s, PHASE_MI);
    s->msg_action = p->out ? LSI_MSG_ACTION_DOUT : LSI_MSG_ACTION_DIN;
    s->current->dma_len = p->pending;
    lsi_add_msg_byte(s, 0x80);
    if (s->current->tag & LSI_TAG_VALID) {
        lsi_add_msg_byte(s, 0x20);
        lsi_add_msg_byte(s, p->tag & 0xff);
    }

    if (lsi_irq_on_rsl(s)) {
        lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0);
    }
}

Project: qemu
File: lsi53c895a.c

static void lsi_resume_script(LSIState *s)
{
    if (s->waiting != 2) {
        s->waiting = LSI_NOWAIT;
        lsi_execute_script(s);
    } else {
        s->waiting = LSI_NOWAIT;
    }
}

Project: qemu
File: lsi53c895a.c

static void lsi_script_dma_interrupt(LSIState *s, int stat)
{
    trace_lsi_script_dma_interrupt(stat, s->dstat);
    s->dstat |= stat;
    lsi_update_irq(s);
    lsi_stop_script(s);
}

Project: qemu
File: lsi53c895a.c

static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
{
    uint32_t mask0;
    uint32_t mask1;

    trace_lsi_script_scsi_interrupt(stat1, stat0, s->sist1, s->sist0);
    s->sist0 |= stat0;
    s->sist1 |= stat1;
    /* Stop processor on fatal or unmasked interrupt.  As a special hack
       we don't stop processing when raising STO.  Instead continue
       execution and stop at the next insn that accesses the SCSI bus.  */
    mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL);
    mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH);
    mask1 &= ~LSI_SIST1_STO;
    if (s->sist0 & mask0 || s->sist1 & mask1) {
        lsi_stop_script(s);
    }
    lsi_update_irq(s);
}

Project: qemu
File: lsi53c895a.c

static void lsi_set_irq(LSIState *s, int level)
{
    PCIDevice *d = PCI_DEVICE(s);

    if (s->ext_irq) {
        qemu_set_irq(s->ext_irq, level);
    } else {
        pci_set_irq(d, level);
    }
}

Project: qemu
File: lsi53c895a.c

static inline void lsi_set_phase(LSIState *s, int phase)
{
    s->sbcl &= ~PHASE_MASK;
    s->sbcl |= phase | LSI_SBCL_REQ;
    s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase;
}

Project: qemu
File: lsi53c895a.c

static void lsi_skip_msgbytes(LSIState *s, unsigned int n)
{
    s->dnad += n;
    s->dbc  -= n;
}

Project: qemu
File: lsi53c895a.c

static void lsi_soft_reset(LSIState *s)
{
    trace_lsi_reset();
    s->carry = 0;

    s->msg_action = LSI_MSG_ACTION_COMMAND;
    s->msg_len = 0;
    s->waiting = LSI_NOWAIT;
    s->dsa = 0;
    s->dnad = 0;
    s->dbc = 0;
    s->temp = 0;
    memset(s->scratch, 0, sizeof(s->scratch));
    s->istat0 = 0;
    s->istat1 = 0;
    s->dcmd = 0x40;
    s->dstat = 0;
    s->dien = 0;
    s->sist0 = 0;
    s->sist1 = 0;
    s->sien0 = 0;
    s->sien1 = 0;
    s->mbox0 = 0;
    s->mbox1 = 0;
    s->dfifo = 0;
    s->ctest2 = LSI_CTEST2_DACK;
    s->ctest3 = 0;
    s->ctest4 = 0;
    s->ctest5 = 0;
    s->ccntl0 = 0;
    s->ccntl1 = 0;
    s->dsp = 0;
    s->dsps = 0;
    s->dmode = 0;
    s->dcntl = 0;
    s->scntl0 = 0xc0;
    s->scntl1 = 0;
    s->scntl2 = 0;
    s->scntl3 = 0;
    s->sstat0 = 0;
    s->sstat1 = 0;
    s->scid = 7;
    s->sxfer = 0;
    s->socl = 0;
    s->sdid = 0;
    s->ssid = 0;
    s->sbcl = 0;
    s->stest1 = 0;
    s->stest2 = 0;
    s->stest3 = 0;
    s->sidl = 0;
    s->stime0 = 0;
    s->respid0 = 0x80;
    s->respid1 = 0;
    s->mmrs = 0;
    s->mmws = 0;
    s->sfs = 0;
    s->drs = 0;
    s->sbms = 0;
    s->dbms = 0;
    s->dnad64 = 0;
    s->pmjad1 = 0;
    s->pmjad2 = 0;
    s->rbc = 0;
    s->ua = 0;
    s->ia = 0;
    s->sbc = 0;
    s->csbc = 0;
    s->sbr = 0;
    assert(QTAILQ_EMPTY(&s->queue));
    assert(!s->current);
}

Project: qemu
File: lsi53c895a.c

static void lsi_stop_script(LSIState *s)
{
    s->istat1 &= ~LSI_ISTAT1_SRUN;
}

Project: qemu
File: lsi53c895a.c

static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
{
    LSIState *s = LSI53C895A(req->bus->qbus.parent);
    int out;

    assert(req->hba_private);
    if (s->waiting == LSI_WAIT_RESELECT || req->hba_private != s->current ||
        (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
        if (lsi_queue_req(s, req, len)) {
            return;
        }
    }

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

    /* host adapter (re)connected */
    trace_lsi_transfer_data(req->tag, len);
    s->current->dma_len = len;
    s->command_complete = 1;
    if (s->waiting) {
        if (s->waiting == LSI_WAIT_RESELECT || s->dbc == 0) {
            lsi_resume_script(s);
        } else {
            lsi_do_dma(s, out);
        }
    }
}

Project: qemu
File: lsi53c895a.c

static void lsi_update_irq(LSIState *s)
{
    int level;
    static int last_level;

    /* It's unclear whether the DIP/SIP bits should be cleared when the
       Interrupt Status Registers are cleared or when istat0 is read.
       We currently do the formwer, which seems to work.  */
    level = 0;
    if (s->dstat) {
        if (s->dstat & s->dien)
            level = 1;
        s->istat0 |= LSI_ISTAT0_DIP;
    } else {
        s->istat0 &= ~LSI_ISTAT0_DIP;
    }

    if (s->sist0 || s->sist1) {
        if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1))
            level = 1;
        s->istat0 |= LSI_ISTAT0_SIP;
    } else {
        s->istat0 &= ~LSI_ISTAT0_SIP;
    }
    if (s->istat0 & LSI_ISTAT0_INTF)
        level = 1;

    if (level != last_level) {
        trace_lsi_update_irq(level, s->dstat, s->sist1, s->sist0);
        last_level = level;
    }
    lsi_set_irq(s, level);

    if (!s->current && !level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
        lsi_request *p;

        trace_lsi_update_irq_disconnected();
        p = get_pending_req(s);
        if (p) {
            lsi_reselect(s, p);
        }
    }
}

Project: qemu
File: lsi53c895a.c

static void lsi_wait_reselect(LSIState *s)
{
    lsi_request *p;

    trace_lsi_wait_reselect();

    if (s->current) {
        return;
    }
    p = get_pending_req(s);
    if (p) {
        lsi_reselect(s, p);
    }
    if (s->current == NULL) {
        s->waiting = LSI_WAIT_RESELECT;
    }
}

Project: qemu
File: lsi53c895a.c

static inline uint32_t read_dword(LSIState *s, uint32_t addr)
{
    uint32_t buf;

    pci_dma_read(PCI_DEVICE(s), addr, &buf, 4);
    return cpu_to_le32(buf);
}

Project: qemu
File: lsi53c895a.c

static const char *scsi_phase_name(int phase)
{
    return scsi_phases[phase & PHASE_MASK];
}