⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lsi53c895a.c

📁 qemu性能直逼VMware的仿真器QEMU 的模擬速度約為實機的 25%;約為 Bochs 的 60 倍。Plex86、User-Mode-Linux、VMware 和 Virtual PC 則比
💻 C
📖 第 1 页 / 共 4 页
字号:
    if (s->dma_buf == NULL) {        s->dma_buf = scsi_get_buf(s->current_dev, s->current_tag);    }    /* ??? Set SFBR to first data byte.  */    if (out) {        cpu_physical_memory_read(addr, s->dma_buf, count);    } else {        cpu_physical_memory_write(addr, s->dma_buf, count);    }    s->current_dma_len -= count;    if (s->current_dma_len == 0) {        s->dma_buf = NULL;        if (out) {            /* Write the data.  */            scsi_write_data(s->current_dev, s->current_tag);        } else {            /* Request any remaining data.  */            scsi_read_data(s->current_dev, s->current_tag);        }    } else {        s->dma_buf += count;        lsi_resume_script(s);    }}/* Add a command to the queue.  */static void lsi_queue_command(LSIState *s){    lsi_queue *p;    DPRINTF("Queueing tag=0x%x\n", s->current_tag);    if (s->queue_len == s->active_commands) {        s->queue_len++;        s->queue = realloc(s->queue, s->queue_len * sizeof(lsi_queue));    }    p = &s->queue[s->active_commands++];    p->tag = s->current_tag;    p->pending = 0;    p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;}/* Queue a byte for a MSG IN phase.  */static void lsi_add_msg_byte(LSIState *s, uint8_t data){    if (s->msg_len >= LSI_MAX_MSGIN_LEN) {        BADF("MSG IN data too long\n");    } else {        DPRINTF("MSG IN 0x%02x\n", data);        s->msg[s->msg_len++] = data;    }}/* Perform reselection to continue a command.  */static void lsi_reselect(LSIState *s, uint32_t tag){    lsi_queue *p;    int n;    int id;    p = NULL;    for (n = 0; n < s->active_commands; n++) {        p = &s->queue[n];        if (p->tag == tag)            break;    }    if (n == s->active_commands) {        BADF("Reselected non-existant command tag=0x%x\n", tag);        return;    }    id = (tag >> 8) & 0xf;    s->ssid = id | 0x80;    DPRINTF("Reselected target %d\n", id);    s->current_dev = s->scsi_dev[id];    s->current_tag = tag;    s->scntl1 |= LSI_SCNTL1_CON;    lsi_set_phase(s, PHASE_MI);    s->msg_action = p->out ? 2 : 3;    s->current_dma_len = p->pending;    s->dma_buf = NULL;    lsi_add_msg_byte(s, 0x80);    if (s->current_tag & LSI_TAG_VALID) {        lsi_add_msg_byte(s, 0x20);        lsi_add_msg_byte(s, tag & 0xff);    }    s->active_commands--;    if (n != s->active_commands) {        s->queue[n] = s->queue[s->active_commands];    }}/* 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){    lsi_queue *p;    int i;    for (i = 0; i < s->active_commands; i++) {        p = &s->queue[i];        if (p->tag == tag) {            if (p->pending) {                BADF("Multiple IO pending for tag %d\n", tag);            }            p->pending = arg;            if (s->waiting == 1) {                /* Reselect device.  */                lsi_reselect(s, tag);                return 0;            } else {               DPRINTF("Queueing IO tag=0x%x\n", tag);                p->pending = arg;                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(void *opaque, int reason, uint32_t tag,                                 uint32_t arg){    LSIState *s = (LSIState *)opaque;    int out;    out = (s->sstat1 & PHASE_MASK) == PHASE_DO;    if (reason == SCSI_REASON_DONE) {        DPRINTF("Command complete sense=%d\n", (int)arg);        s->sense = arg;        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);        }        lsi_resume_script(s);        return;    }    if (s->waiting == 1 || tag != s->current_tag) {        if (lsi_queue_tag(s, tag, arg))            return;    }    DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg);    s->current_dma_len = arg;    if (!s->waiting)        return;    if (s->waiting == 1 || s->dbc == 0) {        lsi_resume_script(s);    } else {        lsi_do_dma(s, out);    }}static void lsi_do_command(LSIState *s){    uint8_t buf[16];    int n;    DPRINTF("Send command len=%d\n", s->dbc);    if (s->dbc > 16)        s->dbc = 16;    cpu_physical_memory_read(s->dnad, buf, s->dbc);    s->sfbr = buf[0];    n = scsi_send_command(s->current_dev, s->current_tag, buf, s->current_lun);    if (n > 0) {        lsi_set_phase(s, PHASE_DI);        scsi_read_data(s->current_dev, s->current_tag);    } else if (n < 0) {        lsi_set_phase(s, PHASE_DO);        scsi_write_data(s->current_dev, s->current_tag);    }    if (n && s->current_dma_len == 0) {        /* Command did not complete immediately so disconnect.  */        lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */        lsi_add_msg_byte(s, 4); /* DISCONNECT */        lsi_set_phase(s, PHASE_MI);        s->msg_action = 1;        lsi_queue_command(s);    }}static void lsi_do_status(LSIState *s){    uint8_t sense;    DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense);    if (s->dbc != 1)        BADF("Bad Status move\n");    s->dbc = 1;    sense = s->sense;    s->sfbr = sense;    cpu_physical_memory_write(s->dnad, &sense, 1);    lsi_set_phase(s, PHASE_MI);    s->msg_action = 1;    lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */}static void lsi_disconnect(LSIState *s){    s->scntl1 &= ~LSI_SCNTL1_CON;    s->sstat1 &= ~PHASE_MASK;}static void lsi_do_msgin(LSIState *s){    int len;    DPRINTF("Message in len=%d/%d\n", s->dbc, s->msg_len);    s->sfbr = s->msg[0];    len = s->msg_len;    if (len > s->dbc)        len = s->dbc;    cpu_physical_memory_write(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 0:            lsi_set_phase(s, PHASE_CMD);            break;        case 1:            lsi_disconnect(s);            break;        case 2:            lsi_set_phase(s, PHASE_DO);            break;        case 3:            lsi_set_phase(s, PHASE_DI);            break;        default:            abort();        }    }}/* Read the next byte during a MSGOUT phase.  */static uint8_t lsi_get_msgbyte(LSIState *s){    uint8_t data;    cpu_physical_memory_read(s->dnad, &data, 1);    s->dnad++;    s->dbc--;    return data;}static void lsi_do_msgout(LSIState *s){    uint8_t msg;    int len;    DPRINTF("MSG out len=%d\n", s->dbc);    while (s->dbc) {        msg = lsi_get_msgbyte(s);        s->sfbr = msg;        switch (msg) {        case 0x00:            DPRINTF("MSG: Disconnect\n");            lsi_disconnect(s);            break;        case 0x08:            DPRINTF("MSG: No Operation\n");            lsi_set_phase(s, PHASE_CMD);            break;        case 0x01:            len = lsi_get_msgbyte(s);            msg = lsi_get_msgbyte(s);            DPRINTF("Extended message 0x%x (len %d)\n", msg, len);            switch (msg) {            case 1:                DPRINTF("SDTR (ignored)\n");                s->dbc -= 2;                break;            case 3:                DPRINTF("WDTR (ignored)\n");                s->dbc -= 1;                break;            default:                goto bad;            }            break;        case 0x20: /* SIMPLE queue */            s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;            DPRINTF("SIMPLE queue tag=0x%x\n", s->current_tag & 0xff);            break;        case 0x21: /* HEAD of queue */            BADF("HEAD queue not implemented\n");            s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;            break;        case 0x22: /* ORDERED queue */            BADF("ORDERED queue not implemented\n");            s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;            break;        default:            if ((msg & 0x80) == 0) {                goto bad;            }            s->current_lun = msg & 7;            DPRINTF("Select LUN %d\n", s->current_lun);            lsi_set_phase(s, PHASE_CMD);            break;        }    }    return;bad:    BADF("Unimplemented message 0x%02x\n", msg);    lsi_set_phase(s, PHASE_MI);    lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */    s->msg_action = 0;}/* Sign extend a 24-bit value.  */static inline int32_t sxt24(int32_t n){    return (n << 8) >> 8;}static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count){    int n;    uint8_t buf[TARGET_PAGE_SIZE];    DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);    while (count) {        n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count;        cpu_physical_memory_read(src, buf, n);        cpu_physical_memory_write(dest, buf, n);        src += n;        dest += n;        count -= n;    }}static void lsi_wait_reselect(LSIState *s){    int i;    DPRINTF("Wait Reselect\n");    if (s->current_dma_len)        BADF("Reselect with pending DMA\n");    for (i = 0; i < s->active_commands; i++) {        if (s->queue[i].pending) {            lsi_reselect(s, s->queue[i].tag);            break;        }    }    if (s->current_dma_len == 0) {        s->waiting = 1;    }}static void lsi_execute_script(LSIState *s){    uint32_t insn;    uint32_t addr;    int opcode;    s->istat1 |= LSI_ISTAT1_SRUN;again:    insn = read_dword(s, s->dsp);    addr = read_dword(s, s->dsp + 4);    DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);    s->dsps = addr;    s->dcmd = insn >> 24;    s->dsp += 8;    switch (insn >> 30) {    case 0: /* Block move.  */        if (s->sist1 & LSI_SIST1_STO) {            DPRINTF("Delayed select timeout\n");            lsi_stop_script(s);            break;        }        s->dbc = insn & 0xffffff;        s->rbc = s->dbc;        if (insn & (1 << 29)) {            /* Indirect addressing.  */            addr = read_dword(s, addr);        } else if (insn & (1 << 28)) {            uint32_t buf[2];            int32_t offset;            /* Table indirect addressing.  */            offset = sxt24(addr);            cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8);            s->dbc = cpu_to_le32(buf[0]);            addr = cpu_to_le32(buf[1]);        }        if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {            DPRINTF("Wrong phase got %d expected %d\n",                    s->sstat1 & PHASE_MASK, (insn >> 24) & 7);            lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);            break;        }        s->dnad = addr;        switch (s->sstat1 & 0x7) {        case PHASE_DO:            s->waiting = 2;            lsi_do_dma(s, 1);            if (s->waiting)                s->waiting = 3;            break;        case PHASE_DI:            s->waiting = 2;            lsi_do_dma(s, 0);            if (s->waiting)                s->waiting = 3;            break;        case PHASE_CMD:            lsi_do_command(s);            break;        case PHASE_ST:            lsi_do_status(s);            break;        case PHASE_MO:            lsi_do_msgout(s);            break;        case PHASE_MI:            lsi_do_msgin(s);            break;        default:            BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK);            exit(1);        }        s->dfifo = s->dbc & 0xff;        s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3);        s->sbc = s->dbc;        s->rbc -= s->dbc;        s->ua = addr + s->dbc;        /* ??? Set ESA.  */        s->ia = s->dsp - 8;        break;    case 1: /* IO or Read/Write instruction.  */        opcode = (insn >> 27) & 7;        if (opcode < 5) {            uint32_t id;            if (insn & (1 << 25)) {                id = read_dword(s, s->dsa + sxt24(insn));            } else {                id = addr;            }            id = (id >> 16) & 0xf;            if (insn & (1 << 26)) {                addr = s->dsp + sxt24(addr);            }            s->dnad = addr;            switch (opcode) {            case 0: /* Select */                s->sdid = id;                if (s->current_dma_len && (s->ssid & 0xf) == id) {                    DPRINTF("Already reselected by target %d\n", id);                    break;                }                s->sstat0 |= LSI_SSTAT0_WOA;                s->scntl1 &= ~LSI_SCNTL1_IARB;                if (id >= LSI_MAX_DEVS || !s->scsi_dev[id]) {                    DPRINTF("Selected absent target %d\n", id);                    lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);                    lsi_disconnect(s);                    break;                }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -