xref: /openbmc/qemu/hw/scsi/lsi53c895a.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * QEMU LSI53C895A SCSI Host Bus Adapter emulation
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2006 CodeSourcery.
549ab747fSPaolo Bonzini  * Written by Paul Brook
649ab747fSPaolo Bonzini  *
749ab747fSPaolo Bonzini  * This code is licensed under the LGPL.
849ab747fSPaolo Bonzini  */
949ab747fSPaolo Bonzini 
10ceae18bdSHervé Poussineau /* Note:
11ceae18bdSHervé Poussineau  * LSI53C810 emulation is incorrect, in the sense that it supports
12ceae18bdSHervé Poussineau  * features added in later evolutions. This should not be a problem,
13ceae18bdSHervé Poussineau  * as well-behaved operating systems will not try to use them.
14ceae18bdSHervé Poussineau  */
15ceae18bdSHervé Poussineau 
16a4ab4792SPeter Maydell #include "qemu/osdep.h"
1749ab747fSPaolo Bonzini 
1864552b6bSMarkus Armbruster #include "hw/irq.h"
19edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h"
2049ab747fSPaolo Bonzini #include "hw/scsi/scsi.h"
21d6454270SMarkus Armbruster #include "migration/vmstate.h"
2249ab747fSPaolo Bonzini #include "sysemu/dma.h"
2385a20bc4SHervé Poussineau #include "qemu/log.h"
240b8fa32fSMarkus Armbruster #include "qemu/module.h"
25c921370bSMark Cave-Ayland #include "trace.h"
26db1015e9SEduardo Habkost #include "qom/object.h"
2749ab747fSPaolo Bonzini 
2864eb7491SHervé Poussineau static const char *names[] = {
2964eb7491SHervé Poussineau     "SCNTL0", "SCNTL1", "SCNTL2", "SCNTL3", "SCID", "SXFER", "SDID", "GPREG",
3064eb7491SHervé Poussineau     "SFBR", "SOCL", "SSID", "SBCL", "DSTAT", "SSTAT0", "SSTAT1", "SSTAT2",
3164eb7491SHervé Poussineau     "DSA0", "DSA1", "DSA2", "DSA3", "ISTAT", "0x15", "0x16", "0x17",
3264eb7491SHervé Poussineau     "CTEST0", "CTEST1", "CTEST2", "CTEST3", "TEMP0", "TEMP1", "TEMP2", "TEMP3",
3364eb7491SHervé Poussineau     "DFIFO", "CTEST4", "CTEST5", "CTEST6", "DBC0", "DBC1", "DBC2", "DCMD",
3464eb7491SHervé Poussineau     "DNAD0", "DNAD1", "DNAD2", "DNAD3", "DSP0", "DSP1", "DSP2", "DSP3",
3564eb7491SHervé Poussineau     "DSPS0", "DSPS1", "DSPS2", "DSPS3", "SCRATCHA0", "SCRATCHA1", "SCRATCHA2", "SCRATCHA3",
3664eb7491SHervé Poussineau     "DMODE", "DIEN", "SBR", "DCNTL", "ADDER0", "ADDER1", "ADDER2", "ADDER3",
3764eb7491SHervé Poussineau     "SIEN0", "SIEN1", "SIST0", "SIST1", "SLPAR", "0x45", "MACNTL", "GPCNTL",
3864eb7491SHervé Poussineau     "STIME0", "STIME1", "RESPID", "0x4b", "STEST0", "STEST1", "STEST2", "STEST3",
3964eb7491SHervé Poussineau     "SIDL", "0x51", "0x52", "0x53", "SODL", "0x55", "0x56", "0x57",
4064eb7491SHervé Poussineau     "SBDL", "0x59", "0x5a", "0x5b", "SCRATCHB0", "SCRATCHB1", "SCRATCHB2", "SCRATCHB3",
4164eb7491SHervé Poussineau };
4264eb7491SHervé Poussineau 
4349ab747fSPaolo Bonzini #define LSI_MAX_DEVS 7
4449ab747fSPaolo Bonzini 
4549ab747fSPaolo Bonzini #define LSI_SCNTL0_TRG    0x01
4649ab747fSPaolo Bonzini #define LSI_SCNTL0_AAP    0x02
4749ab747fSPaolo Bonzini #define LSI_SCNTL0_EPC    0x08
4849ab747fSPaolo Bonzini #define LSI_SCNTL0_WATN   0x10
4949ab747fSPaolo Bonzini #define LSI_SCNTL0_START  0x20
5049ab747fSPaolo Bonzini 
5149ab747fSPaolo Bonzini #define LSI_SCNTL1_SST    0x01
5249ab747fSPaolo Bonzini #define LSI_SCNTL1_IARB   0x02
5349ab747fSPaolo Bonzini #define LSI_SCNTL1_AESP   0x04
5449ab747fSPaolo Bonzini #define LSI_SCNTL1_RST    0x08
5549ab747fSPaolo Bonzini #define LSI_SCNTL1_CON    0x10
5649ab747fSPaolo Bonzini #define LSI_SCNTL1_DHP    0x20
5749ab747fSPaolo Bonzini #define LSI_SCNTL1_ADB    0x40
5849ab747fSPaolo Bonzini #define LSI_SCNTL1_EXC    0x80
5949ab747fSPaolo Bonzini 
6049ab747fSPaolo Bonzini #define LSI_SCNTL2_WSR    0x01
6149ab747fSPaolo Bonzini #define LSI_SCNTL2_VUE0   0x02
6249ab747fSPaolo Bonzini #define LSI_SCNTL2_VUE1   0x04
6349ab747fSPaolo Bonzini #define LSI_SCNTL2_WSS    0x08
6449ab747fSPaolo Bonzini #define LSI_SCNTL2_SLPHBEN 0x10
6549ab747fSPaolo Bonzini #define LSI_SCNTL2_SLPMD  0x20
6649ab747fSPaolo Bonzini #define LSI_SCNTL2_CHM    0x40
6749ab747fSPaolo Bonzini #define LSI_SCNTL2_SDU    0x80
6849ab747fSPaolo Bonzini 
6949ab747fSPaolo Bonzini #define LSI_ISTAT0_DIP    0x01
7049ab747fSPaolo Bonzini #define LSI_ISTAT0_SIP    0x02
7149ab747fSPaolo Bonzini #define LSI_ISTAT0_INTF   0x04
7249ab747fSPaolo Bonzini #define LSI_ISTAT0_CON    0x08
7349ab747fSPaolo Bonzini #define LSI_ISTAT0_SEM    0x10
7449ab747fSPaolo Bonzini #define LSI_ISTAT0_SIGP   0x20
7549ab747fSPaolo Bonzini #define LSI_ISTAT0_SRST   0x40
7649ab747fSPaolo Bonzini #define LSI_ISTAT0_ABRT   0x80
7749ab747fSPaolo Bonzini 
7849ab747fSPaolo Bonzini #define LSI_ISTAT1_SI     0x01
7949ab747fSPaolo Bonzini #define LSI_ISTAT1_SRUN   0x02
8049ab747fSPaolo Bonzini #define LSI_ISTAT1_FLSH   0x04
8149ab747fSPaolo Bonzini 
8249ab747fSPaolo Bonzini #define LSI_SSTAT0_SDP0   0x01
8349ab747fSPaolo Bonzini #define LSI_SSTAT0_RST    0x02
8449ab747fSPaolo Bonzini #define LSI_SSTAT0_WOA    0x04
8549ab747fSPaolo Bonzini #define LSI_SSTAT0_LOA    0x08
8649ab747fSPaolo Bonzini #define LSI_SSTAT0_AIP    0x10
8749ab747fSPaolo Bonzini #define LSI_SSTAT0_OLF    0x20
8849ab747fSPaolo Bonzini #define LSI_SSTAT0_ORF    0x40
8949ab747fSPaolo Bonzini #define LSI_SSTAT0_ILF    0x80
9049ab747fSPaolo Bonzini 
9149ab747fSPaolo Bonzini #define LSI_SIST0_PAR     0x01
9249ab747fSPaolo Bonzini #define LSI_SIST0_RST     0x02
9349ab747fSPaolo Bonzini #define LSI_SIST0_UDC     0x04
9449ab747fSPaolo Bonzini #define LSI_SIST0_SGE     0x08
9549ab747fSPaolo Bonzini #define LSI_SIST0_RSL     0x10
9649ab747fSPaolo Bonzini #define LSI_SIST0_SEL     0x20
9749ab747fSPaolo Bonzini #define LSI_SIST0_CMP     0x40
9849ab747fSPaolo Bonzini #define LSI_SIST0_MA      0x80
9949ab747fSPaolo Bonzini 
10049ab747fSPaolo Bonzini #define LSI_SIST1_HTH     0x01
10149ab747fSPaolo Bonzini #define LSI_SIST1_GEN     0x02
10249ab747fSPaolo Bonzini #define LSI_SIST1_STO     0x04
10349ab747fSPaolo Bonzini #define LSI_SIST1_SBMC    0x10
10449ab747fSPaolo Bonzini 
10549ab747fSPaolo Bonzini #define LSI_SOCL_IO       0x01
10649ab747fSPaolo Bonzini #define LSI_SOCL_CD       0x02
10749ab747fSPaolo Bonzini #define LSI_SOCL_MSG      0x04
10849ab747fSPaolo Bonzini #define LSI_SOCL_ATN      0x08
10949ab747fSPaolo Bonzini #define LSI_SOCL_SEL      0x10
11049ab747fSPaolo Bonzini #define LSI_SOCL_BSY      0x20
11149ab747fSPaolo Bonzini #define LSI_SOCL_ACK      0x40
11249ab747fSPaolo Bonzini #define LSI_SOCL_REQ      0x80
11349ab747fSPaolo Bonzini 
11449ab747fSPaolo Bonzini #define LSI_DSTAT_IID     0x01
11549ab747fSPaolo Bonzini #define LSI_DSTAT_SIR     0x04
11649ab747fSPaolo Bonzini #define LSI_DSTAT_SSI     0x08
11749ab747fSPaolo Bonzini #define LSI_DSTAT_ABRT    0x10
11849ab747fSPaolo Bonzini #define LSI_DSTAT_BF      0x20
11949ab747fSPaolo Bonzini #define LSI_DSTAT_MDPE    0x40
12049ab747fSPaolo Bonzini #define LSI_DSTAT_DFE     0x80
12149ab747fSPaolo Bonzini 
12249ab747fSPaolo Bonzini #define LSI_DCNTL_COM     0x01
12349ab747fSPaolo Bonzini #define LSI_DCNTL_IRQD    0x02
12449ab747fSPaolo Bonzini #define LSI_DCNTL_STD     0x04
12549ab747fSPaolo Bonzini #define LSI_DCNTL_IRQM    0x08
12649ab747fSPaolo Bonzini #define LSI_DCNTL_SSM     0x10
12749ab747fSPaolo Bonzini #define LSI_DCNTL_PFEN    0x20
12849ab747fSPaolo Bonzini #define LSI_DCNTL_PFF     0x40
12949ab747fSPaolo Bonzini #define LSI_DCNTL_CLSE    0x80
13049ab747fSPaolo Bonzini 
13149ab747fSPaolo Bonzini #define LSI_DMODE_MAN     0x01
13249ab747fSPaolo Bonzini #define LSI_DMODE_BOF     0x02
13349ab747fSPaolo Bonzini #define LSI_DMODE_ERMP    0x04
13449ab747fSPaolo Bonzini #define LSI_DMODE_ERL     0x08
13549ab747fSPaolo Bonzini #define LSI_DMODE_DIOM    0x10
13649ab747fSPaolo Bonzini #define LSI_DMODE_SIOM    0x20
13749ab747fSPaolo Bonzini 
13849ab747fSPaolo Bonzini #define LSI_CTEST2_DACK   0x01
13949ab747fSPaolo Bonzini #define LSI_CTEST2_DREQ   0x02
14049ab747fSPaolo Bonzini #define LSI_CTEST2_TEOP   0x04
14149ab747fSPaolo Bonzini #define LSI_CTEST2_PCICIE 0x08
14249ab747fSPaolo Bonzini #define LSI_CTEST2_CM     0x10
14349ab747fSPaolo Bonzini #define LSI_CTEST2_CIO    0x20
14449ab747fSPaolo Bonzini #define LSI_CTEST2_SIGP   0x40
14549ab747fSPaolo Bonzini #define LSI_CTEST2_DDIR   0x80
14649ab747fSPaolo Bonzini 
14749ab747fSPaolo Bonzini #define LSI_CTEST5_BL2    0x04
14849ab747fSPaolo Bonzini #define LSI_CTEST5_DDIR   0x08
14949ab747fSPaolo Bonzini #define LSI_CTEST5_MASR   0x10
15049ab747fSPaolo Bonzini #define LSI_CTEST5_DFSN   0x20
15149ab747fSPaolo Bonzini #define LSI_CTEST5_BBCK   0x40
15249ab747fSPaolo Bonzini #define LSI_CTEST5_ADCK   0x80
15349ab747fSPaolo Bonzini 
15449ab747fSPaolo Bonzini #define LSI_CCNTL0_DILS   0x01
15549ab747fSPaolo Bonzini #define LSI_CCNTL0_DISFC  0x10
15649ab747fSPaolo Bonzini #define LSI_CCNTL0_ENNDJ  0x20
15749ab747fSPaolo Bonzini #define LSI_CCNTL0_PMJCTL 0x40
15849ab747fSPaolo Bonzini #define LSI_CCNTL0_ENPMJ  0x80
15949ab747fSPaolo Bonzini 
16049ab747fSPaolo Bonzini #define LSI_CCNTL1_EN64DBMV  0x01
16149ab747fSPaolo Bonzini #define LSI_CCNTL1_EN64TIBMV 0x02
16249ab747fSPaolo Bonzini #define LSI_CCNTL1_64TIMOD   0x04
16349ab747fSPaolo Bonzini #define LSI_CCNTL1_DDAC      0x08
16449ab747fSPaolo Bonzini #define LSI_CCNTL1_ZMOD      0x80
16549ab747fSPaolo Bonzini 
16612dd89f7SSven Schnelle #define LSI_SBCL_ATN         0x08
16712dd89f7SSven Schnelle #define LSI_SBCL_BSY         0x20
16812dd89f7SSven Schnelle #define LSI_SBCL_ACK         0x40
16912dd89f7SSven Schnelle #define LSI_SBCL_REQ         0x80
17012dd89f7SSven Schnelle 
17149ab747fSPaolo Bonzini /* Enable Response to Reselection */
17249ab747fSPaolo Bonzini #define LSI_SCID_RRE      0x60
17349ab747fSPaolo Bonzini 
17449ab747fSPaolo Bonzini #define LSI_CCNTL1_40BIT (LSI_CCNTL1_EN64TIBMV|LSI_CCNTL1_64TIMOD)
17549ab747fSPaolo Bonzini 
17649ab747fSPaolo Bonzini #define PHASE_DO          0
17749ab747fSPaolo Bonzini #define PHASE_DI          1
17849ab747fSPaolo Bonzini #define PHASE_CMD         2
17949ab747fSPaolo Bonzini #define PHASE_ST          3
18049ab747fSPaolo Bonzini #define PHASE_MO          6
18149ab747fSPaolo Bonzini #define PHASE_MI          7
18249ab747fSPaolo Bonzini #define PHASE_MASK        7
18349ab747fSPaolo Bonzini 
18449ab747fSPaolo Bonzini /* Maximum length of MSG IN data.  */
18549ab747fSPaolo Bonzini #define LSI_MAX_MSGIN_LEN 8
18649ab747fSPaolo Bonzini 
18749ab747fSPaolo Bonzini /* Flag set if this is a tagged command.  */
18849ab747fSPaolo Bonzini #define LSI_TAG_VALID     (1 << 16)
18949ab747fSPaolo Bonzini 
190de594e47SPaolo Bonzini /* Maximum instructions to process. */
191a4975023SFiona Ebner #define LSI_MAX_INSN    500
192de594e47SPaolo Bonzini 
19349ab747fSPaolo Bonzini typedef struct lsi_request {
19449ab747fSPaolo Bonzini     SCSIRequest *req;
19549ab747fSPaolo Bonzini     uint32_t tag;
19649ab747fSPaolo Bonzini     uint32_t dma_len;
19749ab747fSPaolo Bonzini     uint8_t *dma_buf;
19849ab747fSPaolo Bonzini     uint32_t pending;
19949ab747fSPaolo Bonzini     int out;
20049ab747fSPaolo Bonzini     QTAILQ_ENTRY(lsi_request) next;
20149ab747fSPaolo Bonzini } lsi_request;
20249ab747fSPaolo Bonzini 
203f08ec2b8SSven Schnelle enum {
204f08ec2b8SSven Schnelle     LSI_NOWAIT, /* SCRIPTS are running or stopped */
205f08ec2b8SSven Schnelle     LSI_WAIT_RESELECT, /* Wait Reselect instruction has been issued */
206f08ec2b8SSven Schnelle     LSI_DMA_SCRIPTS, /* processing DMA from lsi_execute_script */
207f08ec2b8SSven Schnelle     LSI_DMA_IN_PROGRESS, /* DMA operation is in progress */
20898763599SSven Schnelle     LSI_WAIT_SCRIPTS, /* SCRIPTS stopped because of instruction count limit */
209f08ec2b8SSven Schnelle };
210f08ec2b8SSven Schnelle 
2114ae63d37SSven Schnelle enum {
2124ae63d37SSven Schnelle     LSI_MSG_ACTION_COMMAND = 0,
2134ae63d37SSven Schnelle     LSI_MSG_ACTION_DISCONNECT = 1,
2144ae63d37SSven Schnelle     LSI_MSG_ACTION_DOUT = 2,
2154ae63d37SSven Schnelle     LSI_MSG_ACTION_DIN = 3,
2164ae63d37SSven Schnelle };
2174ae63d37SSven Schnelle 
218db1015e9SEduardo Habkost struct LSIState {
219725eec70SAndreas Färber     /*< private >*/
220725eec70SAndreas Färber     PCIDevice parent_obj;
221725eec70SAndreas Färber     /*< public >*/
222725eec70SAndreas Färber 
2233cc1b9cbSMark Cave-Ayland     qemu_irq ext_irq;
22449ab747fSPaolo Bonzini     MemoryRegion mmio_io;
22549ab747fSPaolo Bonzini     MemoryRegion ram_io;
22649ab747fSPaolo Bonzini     MemoryRegion io_io;
227a8632434SHervé Poussineau     AddressSpace pci_io_as;
22898763599SSven Schnelle     QEMUTimer *scripts_timer;
22949ab747fSPaolo Bonzini 
230b1f1dc91SBALATON Zoltan     int carry; /* ??? Should this be in a visible register somewhere?  */
23149ab747fSPaolo Bonzini     int status;
23249ab747fSPaolo Bonzini     int msg_action;
23349ab747fSPaolo Bonzini     int msg_len;
23449ab747fSPaolo Bonzini     uint8_t msg[LSI_MAX_MSGIN_LEN];
23549ab747fSPaolo Bonzini     int waiting;
23649ab747fSPaolo Bonzini     SCSIBus bus;
23749ab747fSPaolo Bonzini     int current_lun;
23849ab747fSPaolo Bonzini     /* The tag is a combination of the device ID and the SCSI tag.  */
23949ab747fSPaolo Bonzini     uint32_t select_tag;
24049ab747fSPaolo Bonzini     int command_complete;
24149ab747fSPaolo Bonzini     QTAILQ_HEAD(, lsi_request) queue;
24249ab747fSPaolo Bonzini     lsi_request *current;
24349ab747fSPaolo Bonzini 
24449ab747fSPaolo Bonzini     uint32_t dsa;
24549ab747fSPaolo Bonzini     uint32_t temp;
24649ab747fSPaolo Bonzini     uint32_t dnad;
24749ab747fSPaolo Bonzini     uint32_t dbc;
24849ab747fSPaolo Bonzini     uint8_t istat0;
24949ab747fSPaolo Bonzini     uint8_t istat1;
25049ab747fSPaolo Bonzini     uint8_t dcmd;
25149ab747fSPaolo Bonzini     uint8_t dstat;
25249ab747fSPaolo Bonzini     uint8_t dien;
25349ab747fSPaolo Bonzini     uint8_t sist0;
25449ab747fSPaolo Bonzini     uint8_t sist1;
25549ab747fSPaolo Bonzini     uint8_t sien0;
25649ab747fSPaolo Bonzini     uint8_t sien1;
25749ab747fSPaolo Bonzini     uint8_t mbox0;
25849ab747fSPaolo Bonzini     uint8_t mbox1;
25949ab747fSPaolo Bonzini     uint8_t dfifo;
26049ab747fSPaolo Bonzini     uint8_t ctest2;
26149ab747fSPaolo Bonzini     uint8_t ctest3;
26249ab747fSPaolo Bonzini     uint8_t ctest4;
26349ab747fSPaolo Bonzini     uint8_t ctest5;
26449ab747fSPaolo Bonzini     uint8_t ccntl0;
26549ab747fSPaolo Bonzini     uint8_t ccntl1;
26649ab747fSPaolo Bonzini     uint32_t dsp;
26749ab747fSPaolo Bonzini     uint32_t dsps;
26849ab747fSPaolo Bonzini     uint8_t dmode;
26949ab747fSPaolo Bonzini     uint8_t dcntl;
27049ab747fSPaolo Bonzini     uint8_t scntl0;
27149ab747fSPaolo Bonzini     uint8_t scntl1;
27249ab747fSPaolo Bonzini     uint8_t scntl2;
27349ab747fSPaolo Bonzini     uint8_t scntl3;
27449ab747fSPaolo Bonzini     uint8_t sstat0;
27549ab747fSPaolo Bonzini     uint8_t sstat1;
27649ab747fSPaolo Bonzini     uint8_t scid;
27749ab747fSPaolo Bonzini     uint8_t sxfer;
27849ab747fSPaolo Bonzini     uint8_t socl;
27949ab747fSPaolo Bonzini     uint8_t sdid;
28049ab747fSPaolo Bonzini     uint8_t ssid;
28149ab747fSPaolo Bonzini     uint8_t sfbr;
28212dd89f7SSven Schnelle     uint8_t sbcl;
28349ab747fSPaolo Bonzini     uint8_t stest1;
28449ab747fSPaolo Bonzini     uint8_t stest2;
28549ab747fSPaolo Bonzini     uint8_t stest3;
28649ab747fSPaolo Bonzini     uint8_t sidl;
28749ab747fSPaolo Bonzini     uint8_t stime0;
28849ab747fSPaolo Bonzini     uint8_t respid0;
28949ab747fSPaolo Bonzini     uint8_t respid1;
29049ab747fSPaolo Bonzini     uint32_t mmrs;
29149ab747fSPaolo Bonzini     uint32_t mmws;
29249ab747fSPaolo Bonzini     uint32_t sfs;
29349ab747fSPaolo Bonzini     uint32_t drs;
29449ab747fSPaolo Bonzini     uint32_t sbms;
29549ab747fSPaolo Bonzini     uint32_t dbms;
29649ab747fSPaolo Bonzini     uint32_t dnad64;
29749ab747fSPaolo Bonzini     uint32_t pmjad1;
29849ab747fSPaolo Bonzini     uint32_t pmjad2;
29949ab747fSPaolo Bonzini     uint32_t rbc;
30049ab747fSPaolo Bonzini     uint32_t ua;
30149ab747fSPaolo Bonzini     uint32_t ia;
30249ab747fSPaolo Bonzini     uint32_t sbc;
30349ab747fSPaolo Bonzini     uint32_t csbc;
30449ab747fSPaolo Bonzini     uint32_t scratch[18]; /* SCRATCHA-SCRATCHR */
30549ab747fSPaolo Bonzini     uint8_t sbr;
3066f84da3aSPeter Lieven     uint32_t adder;
30749ab747fSPaolo Bonzini 
308811a75baSSven Schnelle     uint8_t script_ram[2048 * sizeof(uint32_t)];
309db1015e9SEduardo Habkost };
31049ab747fSPaolo Bonzini 
311ceae18bdSHervé Poussineau #define TYPE_LSI53C810  "lsi53c810"
31271186c86SPeter Crosthwaite #define TYPE_LSI53C895A "lsi53c895a"
31371186c86SPeter Crosthwaite 
3148063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(LSIState, LSI53C895A)
31571186c86SPeter Crosthwaite 
31682cf2bcfSSven Schnelle static const char *scsi_phases[] = {
31782cf2bcfSSven Schnelle     "DOUT",
31882cf2bcfSSven Schnelle     "DIN",
31982cf2bcfSSven Schnelle     "CMD",
32082cf2bcfSSven Schnelle     "STATUS",
32182cf2bcfSSven Schnelle     "RSVOUT",
32282cf2bcfSSven Schnelle     "RSVIN",
32382cf2bcfSSven Schnelle     "MSGOUT",
32482cf2bcfSSven Schnelle     "MSGIN"
32582cf2bcfSSven Schnelle };
32682cf2bcfSSven Schnelle 
scsi_phase_name(int phase)32782cf2bcfSSven Schnelle static const char *scsi_phase_name(int phase)
32882cf2bcfSSven Schnelle {
32982cf2bcfSSven Schnelle     return scsi_phases[phase & PHASE_MASK];
33082cf2bcfSSven Schnelle }
33182cf2bcfSSven Schnelle 
lsi_irq_on_rsl(LSIState * s)33249ab747fSPaolo Bonzini static inline int lsi_irq_on_rsl(LSIState *s)
33349ab747fSPaolo Bonzini {
33449ab747fSPaolo Bonzini     return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE);
33549ab747fSPaolo Bonzini }
33649ab747fSPaolo Bonzini 
get_pending_req(LSIState * s)33756333e69SGeorge Kennedy static lsi_request *get_pending_req(LSIState *s)
33856333e69SGeorge Kennedy {
33956333e69SGeorge Kennedy     lsi_request *p;
34056333e69SGeorge Kennedy 
34156333e69SGeorge Kennedy     QTAILQ_FOREACH(p, &s->queue, next) {
34256333e69SGeorge Kennedy         if (p->pending) {
34356333e69SGeorge Kennedy             return p;
34456333e69SGeorge Kennedy         }
34556333e69SGeorge Kennedy     }
34656333e69SGeorge Kennedy     return NULL;
34756333e69SGeorge Kennedy }
34856333e69SGeorge Kennedy 
lsi_soft_reset(LSIState * s)34949ab747fSPaolo Bonzini static void lsi_soft_reset(LSIState *s)
35049ab747fSPaolo Bonzini {
351c921370bSMark Cave-Ayland     trace_lsi_reset();
35249ab747fSPaolo Bonzini     s->carry = 0;
35349ab747fSPaolo Bonzini 
3544ae63d37SSven Schnelle     s->msg_action = LSI_MSG_ACTION_COMMAND;
35549ab747fSPaolo Bonzini     s->msg_len = 0;
356f08ec2b8SSven Schnelle     s->waiting = LSI_NOWAIT;
35749ab747fSPaolo Bonzini     s->dsa = 0;
35849ab747fSPaolo Bonzini     s->dnad = 0;
35949ab747fSPaolo Bonzini     s->dbc = 0;
36049ab747fSPaolo Bonzini     s->temp = 0;
36149ab747fSPaolo Bonzini     memset(s->scratch, 0, sizeof(s->scratch));
36249ab747fSPaolo Bonzini     s->istat0 = 0;
36349ab747fSPaolo Bonzini     s->istat1 = 0;
36449ab747fSPaolo Bonzini     s->dcmd = 0x40;
36598f62e3dSHervé Poussineau     s->dstat = 0;
36649ab747fSPaolo Bonzini     s->dien = 0;
36749ab747fSPaolo Bonzini     s->sist0 = 0;
36849ab747fSPaolo Bonzini     s->sist1 = 0;
36949ab747fSPaolo Bonzini     s->sien0 = 0;
37049ab747fSPaolo Bonzini     s->sien1 = 0;
37149ab747fSPaolo Bonzini     s->mbox0 = 0;
37249ab747fSPaolo Bonzini     s->mbox1 = 0;
37349ab747fSPaolo Bonzini     s->dfifo = 0;
37449ab747fSPaolo Bonzini     s->ctest2 = LSI_CTEST2_DACK;
37549ab747fSPaolo Bonzini     s->ctest3 = 0;
37649ab747fSPaolo Bonzini     s->ctest4 = 0;
37749ab747fSPaolo Bonzini     s->ctest5 = 0;
37849ab747fSPaolo Bonzini     s->ccntl0 = 0;
37949ab747fSPaolo Bonzini     s->ccntl1 = 0;
38049ab747fSPaolo Bonzini     s->dsp = 0;
38149ab747fSPaolo Bonzini     s->dsps = 0;
38249ab747fSPaolo Bonzini     s->dmode = 0;
38349ab747fSPaolo Bonzini     s->dcntl = 0;
38449ab747fSPaolo Bonzini     s->scntl0 = 0xc0;
38549ab747fSPaolo Bonzini     s->scntl1 = 0;
38649ab747fSPaolo Bonzini     s->scntl2 = 0;
38749ab747fSPaolo Bonzini     s->scntl3 = 0;
38849ab747fSPaolo Bonzini     s->sstat0 = 0;
38949ab747fSPaolo Bonzini     s->sstat1 = 0;
39049ab747fSPaolo Bonzini     s->scid = 7;
39149ab747fSPaolo Bonzini     s->sxfer = 0;
39249ab747fSPaolo Bonzini     s->socl = 0;
39349ab747fSPaolo Bonzini     s->sdid = 0;
39449ab747fSPaolo Bonzini     s->ssid = 0;
39512dd89f7SSven Schnelle     s->sbcl = 0;
39649ab747fSPaolo Bonzini     s->stest1 = 0;
39749ab747fSPaolo Bonzini     s->stest2 = 0;
39849ab747fSPaolo Bonzini     s->stest3 = 0;
39949ab747fSPaolo Bonzini     s->sidl = 0;
40049ab747fSPaolo Bonzini     s->stime0 = 0;
40149ab747fSPaolo Bonzini     s->respid0 = 0x80;
40249ab747fSPaolo Bonzini     s->respid1 = 0;
40349ab747fSPaolo Bonzini     s->mmrs = 0;
40449ab747fSPaolo Bonzini     s->mmws = 0;
40549ab747fSPaolo Bonzini     s->sfs = 0;
40649ab747fSPaolo Bonzini     s->drs = 0;
40749ab747fSPaolo Bonzini     s->sbms = 0;
40849ab747fSPaolo Bonzini     s->dbms = 0;
40949ab747fSPaolo Bonzini     s->dnad64 = 0;
41049ab747fSPaolo Bonzini     s->pmjad1 = 0;
41149ab747fSPaolo Bonzini     s->pmjad2 = 0;
41249ab747fSPaolo Bonzini     s->rbc = 0;
41349ab747fSPaolo Bonzini     s->ua = 0;
41449ab747fSPaolo Bonzini     s->ia = 0;
41549ab747fSPaolo Bonzini     s->sbc = 0;
41649ab747fSPaolo Bonzini     s->csbc = 0;
41749ab747fSPaolo Bonzini     s->sbr = 0;
41849ab747fSPaolo Bonzini     assert(QTAILQ_EMPTY(&s->queue));
41949ab747fSPaolo Bonzini     assert(!s->current);
42098763599SSven Schnelle     timer_del(s->scripts_timer);
42149ab747fSPaolo Bonzini }
42249ab747fSPaolo Bonzini 
lsi_dma_40bit(LSIState * s)42349ab747fSPaolo Bonzini static int lsi_dma_40bit(LSIState *s)
42449ab747fSPaolo Bonzini {
42549ab747fSPaolo Bonzini     if ((s->ccntl1 & LSI_CCNTL1_40BIT) == LSI_CCNTL1_40BIT)
42649ab747fSPaolo Bonzini         return 1;
42749ab747fSPaolo Bonzini     return 0;
42849ab747fSPaolo Bonzini }
42949ab747fSPaolo Bonzini 
lsi_dma_ti64bit(LSIState * s)43049ab747fSPaolo Bonzini static int lsi_dma_ti64bit(LSIState *s)
43149ab747fSPaolo Bonzini {
43249ab747fSPaolo Bonzini     if ((s->ccntl1 & LSI_CCNTL1_EN64TIBMV) == LSI_CCNTL1_EN64TIBMV)
43349ab747fSPaolo Bonzini         return 1;
43449ab747fSPaolo Bonzini     return 0;
43549ab747fSPaolo Bonzini }
43649ab747fSPaolo Bonzini 
lsi_dma_64bit(LSIState * s)43749ab747fSPaolo Bonzini static int lsi_dma_64bit(LSIState *s)
43849ab747fSPaolo Bonzini {
43949ab747fSPaolo Bonzini     if ((s->ccntl1 & LSI_CCNTL1_EN64DBMV) == LSI_CCNTL1_EN64DBMV)
44049ab747fSPaolo Bonzini         return 1;
44149ab747fSPaolo Bonzini     return 0;
44249ab747fSPaolo Bonzini }
44349ab747fSPaolo Bonzini 
44449ab747fSPaolo Bonzini static uint8_t lsi_reg_readb(LSIState *s, int offset);
44549ab747fSPaolo Bonzini static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
44649ab747fSPaolo Bonzini static void lsi_execute_script(LSIState *s);
44749ab747fSPaolo Bonzini static void lsi_reselect(LSIState *s, lsi_request *p);
44849ab747fSPaolo Bonzini 
lsi_mem_read(LSIState * s,dma_addr_t addr,void * buf,dma_addr_t len)4493975bb56SMao Zhongyi static inline void lsi_mem_read(LSIState *s, dma_addr_t addr,
450a8632434SHervé Poussineau                                void *buf, dma_addr_t len)
451a8632434SHervé Poussineau {
452a8632434SHervé Poussineau     if (s->dmode & LSI_DMODE_SIOM) {
453a8632434SHervé Poussineau         address_space_read(&s->pci_io_as, addr, MEMTXATTRS_UNSPECIFIED,
454a8632434SHervé Poussineau                            buf, len);
455a8632434SHervé Poussineau     } else {
4563975bb56SMao Zhongyi         pci_dma_read(PCI_DEVICE(s), addr, buf, len);
457a8632434SHervé Poussineau     }
458a8632434SHervé Poussineau }
459a8632434SHervé Poussineau 
lsi_mem_write(LSIState * s,dma_addr_t addr,const void * buf,dma_addr_t len)4603975bb56SMao Zhongyi static inline void lsi_mem_write(LSIState *s, dma_addr_t addr,
461a8632434SHervé Poussineau                                 const void *buf, dma_addr_t len)
462a8632434SHervé Poussineau {
463a8632434SHervé Poussineau     if (s->dmode & LSI_DMODE_DIOM) {
464a8632434SHervé Poussineau         address_space_write(&s->pci_io_as, addr, MEMTXATTRS_UNSPECIFIED,
465a8632434SHervé Poussineau                             buf, len);
466a8632434SHervé Poussineau     } else {
4673975bb56SMao Zhongyi         pci_dma_write(PCI_DEVICE(s), addr, buf, len);
468a8632434SHervé Poussineau     }
469a8632434SHervé Poussineau }
470a8632434SHervé Poussineau 
read_dword(LSIState * s,uint32_t addr)47149ab747fSPaolo Bonzini static inline uint32_t read_dword(LSIState *s, uint32_t addr)
47249ab747fSPaolo Bonzini {
47349ab747fSPaolo Bonzini     uint32_t buf;
47449ab747fSPaolo Bonzini 
475725eec70SAndreas Färber     pci_dma_read(PCI_DEVICE(s), addr, &buf, 4);
47649ab747fSPaolo Bonzini     return cpu_to_le32(buf);
47749ab747fSPaolo Bonzini }
47849ab747fSPaolo Bonzini 
lsi_stop_script(LSIState * s)47949ab747fSPaolo Bonzini static void lsi_stop_script(LSIState *s)
48049ab747fSPaolo Bonzini {
48149ab747fSPaolo Bonzini     s->istat1 &= ~LSI_ISTAT1_SRUN;
48249ab747fSPaolo Bonzini }
48349ab747fSPaolo Bonzini 
lsi_set_irq(LSIState * s,int level)4843cc1b9cbSMark Cave-Ayland static void lsi_set_irq(LSIState *s, int level)
48549ab747fSPaolo Bonzini {
486725eec70SAndreas Färber     PCIDevice *d = PCI_DEVICE(s);
4873cc1b9cbSMark Cave-Ayland 
4883cc1b9cbSMark Cave-Ayland     if (s->ext_irq) {
4893cc1b9cbSMark Cave-Ayland         qemu_set_irq(s->ext_irq, level);
4903cc1b9cbSMark Cave-Ayland     } else {
4913cc1b9cbSMark Cave-Ayland         pci_set_irq(d, level);
4923cc1b9cbSMark Cave-Ayland     }
4933cc1b9cbSMark Cave-Ayland }
4943cc1b9cbSMark Cave-Ayland 
lsi_update_irq(LSIState * s)4953cc1b9cbSMark Cave-Ayland static void lsi_update_irq(LSIState *s)
4963cc1b9cbSMark Cave-Ayland {
49749ab747fSPaolo Bonzini     int level;
49849ab747fSPaolo Bonzini     static int last_level;
49949ab747fSPaolo Bonzini 
50049ab747fSPaolo Bonzini     /* It's unclear whether the DIP/SIP bits should be cleared when the
50149ab747fSPaolo Bonzini        Interrupt Status Registers are cleared or when istat0 is read.
50249ab747fSPaolo Bonzini        We currently do the formwer, which seems to work.  */
50349ab747fSPaolo Bonzini     level = 0;
50449ab747fSPaolo Bonzini     if (s->dstat) {
50549ab747fSPaolo Bonzini         if (s->dstat & s->dien)
50649ab747fSPaolo Bonzini             level = 1;
50749ab747fSPaolo Bonzini         s->istat0 |= LSI_ISTAT0_DIP;
50849ab747fSPaolo Bonzini     } else {
50949ab747fSPaolo Bonzini         s->istat0 &= ~LSI_ISTAT0_DIP;
51049ab747fSPaolo Bonzini     }
51149ab747fSPaolo Bonzini 
51249ab747fSPaolo Bonzini     if (s->sist0 || s->sist1) {
51349ab747fSPaolo Bonzini         if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1))
51449ab747fSPaolo Bonzini             level = 1;
51549ab747fSPaolo Bonzini         s->istat0 |= LSI_ISTAT0_SIP;
51649ab747fSPaolo Bonzini     } else {
51749ab747fSPaolo Bonzini         s->istat0 &= ~LSI_ISTAT0_SIP;
51849ab747fSPaolo Bonzini     }
51949ab747fSPaolo Bonzini     if (s->istat0 & LSI_ISTAT0_INTF)
52049ab747fSPaolo Bonzini         level = 1;
52149ab747fSPaolo Bonzini 
52249ab747fSPaolo Bonzini     if (level != last_level) {
523c921370bSMark Cave-Ayland         trace_lsi_update_irq(level, s->dstat, s->sist1, s->sist0);
52449ab747fSPaolo Bonzini         last_level = level;
52549ab747fSPaolo Bonzini     }
5263cc1b9cbSMark Cave-Ayland     lsi_set_irq(s, level);
52749ab747fSPaolo Bonzini 
52856333e69SGeorge Kennedy     if (!s->current && !level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
52956333e69SGeorge Kennedy         lsi_request *p;
53056333e69SGeorge Kennedy 
531c921370bSMark Cave-Ayland         trace_lsi_update_irq_disconnected();
53256333e69SGeorge Kennedy         p = get_pending_req(s);
53356333e69SGeorge Kennedy         if (p) {
53449ab747fSPaolo Bonzini             lsi_reselect(s, p);
53549ab747fSPaolo Bonzini         }
53649ab747fSPaolo Bonzini     }
53749ab747fSPaolo Bonzini }
53849ab747fSPaolo Bonzini 
53949ab747fSPaolo Bonzini /* Stop SCRIPTS execution and raise a SCSI interrupt.  */
lsi_script_scsi_interrupt(LSIState * s,int stat0,int stat1)54049ab747fSPaolo Bonzini static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
54149ab747fSPaolo Bonzini {
54249ab747fSPaolo Bonzini     uint32_t mask0;
54349ab747fSPaolo Bonzini     uint32_t mask1;
54449ab747fSPaolo Bonzini 
545c921370bSMark Cave-Ayland     trace_lsi_script_scsi_interrupt(stat1, stat0, s->sist1, s->sist0);
54649ab747fSPaolo Bonzini     s->sist0 |= stat0;
54749ab747fSPaolo Bonzini     s->sist1 |= stat1;
54849ab747fSPaolo Bonzini     /* Stop processor on fatal or unmasked interrupt.  As a special hack
54949ab747fSPaolo Bonzini        we don't stop processing when raising STO.  Instead continue
55049ab747fSPaolo Bonzini        execution and stop at the next insn that accesses the SCSI bus.  */
55149ab747fSPaolo Bonzini     mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL);
55249ab747fSPaolo Bonzini     mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH);
55349ab747fSPaolo Bonzini     mask1 &= ~LSI_SIST1_STO;
55449ab747fSPaolo Bonzini     if (s->sist0 & mask0 || s->sist1 & mask1) {
55549ab747fSPaolo Bonzini         lsi_stop_script(s);
55649ab747fSPaolo Bonzini     }
55749ab747fSPaolo Bonzini     lsi_update_irq(s);
55849ab747fSPaolo Bonzini }
55949ab747fSPaolo Bonzini 
56049ab747fSPaolo Bonzini /* Stop SCRIPTS execution and raise a DMA interrupt.  */
lsi_script_dma_interrupt(LSIState * s,int stat)56149ab747fSPaolo Bonzini static void lsi_script_dma_interrupt(LSIState *s, int stat)
56249ab747fSPaolo Bonzini {
563c921370bSMark Cave-Ayland     trace_lsi_script_dma_interrupt(stat, s->dstat);
56449ab747fSPaolo Bonzini     s->dstat |= stat;
56549ab747fSPaolo Bonzini     lsi_update_irq(s);
56649ab747fSPaolo Bonzini     lsi_stop_script(s);
56749ab747fSPaolo Bonzini }
56849ab747fSPaolo Bonzini 
lsi_set_phase(LSIState * s,int phase)56949ab747fSPaolo Bonzini static inline void lsi_set_phase(LSIState *s, int phase)
57049ab747fSPaolo Bonzini {
57112dd89f7SSven Schnelle     s->sbcl &= ~PHASE_MASK;
57212dd89f7SSven Schnelle     s->sbcl |= phase | LSI_SBCL_REQ;
57349ab747fSPaolo Bonzini     s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase;
57449ab747fSPaolo Bonzini }
57549ab747fSPaolo Bonzini 
lsi_bad_phase(LSIState * s,int out,int new_phase)576a9198b31SSven Schnelle static int lsi_bad_phase(LSIState *s, int out, int new_phase)
57749ab747fSPaolo Bonzini {
578a9198b31SSven Schnelle     int ret = 0;
57949ab747fSPaolo Bonzini     /* Trigger a phase mismatch.  */
58049ab747fSPaolo Bonzini     if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
58149ab747fSPaolo Bonzini         if ((s->ccntl0 & LSI_CCNTL0_PMJCTL)) {
58249ab747fSPaolo Bonzini             s->dsp = out ? s->pmjad1 : s->pmjad2;
58349ab747fSPaolo Bonzini         } else {
58449ab747fSPaolo Bonzini             s->dsp = (s->scntl2 & LSI_SCNTL2_WSR ? s->pmjad2 : s->pmjad1);
58549ab747fSPaolo Bonzini         }
586c921370bSMark Cave-Ayland         trace_lsi_bad_phase_jump(s->dsp);
58749ab747fSPaolo Bonzini     } else {
588c921370bSMark Cave-Ayland         trace_lsi_bad_phase_interrupt();
58949ab747fSPaolo Bonzini         lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
59049ab747fSPaolo Bonzini         lsi_stop_script(s);
591a9198b31SSven Schnelle         ret = 1;
59249ab747fSPaolo Bonzini     }
59349ab747fSPaolo Bonzini     lsi_set_phase(s, new_phase);
594a9198b31SSven Schnelle     return ret;
59549ab747fSPaolo Bonzini }
59649ab747fSPaolo Bonzini 
59749ab747fSPaolo Bonzini 
59849ab747fSPaolo Bonzini /* Resume SCRIPTS execution after a DMA operation.  */
lsi_resume_script(LSIState * s)59949ab747fSPaolo Bonzini static void lsi_resume_script(LSIState *s)
60049ab747fSPaolo Bonzini {
60149ab747fSPaolo Bonzini     if (s->waiting != 2) {
602f08ec2b8SSven Schnelle         s->waiting = LSI_NOWAIT;
60349ab747fSPaolo Bonzini         lsi_execute_script(s);
60449ab747fSPaolo Bonzini     } else {
605f08ec2b8SSven Schnelle         s->waiting = LSI_NOWAIT;
60649ab747fSPaolo Bonzini     }
60749ab747fSPaolo Bonzini }
60849ab747fSPaolo Bonzini 
lsi_disconnect(LSIState * s)60949ab747fSPaolo Bonzini static void lsi_disconnect(LSIState *s)
61049ab747fSPaolo Bonzini {
61149ab747fSPaolo Bonzini     s->scntl1 &= ~LSI_SCNTL1_CON;
61249ab747fSPaolo Bonzini     s->sstat1 &= ~PHASE_MASK;
61312dd89f7SSven Schnelle     s->sbcl = 0;
61449ab747fSPaolo Bonzini }
61549ab747fSPaolo Bonzini 
lsi_bad_selection(LSIState * s,uint32_t id)61649ab747fSPaolo Bonzini static void lsi_bad_selection(LSIState *s, uint32_t id)
61749ab747fSPaolo Bonzini {
618c921370bSMark Cave-Ayland     trace_lsi_bad_selection(id);
61949ab747fSPaolo Bonzini     lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
62049ab747fSPaolo Bonzini     lsi_disconnect(s);
62149ab747fSPaolo Bonzini }
62249ab747fSPaolo Bonzini 
62349ab747fSPaolo Bonzini /* Initiate a SCSI layer data transfer.  */
lsi_do_dma(LSIState * s,int out)62449ab747fSPaolo Bonzini static void lsi_do_dma(LSIState *s, int out)
62549ab747fSPaolo Bonzini {
62649ab747fSPaolo Bonzini     uint32_t count;
62749ab747fSPaolo Bonzini     dma_addr_t addr;
62849ab747fSPaolo Bonzini     SCSIDevice *dev;
62949ab747fSPaolo Bonzini 
6304051a1f0SPhilippe Mathieu-Daudé     if (!s->current || !s->current->dma_len) {
63149ab747fSPaolo Bonzini         /* Wait until data is available.  */
632c921370bSMark Cave-Ayland         trace_lsi_do_dma_unavailable();
63349ab747fSPaolo Bonzini         return;
63449ab747fSPaolo Bonzini     }
63549ab747fSPaolo Bonzini 
63649ab747fSPaolo Bonzini     dev = s->current->req->dev;
63749ab747fSPaolo Bonzini     assert(dev);
63849ab747fSPaolo Bonzini 
63949ab747fSPaolo Bonzini     count = s->dbc;
64049ab747fSPaolo Bonzini     if (count > s->current->dma_len)
64149ab747fSPaolo Bonzini         count = s->current->dma_len;
64249ab747fSPaolo Bonzini 
64349ab747fSPaolo Bonzini     addr = s->dnad;
64449ab747fSPaolo Bonzini     /* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
64549ab747fSPaolo Bonzini     if (lsi_dma_40bit(s) || lsi_dma_ti64bit(s))
64649ab747fSPaolo Bonzini         addr |= ((uint64_t)s->dnad64 << 32);
64749ab747fSPaolo Bonzini     else if (s->dbms)
64849ab747fSPaolo Bonzini         addr |= ((uint64_t)s->dbms << 32);
64949ab747fSPaolo Bonzini     else if (s->sbms)
65049ab747fSPaolo Bonzini         addr |= ((uint64_t)s->sbms << 32);
65149ab747fSPaolo Bonzini 
652c921370bSMark Cave-Ayland     trace_lsi_do_dma(addr, count);
65349ab747fSPaolo Bonzini     s->csbc += count;
65449ab747fSPaolo Bonzini     s->dnad += count;
65549ab747fSPaolo Bonzini     s->dbc -= count;
65649ab747fSPaolo Bonzini      if (s->current->dma_buf == NULL) {
65749ab747fSPaolo Bonzini         s->current->dma_buf = scsi_req_get_buf(s->current->req);
65849ab747fSPaolo Bonzini     }
65949ab747fSPaolo Bonzini     /* ??? Set SFBR to first data byte.  */
66049ab747fSPaolo Bonzini     if (out) {
661a8632434SHervé Poussineau         lsi_mem_read(s, addr, s->current->dma_buf, count);
66249ab747fSPaolo Bonzini     } else {
663a8632434SHervé Poussineau         lsi_mem_write(s, addr, s->current->dma_buf, count);
66449ab747fSPaolo Bonzini     }
66549ab747fSPaolo Bonzini     s->current->dma_len -= count;
66649ab747fSPaolo Bonzini     if (s->current->dma_len == 0) {
66749ab747fSPaolo Bonzini         s->current->dma_buf = NULL;
66849ab747fSPaolo Bonzini         scsi_req_continue(s->current->req);
66949ab747fSPaolo Bonzini     } else {
67049ab747fSPaolo Bonzini         s->current->dma_buf += count;
67149ab747fSPaolo Bonzini         lsi_resume_script(s);
67249ab747fSPaolo Bonzini     }
67349ab747fSPaolo Bonzini }
67449ab747fSPaolo Bonzini 
67549ab747fSPaolo Bonzini 
67649ab747fSPaolo Bonzini /* Add a command to the queue.  */
lsi_queue_command(LSIState * s)67749ab747fSPaolo Bonzini static void lsi_queue_command(LSIState *s)
67849ab747fSPaolo Bonzini {
67949ab747fSPaolo Bonzini     lsi_request *p = s->current;
68049ab747fSPaolo Bonzini 
681c921370bSMark Cave-Ayland     trace_lsi_queue_command(p->tag);
68249ab747fSPaolo Bonzini     assert(s->current != NULL);
68349ab747fSPaolo Bonzini     assert(s->current->dma_len == 0);
68449ab747fSPaolo Bonzini     QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
68549ab747fSPaolo Bonzini     s->current = NULL;
68649ab747fSPaolo Bonzini 
68749ab747fSPaolo Bonzini     p->pending = 0;
68849ab747fSPaolo Bonzini     p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
68949ab747fSPaolo Bonzini }
69049ab747fSPaolo Bonzini 
69149ab747fSPaolo Bonzini /* Queue a byte for a MSG IN phase.  */
lsi_add_msg_byte(LSIState * s,uint8_t data)69249ab747fSPaolo Bonzini static void lsi_add_msg_byte(LSIState *s, uint8_t data)
69349ab747fSPaolo Bonzini {
69449ab747fSPaolo Bonzini     if (s->msg_len >= LSI_MAX_MSGIN_LEN) {
695c921370bSMark Cave-Ayland         trace_lsi_add_msg_byte_error();
69649ab747fSPaolo Bonzini     } else {
697c921370bSMark Cave-Ayland         trace_lsi_add_msg_byte(data);
69849ab747fSPaolo Bonzini         s->msg[s->msg_len++] = data;
69949ab747fSPaolo Bonzini     }
70049ab747fSPaolo Bonzini }
70149ab747fSPaolo Bonzini 
70249ab747fSPaolo Bonzini /* Perform reselection to continue a command.  */
lsi_reselect(LSIState * s,lsi_request * p)70349ab747fSPaolo Bonzini static void lsi_reselect(LSIState *s, lsi_request *p)
70449ab747fSPaolo Bonzini {
70549ab747fSPaolo Bonzini     int id;
70649ab747fSPaolo Bonzini 
70749ab747fSPaolo Bonzini     assert(s->current == NULL);
70849ab747fSPaolo Bonzini     QTAILQ_REMOVE(&s->queue, p, next);
70949ab747fSPaolo Bonzini     s->current = p;
71049ab747fSPaolo Bonzini 
71149ab747fSPaolo Bonzini     id = (p->tag >> 8) & 0xf;
71249ab747fSPaolo Bonzini     s->ssid = id | 0x80;
71349ab747fSPaolo Bonzini     /* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
71449ab747fSPaolo Bonzini     if (!(s->dcntl & LSI_DCNTL_COM)) {
71549ab747fSPaolo Bonzini         s->sfbr = 1 << (id & 0x7);
71649ab747fSPaolo Bonzini     }
717c921370bSMark Cave-Ayland     trace_lsi_reselect(id);
71849ab747fSPaolo Bonzini     s->scntl1 |= LSI_SCNTL1_CON;
71949ab747fSPaolo Bonzini     lsi_set_phase(s, PHASE_MI);
7204ae63d37SSven Schnelle     s->msg_action = p->out ? LSI_MSG_ACTION_DOUT : LSI_MSG_ACTION_DIN;
72149ab747fSPaolo Bonzini     s->current->dma_len = p->pending;
72249ab747fSPaolo Bonzini     lsi_add_msg_byte(s, 0x80);
72349ab747fSPaolo Bonzini     if (s->current->tag & LSI_TAG_VALID) {
72449ab747fSPaolo Bonzini         lsi_add_msg_byte(s, 0x20);
72549ab747fSPaolo Bonzini         lsi_add_msg_byte(s, p->tag & 0xff);
72649ab747fSPaolo Bonzini     }
72749ab747fSPaolo Bonzini 
72849ab747fSPaolo Bonzini     if (lsi_irq_on_rsl(s)) {
72949ab747fSPaolo Bonzini         lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0);
73049ab747fSPaolo Bonzini     }
73149ab747fSPaolo Bonzini }
73249ab747fSPaolo Bonzini 
lsi_find_by_tag(LSIState * s,uint32_t tag)73349ab747fSPaolo Bonzini static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
73449ab747fSPaolo Bonzini {
73549ab747fSPaolo Bonzini     lsi_request *p;
73649ab747fSPaolo Bonzini 
73749ab747fSPaolo Bonzini     QTAILQ_FOREACH(p, &s->queue, next) {
73849ab747fSPaolo Bonzini         if (p->tag == tag) {
73949ab747fSPaolo Bonzini             return p;
74049ab747fSPaolo Bonzini         }
74149ab747fSPaolo Bonzini     }
74249ab747fSPaolo Bonzini 
74349ab747fSPaolo Bonzini     return NULL;
74449ab747fSPaolo Bonzini }
74549ab747fSPaolo Bonzini 
lsi_request_free(LSIState * s,lsi_request * p)74649ab747fSPaolo Bonzini static void lsi_request_free(LSIState *s, lsi_request *p)
74749ab747fSPaolo Bonzini {
74849ab747fSPaolo Bonzini     if (p == s->current) {
74949ab747fSPaolo Bonzini         s->current = NULL;
75049ab747fSPaolo Bonzini     } else {
75149ab747fSPaolo Bonzini         QTAILQ_REMOVE(&s->queue, p, next);
75249ab747fSPaolo Bonzini     }
75349ab747fSPaolo Bonzini     g_free(p);
75449ab747fSPaolo Bonzini }
75549ab747fSPaolo Bonzini 
lsi_request_cancelled(SCSIRequest * req)75649ab747fSPaolo Bonzini static void lsi_request_cancelled(SCSIRequest *req)
75749ab747fSPaolo Bonzini {
75871186c86SPeter Crosthwaite     LSIState *s = LSI53C895A(req->bus->qbus.parent);
75949ab747fSPaolo Bonzini     lsi_request *p = req->hba_private;
76049ab747fSPaolo Bonzini 
76149ab747fSPaolo Bonzini     req->hba_private = NULL;
76249ab747fSPaolo Bonzini     lsi_request_free(s, p);
76349ab747fSPaolo Bonzini     scsi_req_unref(req);
76449ab747fSPaolo Bonzini }
76549ab747fSPaolo Bonzini 
76649ab747fSPaolo Bonzini /* Record that data is available for a queued command.  Returns zero if
76749ab747fSPaolo Bonzini    the device was reselected, nonzero if the IO is deferred.  */
lsi_queue_req(LSIState * s,SCSIRequest * req,uint32_t len)76849ab747fSPaolo Bonzini static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
76949ab747fSPaolo Bonzini {
77049ab747fSPaolo Bonzini     lsi_request *p = req->hba_private;
77149ab747fSPaolo Bonzini 
77249ab747fSPaolo Bonzini     if (p->pending) {
773c921370bSMark Cave-Ayland         trace_lsi_queue_req_error(p);
77449ab747fSPaolo Bonzini     }
77549ab747fSPaolo Bonzini     p->pending = len;
77649ab747fSPaolo Bonzini     /* Reselect if waiting for it, or if reselection triggers an IRQ
77749ab747fSPaolo Bonzini        and the bus is free.
77849ab747fSPaolo Bonzini        Since no interrupt stacking is implemented in the emulation, it
77949ab747fSPaolo Bonzini        is also required that there are no pending interrupts waiting
78049ab747fSPaolo Bonzini        for service from the device driver. */
781f08ec2b8SSven Schnelle     if (s->waiting == LSI_WAIT_RESELECT ||
78249ab747fSPaolo Bonzini         (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
78349ab747fSPaolo Bonzini          !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
78449ab747fSPaolo Bonzini         /* Reselect device.  */
78549ab747fSPaolo Bonzini         lsi_reselect(s, p);
78649ab747fSPaolo Bonzini         return 0;
78749ab747fSPaolo Bonzini     } else {
788c921370bSMark Cave-Ayland         trace_lsi_queue_req(p->tag);
78949ab747fSPaolo Bonzini         p->pending = len;
79049ab747fSPaolo Bonzini         return 1;
79149ab747fSPaolo Bonzini     }
79249ab747fSPaolo Bonzini }
79349ab747fSPaolo Bonzini 
79449ab747fSPaolo Bonzini  /* Callback to indicate that the SCSI layer has completed a command.  */
lsi_command_complete(SCSIRequest * req,size_t resid)79517ea26c2SHannes Reinecke static void lsi_command_complete(SCSIRequest *req, size_t resid)
79649ab747fSPaolo Bonzini {
79771186c86SPeter Crosthwaite     LSIState *s = LSI53C895A(req->bus->qbus.parent);
798a9198b31SSven Schnelle     int out, stop = 0;
79949ab747fSPaolo Bonzini 
80049ab747fSPaolo Bonzini     out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
80117ea26c2SHannes Reinecke     trace_lsi_command_complete(req->status);
80217ea26c2SHannes Reinecke     s->status = req->status;
80349ab747fSPaolo Bonzini     s->command_complete = 2;
80449ab747fSPaolo Bonzini     if (s->waiting && s->dbc != 0) {
80549ab747fSPaolo Bonzini         /* Raise phase mismatch for short transfers.  */
806a9198b31SSven Schnelle         stop = lsi_bad_phase(s, out, PHASE_ST);
807a9198b31SSven Schnelle         if (stop) {
808a9198b31SSven Schnelle             s->waiting = 0;
809a9198b31SSven Schnelle         }
81049ab747fSPaolo Bonzini     } else {
81149ab747fSPaolo Bonzini         lsi_set_phase(s, PHASE_ST);
81249ab747fSPaolo Bonzini     }
81349ab747fSPaolo Bonzini 
81449ab747fSPaolo Bonzini     if (req->hba_private == s->current) {
81549ab747fSPaolo Bonzini         req->hba_private = NULL;
81649ab747fSPaolo Bonzini         lsi_request_free(s, s->current);
81749ab747fSPaolo Bonzini         scsi_req_unref(req);
81849ab747fSPaolo Bonzini     }
819a9198b31SSven Schnelle     if (!stop) {
82049ab747fSPaolo Bonzini         lsi_resume_script(s);
82149ab747fSPaolo Bonzini     }
822a9198b31SSven Schnelle }
82349ab747fSPaolo Bonzini 
82449ab747fSPaolo Bonzini  /* Callback to indicate that the SCSI layer has completed a transfer.  */
lsi_transfer_data(SCSIRequest * req,uint32_t len)82549ab747fSPaolo Bonzini static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
82649ab747fSPaolo Bonzini {
82771186c86SPeter Crosthwaite     LSIState *s = LSI53C895A(req->bus->qbus.parent);
82849ab747fSPaolo Bonzini     int out;
82949ab747fSPaolo Bonzini 
83049ab747fSPaolo Bonzini     assert(req->hba_private);
831f08ec2b8SSven Schnelle     if (s->waiting == LSI_WAIT_RESELECT || req->hba_private != s->current ||
83249ab747fSPaolo Bonzini         (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
83349ab747fSPaolo Bonzini         if (lsi_queue_req(s, req, len)) {
83449ab747fSPaolo Bonzini             return;
83549ab747fSPaolo Bonzini         }
83649ab747fSPaolo Bonzini     }
83749ab747fSPaolo Bonzini 
83849ab747fSPaolo Bonzini     out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
83949ab747fSPaolo Bonzini 
84049ab747fSPaolo Bonzini     /* host adapter (re)connected */
841c921370bSMark Cave-Ayland     trace_lsi_transfer_data(req->tag, len);
84249ab747fSPaolo Bonzini     s->current->dma_len = len;
84349ab747fSPaolo Bonzini     s->command_complete = 1;
84449ab747fSPaolo Bonzini     if (s->waiting) {
845f08ec2b8SSven Schnelle         if (s->waiting == LSI_WAIT_RESELECT || s->dbc == 0) {
84649ab747fSPaolo Bonzini             lsi_resume_script(s);
84749ab747fSPaolo Bonzini         } else {
84849ab747fSPaolo Bonzini             lsi_do_dma(s, out);
84949ab747fSPaolo Bonzini         }
85049ab747fSPaolo Bonzini     }
85149ab747fSPaolo Bonzini }
85249ab747fSPaolo Bonzini 
lsi_do_command(LSIState * s)85349ab747fSPaolo Bonzini static void lsi_do_command(LSIState *s)
85449ab747fSPaolo Bonzini {
85549ab747fSPaolo Bonzini     SCSIDevice *dev;
85649ab747fSPaolo Bonzini     uint8_t buf[16];
85749ab747fSPaolo Bonzini     uint32_t id;
85849ab747fSPaolo Bonzini     int n;
85949ab747fSPaolo Bonzini 
860c921370bSMark Cave-Ayland     trace_lsi_do_command(s->dbc);
86149ab747fSPaolo Bonzini     if (s->dbc > 16)
86249ab747fSPaolo Bonzini         s->dbc = 16;
863725eec70SAndreas Färber     pci_dma_read(PCI_DEVICE(s), s->dnad, buf, s->dbc);
86449ab747fSPaolo Bonzini     s->sfbr = buf[0];
86549ab747fSPaolo Bonzini     s->command_complete = 0;
86649ab747fSPaolo Bonzini 
86749ab747fSPaolo Bonzini     id = (s->select_tag >> 8) & 0xf;
86849ab747fSPaolo Bonzini     dev = scsi_device_find(&s->bus, 0, id, s->current_lun);
86949ab747fSPaolo Bonzini     if (!dev) {
87049ab747fSPaolo Bonzini         lsi_bad_selection(s, id);
87149ab747fSPaolo Bonzini         return;
87249ab747fSPaolo Bonzini     }
87349ab747fSPaolo Bonzini 
87449ab747fSPaolo Bonzini     assert(s->current == NULL);
8753c55fe2aSMarkus Armbruster     s->current = g_new0(lsi_request, 1);
87649ab747fSPaolo Bonzini     s->current->tag = s->select_tag;
87749ab747fSPaolo Bonzini     s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun, buf,
878fe9d8927SJohn Millikin                                    s->dbc, s->current);
87949ab747fSPaolo Bonzini 
88049ab747fSPaolo Bonzini     n = scsi_req_enqueue(s->current->req);
88149ab747fSPaolo Bonzini     if (n) {
88249ab747fSPaolo Bonzini         if (n > 0) {
88349ab747fSPaolo Bonzini             lsi_set_phase(s, PHASE_DI);
88449ab747fSPaolo Bonzini         } else if (n < 0) {
88549ab747fSPaolo Bonzini             lsi_set_phase(s, PHASE_DO);
88649ab747fSPaolo Bonzini         }
88749ab747fSPaolo Bonzini         scsi_req_continue(s->current->req);
88849ab747fSPaolo Bonzini     }
88949ab747fSPaolo Bonzini     if (!s->command_complete) {
89049ab747fSPaolo Bonzini         if (n) {
89149ab747fSPaolo Bonzini             /* Command did not complete immediately so disconnect.  */
89249ab747fSPaolo Bonzini             lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
89349ab747fSPaolo Bonzini             lsi_add_msg_byte(s, 4); /* DISCONNECT */
89449ab747fSPaolo Bonzini             /* wait data */
89549ab747fSPaolo Bonzini             lsi_set_phase(s, PHASE_MI);
8964ae63d37SSven Schnelle             s->msg_action = LSI_MSG_ACTION_DISCONNECT;
89749ab747fSPaolo Bonzini             lsi_queue_command(s);
89849ab747fSPaolo Bonzini         } else {
89949ab747fSPaolo Bonzini             /* wait command complete */
90049ab747fSPaolo Bonzini             lsi_set_phase(s, PHASE_DI);
90149ab747fSPaolo Bonzini         }
90249ab747fSPaolo Bonzini     }
90349ab747fSPaolo Bonzini }
90449ab747fSPaolo Bonzini 
lsi_do_status(LSIState * s)90549ab747fSPaolo Bonzini static void lsi_do_status(LSIState *s)
90649ab747fSPaolo Bonzini {
90749ab747fSPaolo Bonzini     uint8_t status;
908c921370bSMark Cave-Ayland     trace_lsi_do_status(s->dbc, s->status);
909c921370bSMark Cave-Ayland     if (s->dbc != 1) {
910c921370bSMark Cave-Ayland         trace_lsi_do_status_error();
911c921370bSMark Cave-Ayland     }
91249ab747fSPaolo Bonzini     s->dbc = 1;
91349ab747fSPaolo Bonzini     status = s->status;
91449ab747fSPaolo Bonzini     s->sfbr = status;
915725eec70SAndreas Färber     pci_dma_write(PCI_DEVICE(s), s->dnad, &status, 1);
91649ab747fSPaolo Bonzini     lsi_set_phase(s, PHASE_MI);
9174ae63d37SSven Schnelle     s->msg_action = LSI_MSG_ACTION_DISCONNECT;
91849ab747fSPaolo Bonzini     lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
91949ab747fSPaolo Bonzini }
92049ab747fSPaolo Bonzini 
lsi_do_msgin(LSIState * s)92149ab747fSPaolo Bonzini static void lsi_do_msgin(LSIState *s)
92249ab747fSPaolo Bonzini {
923e58ccf03SPrasad J Pandit     uint8_t len;
924c921370bSMark Cave-Ayland     trace_lsi_do_msgin(s->dbc, s->msg_len);
92549ab747fSPaolo Bonzini     s->sfbr = s->msg[0];
92649ab747fSPaolo Bonzini     len = s->msg_len;
927e58ccf03SPrasad J Pandit     assert(len > 0 && len <= LSI_MAX_MSGIN_LEN);
92849ab747fSPaolo Bonzini     if (len > s->dbc)
92949ab747fSPaolo Bonzini         len = s->dbc;
930e497e6a5SPaolo Bonzini 
931e497e6a5SPaolo Bonzini     if (len) {
932725eec70SAndreas Färber         pci_dma_write(PCI_DEVICE(s), s->dnad, s->msg, len);
93349ab747fSPaolo Bonzini         /* Linux drivers rely on the last byte being in the SIDL.  */
93449ab747fSPaolo Bonzini         s->sidl = s->msg[len - 1];
93549ab747fSPaolo Bonzini         s->msg_len -= len;
93649ab747fSPaolo Bonzini         if (s->msg_len) {
93749ab747fSPaolo Bonzini             memmove(s->msg, s->msg + len, s->msg_len);
938e497e6a5SPaolo Bonzini         }
939e497e6a5SPaolo Bonzini     }
940e497e6a5SPaolo Bonzini 
941e497e6a5SPaolo Bonzini     if (!s->msg_len) {
94249ab747fSPaolo Bonzini         /* ??? Check if ATN (not yet implemented) is asserted and maybe
94349ab747fSPaolo Bonzini            switch to PHASE_MO.  */
94449ab747fSPaolo Bonzini         switch (s->msg_action) {
9454ae63d37SSven Schnelle         case LSI_MSG_ACTION_COMMAND:
94649ab747fSPaolo Bonzini             lsi_set_phase(s, PHASE_CMD);
94749ab747fSPaolo Bonzini             break;
9484ae63d37SSven Schnelle         case LSI_MSG_ACTION_DISCONNECT:
94949ab747fSPaolo Bonzini             lsi_disconnect(s);
95049ab747fSPaolo Bonzini             break;
9514ae63d37SSven Schnelle         case LSI_MSG_ACTION_DOUT:
95249ab747fSPaolo Bonzini             lsi_set_phase(s, PHASE_DO);
95349ab747fSPaolo Bonzini             break;
9544ae63d37SSven Schnelle         case LSI_MSG_ACTION_DIN:
95549ab747fSPaolo Bonzini             lsi_set_phase(s, PHASE_DI);
95649ab747fSPaolo Bonzini             break;
95749ab747fSPaolo Bonzini         default:
95849ab747fSPaolo Bonzini             abort();
95949ab747fSPaolo Bonzini         }
96049ab747fSPaolo Bonzini     }
96149ab747fSPaolo Bonzini }
96249ab747fSPaolo Bonzini 
96349ab747fSPaolo Bonzini /* Read the next byte during a MSGOUT phase.  */
lsi_get_msgbyte(LSIState * s)96449ab747fSPaolo Bonzini static uint8_t lsi_get_msgbyte(LSIState *s)
96549ab747fSPaolo Bonzini {
96649ab747fSPaolo Bonzini     uint8_t data;
967725eec70SAndreas Färber     pci_dma_read(PCI_DEVICE(s), s->dnad, &data, 1);
96849ab747fSPaolo Bonzini     s->dnad++;
96949ab747fSPaolo Bonzini     s->dbc--;
97049ab747fSPaolo Bonzini     return data;
97149ab747fSPaolo Bonzini }
97249ab747fSPaolo Bonzini 
97349ab747fSPaolo Bonzini /* Skip the next n bytes during a MSGOUT phase. */
lsi_skip_msgbytes(LSIState * s,unsigned int n)97449ab747fSPaolo Bonzini static void lsi_skip_msgbytes(LSIState *s, unsigned int n)
97549ab747fSPaolo Bonzini {
97649ab747fSPaolo Bonzini     s->dnad += n;
97749ab747fSPaolo Bonzini     s->dbc  -= n;
97849ab747fSPaolo Bonzini }
97949ab747fSPaolo Bonzini 
lsi_do_msgout(LSIState * s)98049ab747fSPaolo Bonzini static void lsi_do_msgout(LSIState *s)
98149ab747fSPaolo Bonzini {
98249ab747fSPaolo Bonzini     uint8_t msg;
98349ab747fSPaolo Bonzini     int len;
98449ab747fSPaolo Bonzini     uint32_t current_tag;
98549ab747fSPaolo Bonzini     lsi_request *current_req, *p, *p_next;
98649ab747fSPaolo Bonzini 
98749ab747fSPaolo Bonzini     if (s->current) {
98849ab747fSPaolo Bonzini         current_tag = s->current->tag;
98949ab747fSPaolo Bonzini         current_req = s->current;
99049ab747fSPaolo Bonzini     } else {
99149ab747fSPaolo Bonzini         current_tag = s->select_tag;
99249ab747fSPaolo Bonzini         current_req = lsi_find_by_tag(s, current_tag);
99349ab747fSPaolo Bonzini     }
99449ab747fSPaolo Bonzini 
995c921370bSMark Cave-Ayland     trace_lsi_do_msgout(s->dbc);
99649ab747fSPaolo Bonzini     while (s->dbc) {
99749ab747fSPaolo Bonzini         msg = lsi_get_msgbyte(s);
99849ab747fSPaolo Bonzini         s->sfbr = msg;
99949ab747fSPaolo Bonzini 
100049ab747fSPaolo Bonzini         switch (msg) {
100149ab747fSPaolo Bonzini         case 0x04:
1002c921370bSMark Cave-Ayland             trace_lsi_do_msgout_disconnect();
100349ab747fSPaolo Bonzini             lsi_disconnect(s);
100449ab747fSPaolo Bonzini             break;
100549ab747fSPaolo Bonzini         case 0x08:
1006c921370bSMark Cave-Ayland             trace_lsi_do_msgout_noop();
100749ab747fSPaolo Bonzini             lsi_set_phase(s, PHASE_CMD);
100849ab747fSPaolo Bonzini             break;
100949ab747fSPaolo Bonzini         case 0x01:
101049ab747fSPaolo Bonzini             len = lsi_get_msgbyte(s);
101149ab747fSPaolo Bonzini             msg = lsi_get_msgbyte(s);
101249ab747fSPaolo Bonzini             (void)len; /* avoid a warning about unused variable*/
1013c921370bSMark Cave-Ayland             trace_lsi_do_msgout_extended(msg, len);
101449ab747fSPaolo Bonzini             switch (msg) {
101549ab747fSPaolo Bonzini             case 1:
1016c921370bSMark Cave-Ayland                 trace_lsi_do_msgout_ignored("SDTR");
101749ab747fSPaolo Bonzini                 lsi_skip_msgbytes(s, 2);
101849ab747fSPaolo Bonzini                 break;
101949ab747fSPaolo Bonzini             case 3:
1020c921370bSMark Cave-Ayland                 trace_lsi_do_msgout_ignored("WDTR");
102149ab747fSPaolo Bonzini                 lsi_skip_msgbytes(s, 1);
102249ab747fSPaolo Bonzini                 break;
1023966a09faSGeorge Kennedy             case 4:
1024c921370bSMark Cave-Ayland                 trace_lsi_do_msgout_ignored("PPR");
1025966a09faSGeorge Kennedy                 lsi_skip_msgbytes(s, 5);
1026966a09faSGeorge Kennedy                 break;
102749ab747fSPaolo Bonzini             default:
102849ab747fSPaolo Bonzini                 goto bad;
102949ab747fSPaolo Bonzini             }
103049ab747fSPaolo Bonzini             break;
103149ab747fSPaolo Bonzini         case 0x20: /* SIMPLE queue */
103249ab747fSPaolo Bonzini             s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
1033c921370bSMark Cave-Ayland             trace_lsi_do_msgout_simplequeue(s->select_tag & 0xff);
103449ab747fSPaolo Bonzini             break;
103549ab747fSPaolo Bonzini         case 0x21: /* HEAD of queue */
1036c921370bSMark Cave-Ayland             qemu_log_mask(LOG_UNIMP, "lsi_scsi: HEAD queue not implemented\n");
103749ab747fSPaolo Bonzini             s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
103849ab747fSPaolo Bonzini             break;
103949ab747fSPaolo Bonzini         case 0x22: /* ORDERED queue */
1040c921370bSMark Cave-Ayland             qemu_log_mask(LOG_UNIMP,
1041c921370bSMark Cave-Ayland                           "lsi_scsi: ORDERED queue not implemented\n");
104249ab747fSPaolo Bonzini             s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
104349ab747fSPaolo Bonzini             break;
104449ab747fSPaolo Bonzini         case 0x0d:
104549ab747fSPaolo Bonzini             /* The ABORT TAG message clears the current I/O process only. */
1046c921370bSMark Cave-Ayland             trace_lsi_do_msgout_abort(current_tag);
10476c8fa961SMauro Matteo Cascella             if (current_req && current_req->req) {
104849ab747fSPaolo Bonzini                 scsi_req_cancel(current_req->req);
10494367a20cSMauro Matteo Cascella                 current_req = NULL;
105049ab747fSPaolo Bonzini             }
105149ab747fSPaolo Bonzini             lsi_disconnect(s);
105249ab747fSPaolo Bonzini             break;
105349ab747fSPaolo Bonzini         case 0x06:
105449ab747fSPaolo Bonzini         case 0x0e:
105549ab747fSPaolo Bonzini         case 0x0c:
105649ab747fSPaolo Bonzini             /* The ABORT message clears all I/O processes for the selecting
105749ab747fSPaolo Bonzini                initiator on the specified logical unit of the target. */
105849ab747fSPaolo Bonzini             if (msg == 0x06) {
1059c921370bSMark Cave-Ayland                 trace_lsi_do_msgout_abort(current_tag);
106049ab747fSPaolo Bonzini             }
106149ab747fSPaolo Bonzini             /* The CLEAR QUEUE message clears all I/O processes for all
106249ab747fSPaolo Bonzini                initiators on the specified logical unit of the target. */
106349ab747fSPaolo Bonzini             if (msg == 0x0e) {
1064c921370bSMark Cave-Ayland                 trace_lsi_do_msgout_clearqueue(current_tag);
106549ab747fSPaolo Bonzini             }
106649ab747fSPaolo Bonzini             /* The BUS DEVICE RESET message clears all I/O processes for all
106749ab747fSPaolo Bonzini                initiators on all logical units of the target. */
106849ab747fSPaolo Bonzini             if (msg == 0x0c) {
1069c921370bSMark Cave-Ayland                 trace_lsi_do_msgout_busdevicereset(current_tag);
107049ab747fSPaolo Bonzini             }
107149ab747fSPaolo Bonzini 
107249ab747fSPaolo Bonzini             /* clear the current I/O process */
107349ab747fSPaolo Bonzini             if (s->current) {
107449ab747fSPaolo Bonzini                 scsi_req_cancel(s->current->req);
10754367a20cSMauro Matteo Cascella                 current_req = NULL;
107649ab747fSPaolo Bonzini             }
107749ab747fSPaolo Bonzini 
107849ab747fSPaolo Bonzini             /* As the current implemented devices scsi_disk and scsi_generic
107949ab747fSPaolo Bonzini                only support one LUN, we don't need to keep track of LUNs.
108049ab747fSPaolo Bonzini                Clearing I/O processes for other initiators could be possible
108149ab747fSPaolo Bonzini                for scsi_generic by sending a SG_SCSI_RESET to the /dev/sgX
108249ab747fSPaolo Bonzini                device, but this is currently not implemented (and seems not
108349ab747fSPaolo Bonzini                to be really necessary). So let's simply clear all queued
108449ab747fSPaolo Bonzini                commands for the current device: */
108549ab747fSPaolo Bonzini             QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
108649ab747fSPaolo Bonzini                 if ((p->tag & 0x0000ff00) == (current_tag & 0x0000ff00)) {
108749ab747fSPaolo Bonzini                     scsi_req_cancel(p->req);
108849ab747fSPaolo Bonzini                 }
108949ab747fSPaolo Bonzini             }
109049ab747fSPaolo Bonzini 
109149ab747fSPaolo Bonzini             lsi_disconnect(s);
109249ab747fSPaolo Bonzini             break;
109349ab747fSPaolo Bonzini         default:
109449ab747fSPaolo Bonzini             if ((msg & 0x80) == 0) {
109549ab747fSPaolo Bonzini                 goto bad;
109649ab747fSPaolo Bonzini             }
109749ab747fSPaolo Bonzini             s->current_lun = msg & 7;
1098c921370bSMark Cave-Ayland             trace_lsi_do_msgout_select(s->current_lun);
109949ab747fSPaolo Bonzini             lsi_set_phase(s, PHASE_CMD);
110049ab747fSPaolo Bonzini             break;
110149ab747fSPaolo Bonzini         }
110249ab747fSPaolo Bonzini     }
110349ab747fSPaolo Bonzini     return;
110449ab747fSPaolo Bonzini bad:
1105c921370bSMark Cave-Ayland     qemu_log_mask(LOG_UNIMP, "Unimplemented message 0x%02x\n", msg);
110649ab747fSPaolo Bonzini     lsi_set_phase(s, PHASE_MI);
110749ab747fSPaolo Bonzini     lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */
11084ae63d37SSven Schnelle     s->msg_action = LSI_MSG_ACTION_COMMAND;
110949ab747fSPaolo Bonzini }
111049ab747fSPaolo Bonzini 
111149ab747fSPaolo Bonzini #define LSI_BUF_SIZE 4096
lsi_memcpy(LSIState * s,uint32_t dest,uint32_t src,int count)111249ab747fSPaolo Bonzini static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
111349ab747fSPaolo Bonzini {
111449ab747fSPaolo Bonzini     int n;
111549ab747fSPaolo Bonzini     uint8_t buf[LSI_BUF_SIZE];
111649ab747fSPaolo Bonzini 
1117c921370bSMark Cave-Ayland     trace_lsi_memcpy(dest, src, count);
111849ab747fSPaolo Bonzini     while (count) {
111949ab747fSPaolo Bonzini         n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count;
1120a8632434SHervé Poussineau         lsi_mem_read(s, src, buf, n);
1121a8632434SHervé Poussineau         lsi_mem_write(s, dest, buf, n);
112249ab747fSPaolo Bonzini         src += n;
112349ab747fSPaolo Bonzini         dest += n;
112449ab747fSPaolo Bonzini         count -= n;
112549ab747fSPaolo Bonzini     }
112649ab747fSPaolo Bonzini }
112749ab747fSPaolo Bonzini 
lsi_wait_reselect(LSIState * s)112849ab747fSPaolo Bonzini static void lsi_wait_reselect(LSIState *s)
112949ab747fSPaolo Bonzini {
113049ab747fSPaolo Bonzini     lsi_request *p;
113149ab747fSPaolo Bonzini 
1132c921370bSMark Cave-Ayland     trace_lsi_wait_reselect();
113349ab747fSPaolo Bonzini 
113456333e69SGeorge Kennedy     if (s->current) {
113556333e69SGeorge Kennedy         return;
113649ab747fSPaolo Bonzini     }
113756333e69SGeorge Kennedy     p = get_pending_req(s);
113856333e69SGeorge Kennedy     if (p) {
113956333e69SGeorge Kennedy         lsi_reselect(s, p);
114049ab747fSPaolo Bonzini     }
114149ab747fSPaolo Bonzini     if (s->current == NULL) {
1142f08ec2b8SSven Schnelle         s->waiting = LSI_WAIT_RESELECT;
114349ab747fSPaolo Bonzini     }
114449ab747fSPaolo Bonzini }
114549ab747fSPaolo Bonzini 
lsi_scripts_timer_start(LSIState * s)114698763599SSven Schnelle static void lsi_scripts_timer_start(LSIState *s)
114798763599SSven Schnelle {
114898763599SSven Schnelle     trace_lsi_scripts_timer_start();
114998763599SSven Schnelle     timer_mod(s->scripts_timer, qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + 500);
115098763599SSven Schnelle }
115198763599SSven Schnelle 
lsi_execute_script(LSIState * s)115249ab747fSPaolo Bonzini static void lsi_execute_script(LSIState *s)
115349ab747fSPaolo Bonzini {
1154725eec70SAndreas Färber     PCIDevice *pci_dev = PCI_DEVICE(s);
115549ab747fSPaolo Bonzini     uint32_t insn;
115649ab747fSPaolo Bonzini     uint32_t addr, addr_high;
115749ab747fSPaolo Bonzini     int opcode;
115849ab747fSPaolo Bonzini     int insn_processed = 0;
1159b987718bSThomas Huth     static int reentrancy_level;
1160b987718bSThomas Huth 
116198763599SSven Schnelle     if (s->waiting == LSI_WAIT_SCRIPTS) {
116298763599SSven Schnelle         timer_del(s->scripts_timer);
116398763599SSven Schnelle         s->waiting = LSI_NOWAIT;
116498763599SSven Schnelle     }
116598763599SSven Schnelle 
1166b987718bSThomas Huth     reentrancy_level++;
116749ab747fSPaolo Bonzini 
116849ab747fSPaolo Bonzini     s->istat1 |= LSI_ISTAT1_SRUN;
116949ab747fSPaolo Bonzini again:
1170b987718bSThomas Huth     /*
1171b987718bSThomas Huth      * Some windows drivers make the device spin waiting for a memory location
1172b987718bSThomas Huth      * to change. If we have executed more than LSI_MAX_INSN instructions then
117398763599SSven Schnelle      * assume this is the case and start a timer. Until the timer fires, the
117498763599SSven Schnelle      * host CPU has a chance to run and change the memory location.
1175b987718bSThomas Huth      *
1176b987718bSThomas Huth      * Another issue (CVE-2023-0330) can occur if the script is programmed to
1177b987718bSThomas Huth      * trigger itself again and again. Avoid this problem by stopping after
1178b987718bSThomas Huth      * being called multiple times in a reentrant way (8 is an arbitrary value
1179b987718bSThomas Huth      * which should be enough for all valid use cases).
1180de594e47SPaolo Bonzini      */
1181b987718bSThomas Huth     if (++insn_processed > LSI_MAX_INSN || reentrancy_level > 8) {
118298763599SSven Schnelle         s->waiting = LSI_WAIT_SCRIPTS;
118398763599SSven Schnelle         lsi_scripts_timer_start(s);
11848b09b7feSSven Schnelle         reentrancy_level--;
1185de594e47SPaolo Bonzini         return;
1186de594e47SPaolo Bonzini     }
118749ab747fSPaolo Bonzini     insn = read_dword(s, s->dsp);
118849ab747fSPaolo Bonzini     if (!insn) {
118949ab747fSPaolo Bonzini         /* If we receive an empty opcode increment the DSP by 4 bytes
119049ab747fSPaolo Bonzini            instead of 8 and execute the next opcode at that location */
119149ab747fSPaolo Bonzini         s->dsp += 4;
119249ab747fSPaolo Bonzini         goto again;
119349ab747fSPaolo Bonzini     }
119449ab747fSPaolo Bonzini     addr = read_dword(s, s->dsp + 4);
119549ab747fSPaolo Bonzini     addr_high = 0;
1196c921370bSMark Cave-Ayland     trace_lsi_execute_script(s->dsp, insn, addr);
119749ab747fSPaolo Bonzini     s->dsps = addr;
119849ab747fSPaolo Bonzini     s->dcmd = insn >> 24;
119949ab747fSPaolo Bonzini     s->dsp += 8;
120049ab747fSPaolo Bonzini     switch (insn >> 30) {
120149ab747fSPaolo Bonzini     case 0: /* Block move.  */
120249ab747fSPaolo Bonzini         if (s->sist1 & LSI_SIST1_STO) {
1203c921370bSMark Cave-Ayland             trace_lsi_execute_script_blockmove_delayed();
120449ab747fSPaolo Bonzini             lsi_stop_script(s);
120549ab747fSPaolo Bonzini             break;
120649ab747fSPaolo Bonzini         }
120749ab747fSPaolo Bonzini         s->dbc = insn & 0xffffff;
120849ab747fSPaolo Bonzini         s->rbc = s->dbc;
120949ab747fSPaolo Bonzini         /* ??? Set ESA.  */
121049ab747fSPaolo Bonzini         s->ia = s->dsp - 8;
121149ab747fSPaolo Bonzini         if (insn & (1 << 29)) {
121249ab747fSPaolo Bonzini             /* Indirect addressing.  */
121349ab747fSPaolo Bonzini             addr = read_dword(s, addr);
121449ab747fSPaolo Bonzini         } else if (insn & (1 << 28)) {
121549ab747fSPaolo Bonzini             uint32_t buf[2];
121649ab747fSPaolo Bonzini             int32_t offset;
121749ab747fSPaolo Bonzini             /* Table indirect addressing.  */
121849ab747fSPaolo Bonzini 
121949ab747fSPaolo Bonzini             /* 32-bit Table indirect */
122092794105SPeter Maydell             offset = sextract32(addr, 0, 24);
1221725eec70SAndreas Färber             pci_dma_read(pci_dev, s->dsa + offset, buf, 8);
122249ab747fSPaolo Bonzini             /* byte count is stored in bits 0:23 only */
122349ab747fSPaolo Bonzini             s->dbc = cpu_to_le32(buf[0]) & 0xffffff;
122449ab747fSPaolo Bonzini             s->rbc = s->dbc;
122549ab747fSPaolo Bonzini             addr = cpu_to_le32(buf[1]);
122649ab747fSPaolo Bonzini 
122749ab747fSPaolo Bonzini             /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of
122849ab747fSPaolo Bonzini              * table, bits [31:24] */
122949ab747fSPaolo Bonzini             if (lsi_dma_40bit(s))
123049ab747fSPaolo Bonzini                 addr_high = cpu_to_le32(buf[0]) >> 24;
123149ab747fSPaolo Bonzini             else if (lsi_dma_ti64bit(s)) {
123249ab747fSPaolo Bonzini                 int selector = (cpu_to_le32(buf[0]) >> 24) & 0x1f;
123349ab747fSPaolo Bonzini                 switch (selector) {
123449ab747fSPaolo Bonzini                 case 0 ... 0x0f:
123549ab747fSPaolo Bonzini                     /* offset index into scratch registers since
123649ab747fSPaolo Bonzini                      * TI64 mode can use registers C to R */
123749ab747fSPaolo Bonzini                     addr_high = s->scratch[2 + selector];
123849ab747fSPaolo Bonzini                     break;
123949ab747fSPaolo Bonzini                 case 0x10:
124049ab747fSPaolo Bonzini                     addr_high = s->mmrs;
124149ab747fSPaolo Bonzini                     break;
124249ab747fSPaolo Bonzini                 case 0x11:
124349ab747fSPaolo Bonzini                     addr_high = s->mmws;
124449ab747fSPaolo Bonzini                     break;
124549ab747fSPaolo Bonzini                 case 0x12:
124649ab747fSPaolo Bonzini                     addr_high = s->sfs;
124749ab747fSPaolo Bonzini                     break;
124849ab747fSPaolo Bonzini                 case 0x13:
124949ab747fSPaolo Bonzini                     addr_high = s->drs;
125049ab747fSPaolo Bonzini                     break;
125149ab747fSPaolo Bonzini                 case 0x14:
125249ab747fSPaolo Bonzini                     addr_high = s->sbms;
125349ab747fSPaolo Bonzini                     break;
125449ab747fSPaolo Bonzini                 case 0x15:
125549ab747fSPaolo Bonzini                     addr_high = s->dbms;
125649ab747fSPaolo Bonzini                     break;
125749ab747fSPaolo Bonzini                 default:
1258c921370bSMark Cave-Ayland                     qemu_log_mask(LOG_GUEST_ERROR,
1259c921370bSMark Cave-Ayland                           "lsi_scsi: Illegal selector specified (0x%x > 0x15) "
126049ab747fSPaolo Bonzini                           "for 64-bit DMA block move", selector);
126149ab747fSPaolo Bonzini                     break;
126249ab747fSPaolo Bonzini                 }
126349ab747fSPaolo Bonzini             }
126449ab747fSPaolo Bonzini         } else if (lsi_dma_64bit(s)) {
126549ab747fSPaolo Bonzini             /* fetch a 3rd dword if 64-bit direct move is enabled and
126649ab747fSPaolo Bonzini                only if we're not doing table indirect or indirect addressing */
126749ab747fSPaolo Bonzini             s->dbms = read_dword(s, s->dsp);
126849ab747fSPaolo Bonzini             s->dsp += 4;
126949ab747fSPaolo Bonzini             s->ia = s->dsp - 12;
127049ab747fSPaolo Bonzini         }
127149ab747fSPaolo Bonzini         if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
127282cf2bcfSSven Schnelle             trace_lsi_execute_script_blockmove_badphase(
127382cf2bcfSSven Schnelle                     scsi_phase_name(s->sstat1),
127482cf2bcfSSven Schnelle                     scsi_phase_name(insn >> 24));
127549ab747fSPaolo Bonzini             lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
127649ab747fSPaolo Bonzini             break;
127749ab747fSPaolo Bonzini         }
127849ab747fSPaolo Bonzini         s->dnad = addr;
127949ab747fSPaolo Bonzini         s->dnad64 = addr_high;
128049ab747fSPaolo Bonzini         switch (s->sstat1 & 0x7) {
128149ab747fSPaolo Bonzini         case PHASE_DO:
1282f08ec2b8SSven Schnelle             s->waiting = LSI_DMA_SCRIPTS;
128349ab747fSPaolo Bonzini             lsi_do_dma(s, 1);
128449ab747fSPaolo Bonzini             if (s->waiting)
1285f08ec2b8SSven Schnelle                 s->waiting = LSI_DMA_IN_PROGRESS;
128649ab747fSPaolo Bonzini             break;
128749ab747fSPaolo Bonzini         case PHASE_DI:
1288f08ec2b8SSven Schnelle             s->waiting = LSI_DMA_SCRIPTS;
128949ab747fSPaolo Bonzini             lsi_do_dma(s, 0);
129049ab747fSPaolo Bonzini             if (s->waiting)
1291f08ec2b8SSven Schnelle                 s->waiting = LSI_DMA_IN_PROGRESS;
129249ab747fSPaolo Bonzini             break;
129349ab747fSPaolo Bonzini         case PHASE_CMD:
129449ab747fSPaolo Bonzini             lsi_do_command(s);
129549ab747fSPaolo Bonzini             break;
129649ab747fSPaolo Bonzini         case PHASE_ST:
129749ab747fSPaolo Bonzini             lsi_do_status(s);
129849ab747fSPaolo Bonzini             break;
129949ab747fSPaolo Bonzini         case PHASE_MO:
130049ab747fSPaolo Bonzini             lsi_do_msgout(s);
130149ab747fSPaolo Bonzini             break;
130249ab747fSPaolo Bonzini         case PHASE_MI:
130349ab747fSPaolo Bonzini             lsi_do_msgin(s);
130449ab747fSPaolo Bonzini             break;
130549ab747fSPaolo Bonzini         default:
130682cf2bcfSSven Schnelle             qemu_log_mask(LOG_UNIMP, "lsi_scsi: Unimplemented phase %s\n",
130782cf2bcfSSven Schnelle                           scsi_phase_name(s->sstat1));
130849ab747fSPaolo Bonzini         }
130949ab747fSPaolo Bonzini         s->dfifo = s->dbc & 0xff;
131049ab747fSPaolo Bonzini         s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3);
131149ab747fSPaolo Bonzini         s->sbc = s->dbc;
131249ab747fSPaolo Bonzini         s->rbc -= s->dbc;
131349ab747fSPaolo Bonzini         s->ua = addr + s->dbc;
131449ab747fSPaolo Bonzini         break;
131549ab747fSPaolo Bonzini 
131649ab747fSPaolo Bonzini     case 1: /* IO or Read/Write instruction.  */
131749ab747fSPaolo Bonzini         opcode = (insn >> 27) & 7;
131849ab747fSPaolo Bonzini         if (opcode < 5) {
131949ab747fSPaolo Bonzini             uint32_t id;
132049ab747fSPaolo Bonzini 
132149ab747fSPaolo Bonzini             if (insn & (1 << 25)) {
132292794105SPeter Maydell                 id = read_dword(s, s->dsa + sextract32(insn, 0, 24));
132349ab747fSPaolo Bonzini             } else {
132449ab747fSPaolo Bonzini                 id = insn;
132549ab747fSPaolo Bonzini             }
132649ab747fSPaolo Bonzini             id = (id >> 16) & 0xf;
132749ab747fSPaolo Bonzini             if (insn & (1 << 26)) {
132892794105SPeter Maydell                 addr = s->dsp + sextract32(addr, 0, 24);
132949ab747fSPaolo Bonzini             }
133049ab747fSPaolo Bonzini             s->dnad = addr;
133149ab747fSPaolo Bonzini             switch (opcode) {
133249ab747fSPaolo Bonzini             case 0: /* Select */
133349ab747fSPaolo Bonzini                 s->sdid = id;
133449ab747fSPaolo Bonzini                 if (s->scntl1 & LSI_SCNTL1_CON) {
1335c921370bSMark Cave-Ayland                     trace_lsi_execute_script_io_alreadyreselected();
133649ab747fSPaolo Bonzini                     s->dsp = s->dnad;
133749ab747fSPaolo Bonzini                     break;
133849ab747fSPaolo Bonzini                 }
133949ab747fSPaolo Bonzini                 s->sstat0 |= LSI_SSTAT0_WOA;
134049ab747fSPaolo Bonzini                 s->scntl1 &= ~LSI_SCNTL1_IARB;
134149ab747fSPaolo Bonzini                 if (!scsi_device_find(&s->bus, 0, id, 0)) {
134249ab747fSPaolo Bonzini                     lsi_bad_selection(s, id);
134349ab747fSPaolo Bonzini                     break;
134449ab747fSPaolo Bonzini                 }
1345c921370bSMark Cave-Ayland                 trace_lsi_execute_script_io_selected(id,
1346c921370bSMark Cave-Ayland                                              insn & (1 << 3) ? " ATN" : "");
13479b4b4e51SMichael Tokarev                 /* ??? Linux drivers complain when this is set.  Maybe
134849ab747fSPaolo Bonzini                    it only applies in low-level mode (unimplemented).
134949ab747fSPaolo Bonzini                 lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
135049ab747fSPaolo Bonzini                 s->select_tag = id << 8;
135149ab747fSPaolo Bonzini                 s->scntl1 |= LSI_SCNTL1_CON;
135249ab747fSPaolo Bonzini                 if (insn & (1 << 3)) {
135349ab747fSPaolo Bonzini                     s->socl |= LSI_SOCL_ATN;
135412dd89f7SSven Schnelle                     s->sbcl |= LSI_SBCL_ATN;
135549ab747fSPaolo Bonzini                 }
135612dd89f7SSven Schnelle                 s->sbcl |= LSI_SBCL_BSY;
135749ab747fSPaolo Bonzini                 lsi_set_phase(s, PHASE_MO);
1358f08ec2b8SSven Schnelle                 s->waiting = LSI_NOWAIT;
135949ab747fSPaolo Bonzini                 break;
136049ab747fSPaolo Bonzini             case 1: /* Disconnect */
1361c921370bSMark Cave-Ayland                 trace_lsi_execute_script_io_disconnect();
136249ab747fSPaolo Bonzini                 s->scntl1 &= ~LSI_SCNTL1_CON;
136356333e69SGeorge Kennedy                 /* FIXME: this is not entirely correct; the target need not ask
136456333e69SGeorge Kennedy                  * for reselection until it has to send data, while here we force a
136556333e69SGeorge Kennedy                  * reselection as soon as the bus is free.  The correct flow would
136656333e69SGeorge Kennedy                  * reselect before lsi_transfer_data and disconnect as soon as
136756333e69SGeorge Kennedy                  * DMA ends.
136856333e69SGeorge Kennedy                  */
136956333e69SGeorge Kennedy                 if (!s->current) {
137056333e69SGeorge Kennedy                     lsi_request *p = get_pending_req(s);
137156333e69SGeorge Kennedy                     if (p) {
137256333e69SGeorge Kennedy                         lsi_reselect(s, p);
137356333e69SGeorge Kennedy                     }
137456333e69SGeorge Kennedy                 }
137549ab747fSPaolo Bonzini                 break;
137649ab747fSPaolo Bonzini             case 2: /* Wait Reselect */
13772265e98bSSven Schnelle                 if (s->istat0 & LSI_ISTAT0_SIGP) {
13782265e98bSSven Schnelle                     s->dsp = s->dnad;
13792265e98bSSven Schnelle                 } else if (!lsi_irq_on_rsl(s)) {
138049ab747fSPaolo Bonzini                         lsi_wait_reselect(s);
138149ab747fSPaolo Bonzini                 }
138249ab747fSPaolo Bonzini                 break;
138349ab747fSPaolo Bonzini             case 3: /* Set */
1384c921370bSMark Cave-Ayland                 trace_lsi_execute_script_io_set(
138549ab747fSPaolo Bonzini                         insn & (1 << 3) ? " ATN" : "",
138649ab747fSPaolo Bonzini                         insn & (1 << 6) ? " ACK" : "",
138749ab747fSPaolo Bonzini                         insn & (1 << 9) ? " TM" : "",
138849ab747fSPaolo Bonzini                         insn & (1 << 10) ? " CC" : "");
138949ab747fSPaolo Bonzini                 if (insn & (1 << 3)) {
139049ab747fSPaolo Bonzini                     s->socl |= LSI_SOCL_ATN;
139112dd89f7SSven Schnelle                     s->sbcl |= LSI_SBCL_ATN;
139249ab747fSPaolo Bonzini                     lsi_set_phase(s, PHASE_MO);
139349ab747fSPaolo Bonzini                 }
139412dd89f7SSven Schnelle 
139512dd89f7SSven Schnelle                 if (insn & (1 << 6)) {
139612dd89f7SSven Schnelle                     s->sbcl |= LSI_SBCL_ACK;
139712dd89f7SSven Schnelle                 }
139812dd89f7SSven Schnelle 
139949ab747fSPaolo Bonzini                 if (insn & (1 << 9)) {
1400c921370bSMark Cave-Ayland                     qemu_log_mask(LOG_UNIMP,
1401c921370bSMark Cave-Ayland                         "lsi_scsi: Target mode not implemented\n");
140249ab747fSPaolo Bonzini                 }
140349ab747fSPaolo Bonzini                 if (insn & (1 << 10))
140449ab747fSPaolo Bonzini                     s->carry = 1;
140549ab747fSPaolo Bonzini                 break;
140649ab747fSPaolo Bonzini             case 4: /* Clear */
1407c921370bSMark Cave-Ayland                 trace_lsi_execute_script_io_clear(
140849ab747fSPaolo Bonzini                         insn & (1 << 3) ? " ATN" : "",
140949ab747fSPaolo Bonzini                         insn & (1 << 6) ? " ACK" : "",
141049ab747fSPaolo Bonzini                         insn & (1 << 9) ? " TM" : "",
141149ab747fSPaolo Bonzini                         insn & (1 << 10) ? " CC" : "");
141249ab747fSPaolo Bonzini                 if (insn & (1 << 3)) {
141349ab747fSPaolo Bonzini                     s->socl &= ~LSI_SOCL_ATN;
141412dd89f7SSven Schnelle                     s->sbcl &= ~LSI_SBCL_ATN;
141549ab747fSPaolo Bonzini                 }
141612dd89f7SSven Schnelle 
141712dd89f7SSven Schnelle                 if (insn & (1 << 6)) {
141812dd89f7SSven Schnelle                     s->sbcl &= ~LSI_SBCL_ACK;
141912dd89f7SSven Schnelle                 }
142012dd89f7SSven Schnelle 
142149ab747fSPaolo Bonzini                 if (insn & (1 << 10))
142249ab747fSPaolo Bonzini                     s->carry = 0;
142349ab747fSPaolo Bonzini                 break;
142449ab747fSPaolo Bonzini             }
142549ab747fSPaolo Bonzini         } else {
142649ab747fSPaolo Bonzini             uint8_t op0;
142749ab747fSPaolo Bonzini             uint8_t op1;
142849ab747fSPaolo Bonzini             uint8_t data8;
142949ab747fSPaolo Bonzini             int reg;
143049ab747fSPaolo Bonzini             int operator;
1431c921370bSMark Cave-Ayland 
143249ab747fSPaolo Bonzini             static const char *opcode_names[3] =
143349ab747fSPaolo Bonzini                 {"Write", "Read", "Read-Modify-Write"};
143449ab747fSPaolo Bonzini             static const char *operator_names[8] =
143549ab747fSPaolo Bonzini                 {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"};
143649ab747fSPaolo Bonzini 
143749ab747fSPaolo Bonzini             reg = ((insn >> 16) & 0x7f) | (insn & 0x80);
143849ab747fSPaolo Bonzini             data8 = (insn >> 8) & 0xff;
143949ab747fSPaolo Bonzini             opcode = (insn >> 27) & 7;
144049ab747fSPaolo Bonzini             operator = (insn >> 24) & 7;
1441c921370bSMark Cave-Ayland             trace_lsi_execute_script_io_opcode(
144249ab747fSPaolo Bonzini                     opcode_names[opcode - 5], reg,
144349ab747fSPaolo Bonzini                     operator_names[operator], data8, s->sfbr,
144449ab747fSPaolo Bonzini                     (insn & (1 << 23)) ? " SFBR" : "");
144549ab747fSPaolo Bonzini             op0 = op1 = 0;
144649ab747fSPaolo Bonzini             switch (opcode) {
144749ab747fSPaolo Bonzini             case 5: /* From SFBR */
144849ab747fSPaolo Bonzini                 op0 = s->sfbr;
144949ab747fSPaolo Bonzini                 op1 = data8;
145049ab747fSPaolo Bonzini                 break;
145149ab747fSPaolo Bonzini             case 6: /* To SFBR */
145249ab747fSPaolo Bonzini                 if (operator)
145349ab747fSPaolo Bonzini                     op0 = lsi_reg_readb(s, reg);
145449ab747fSPaolo Bonzini                 op1 = data8;
145549ab747fSPaolo Bonzini                 break;
145649ab747fSPaolo Bonzini             case 7: /* Read-modify-write */
145749ab747fSPaolo Bonzini                 if (operator)
145849ab747fSPaolo Bonzini                     op0 = lsi_reg_readb(s, reg);
145949ab747fSPaolo Bonzini                 if (insn & (1 << 23)) {
146049ab747fSPaolo Bonzini                     op1 = s->sfbr;
146149ab747fSPaolo Bonzini                 } else {
146249ab747fSPaolo Bonzini                     op1 = data8;
146349ab747fSPaolo Bonzini                 }
146449ab747fSPaolo Bonzini                 break;
146549ab747fSPaolo Bonzini             }
146649ab747fSPaolo Bonzini 
146749ab747fSPaolo Bonzini             switch (operator) {
146849ab747fSPaolo Bonzini             case 0: /* move */
146949ab747fSPaolo Bonzini                 op0 = op1;
147049ab747fSPaolo Bonzini                 break;
147149ab747fSPaolo Bonzini             case 1: /* Shift left */
147249ab747fSPaolo Bonzini                 op1 = op0 >> 7;
147349ab747fSPaolo Bonzini                 op0 = (op0 << 1) | s->carry;
147449ab747fSPaolo Bonzini                 s->carry = op1;
147549ab747fSPaolo Bonzini                 break;
147649ab747fSPaolo Bonzini             case 2: /* OR */
147749ab747fSPaolo Bonzini                 op0 |= op1;
147849ab747fSPaolo Bonzini                 break;
147949ab747fSPaolo Bonzini             case 3: /* XOR */
148049ab747fSPaolo Bonzini                 op0 ^= op1;
148149ab747fSPaolo Bonzini                 break;
148249ab747fSPaolo Bonzini             case 4: /* AND */
148349ab747fSPaolo Bonzini                 op0 &= op1;
148449ab747fSPaolo Bonzini                 break;
148549ab747fSPaolo Bonzini             case 5: /* SHR */
148649ab747fSPaolo Bonzini                 op1 = op0 & 1;
148749ab747fSPaolo Bonzini                 op0 = (op0 >> 1) | (s->carry << 7);
148849ab747fSPaolo Bonzini                 s->carry = op1;
148949ab747fSPaolo Bonzini                 break;
149049ab747fSPaolo Bonzini             case 6: /* ADD */
149149ab747fSPaolo Bonzini                 op0 += op1;
149249ab747fSPaolo Bonzini                 s->carry = op0 < op1;
149349ab747fSPaolo Bonzini                 break;
149449ab747fSPaolo Bonzini             case 7: /* ADC */
149549ab747fSPaolo Bonzini                 op0 += op1 + s->carry;
149649ab747fSPaolo Bonzini                 if (s->carry)
149749ab747fSPaolo Bonzini                     s->carry = op0 <= op1;
149849ab747fSPaolo Bonzini                 else
149949ab747fSPaolo Bonzini                     s->carry = op0 < op1;
150049ab747fSPaolo Bonzini                 break;
150149ab747fSPaolo Bonzini             }
150249ab747fSPaolo Bonzini 
150349ab747fSPaolo Bonzini             switch (opcode) {
150449ab747fSPaolo Bonzini             case 5: /* From SFBR */
150549ab747fSPaolo Bonzini             case 7: /* Read-modify-write */
150649ab747fSPaolo Bonzini                 lsi_reg_writeb(s, reg, op0);
150749ab747fSPaolo Bonzini                 break;
150849ab747fSPaolo Bonzini             case 6: /* To SFBR */
150949ab747fSPaolo Bonzini                 s->sfbr = op0;
151049ab747fSPaolo Bonzini                 break;
151149ab747fSPaolo Bonzini             }
151249ab747fSPaolo Bonzini         }
151349ab747fSPaolo Bonzini         break;
151449ab747fSPaolo Bonzini 
151549ab747fSPaolo Bonzini     case 2: /* Transfer Control.  */
151649ab747fSPaolo Bonzini         {
151749ab747fSPaolo Bonzini             int cond;
151849ab747fSPaolo Bonzini             int jmp;
151949ab747fSPaolo Bonzini 
152049ab747fSPaolo Bonzini             if ((insn & 0x002e0000) == 0) {
1521c921370bSMark Cave-Ayland                 trace_lsi_execute_script_tc_nop();
152249ab747fSPaolo Bonzini                 break;
152349ab747fSPaolo Bonzini             }
152449ab747fSPaolo Bonzini             if (s->sist1 & LSI_SIST1_STO) {
1525c921370bSMark Cave-Ayland                 trace_lsi_execute_script_tc_delayedselect_timeout();
152649ab747fSPaolo Bonzini                 lsi_stop_script(s);
152749ab747fSPaolo Bonzini                 break;
152849ab747fSPaolo Bonzini             }
152949ab747fSPaolo Bonzini             cond = jmp = (insn & (1 << 19)) != 0;
153049ab747fSPaolo Bonzini             if (cond == jmp && (insn & (1 << 21))) {
1531c921370bSMark Cave-Ayland                 trace_lsi_execute_script_tc_compc(s->carry == jmp);
153249ab747fSPaolo Bonzini                 cond = s->carry != 0;
153349ab747fSPaolo Bonzini             }
153449ab747fSPaolo Bonzini             if (cond == jmp && (insn & (1 << 17))) {
153582cf2bcfSSven Schnelle                 trace_lsi_execute_script_tc_compp(scsi_phase_name(s->sstat1),
153682cf2bcfSSven Schnelle                         jmp ? '=' : '!', scsi_phase_name(insn >> 24));
153749ab747fSPaolo Bonzini                 cond = (s->sstat1 & PHASE_MASK) == ((insn >> 24) & 7);
153849ab747fSPaolo Bonzini             }
153949ab747fSPaolo Bonzini             if (cond == jmp && (insn & (1 << 18))) {
154049ab747fSPaolo Bonzini                 uint8_t mask;
154149ab747fSPaolo Bonzini 
154249ab747fSPaolo Bonzini                 mask = (~insn >> 8) & 0xff;
1543c921370bSMark Cave-Ayland                 trace_lsi_execute_script_tc_compd(
154449ab747fSPaolo Bonzini                         s->sfbr, mask, jmp ? '=' : '!', insn & mask);
154549ab747fSPaolo Bonzini                 cond = (s->sfbr & mask) == (insn & mask);
154649ab747fSPaolo Bonzini             }
154749ab747fSPaolo Bonzini             if (cond == jmp) {
154849ab747fSPaolo Bonzini                 if (insn & (1 << 23)) {
154949ab747fSPaolo Bonzini                     /* Relative address.  */
155092794105SPeter Maydell                     addr = s->dsp + sextract32(addr, 0, 24);
155149ab747fSPaolo Bonzini                 }
155249ab747fSPaolo Bonzini                 switch ((insn >> 27) & 7) {
155349ab747fSPaolo Bonzini                 case 0: /* Jump */
1554c921370bSMark Cave-Ayland                     trace_lsi_execute_script_tc_jump(addr);
15556f84da3aSPeter Lieven                     s->adder = addr;
155649ab747fSPaolo Bonzini                     s->dsp = addr;
155749ab747fSPaolo Bonzini                     break;
155849ab747fSPaolo Bonzini                 case 1: /* Call */
1559c921370bSMark Cave-Ayland                     trace_lsi_execute_script_tc_call(addr);
156049ab747fSPaolo Bonzini                     s->temp = s->dsp;
156149ab747fSPaolo Bonzini                     s->dsp = addr;
156249ab747fSPaolo Bonzini                     break;
156349ab747fSPaolo Bonzini                 case 2: /* Return */
1564c921370bSMark Cave-Ayland                     trace_lsi_execute_script_tc_return(s->temp);
156549ab747fSPaolo Bonzini                     s->dsp = s->temp;
156649ab747fSPaolo Bonzini                     break;
156749ab747fSPaolo Bonzini                 case 3: /* Interrupt */
1568c921370bSMark Cave-Ayland                     trace_lsi_execute_script_tc_interrupt(s->dsps);
156949ab747fSPaolo Bonzini                     if ((insn & (1 << 20)) != 0) {
157049ab747fSPaolo Bonzini                         s->istat0 |= LSI_ISTAT0_INTF;
157149ab747fSPaolo Bonzini                         lsi_update_irq(s);
157249ab747fSPaolo Bonzini                     } else {
157349ab747fSPaolo Bonzini                         lsi_script_dma_interrupt(s, LSI_DSTAT_SIR);
157449ab747fSPaolo Bonzini                     }
157549ab747fSPaolo Bonzini                     break;
157649ab747fSPaolo Bonzini                 default:
1577c921370bSMark Cave-Ayland                     trace_lsi_execute_script_tc_illegal();
157849ab747fSPaolo Bonzini                     lsi_script_dma_interrupt(s, LSI_DSTAT_IID);
157949ab747fSPaolo Bonzini                     break;
158049ab747fSPaolo Bonzini                 }
158149ab747fSPaolo Bonzini             } else {
1582c921370bSMark Cave-Ayland                 trace_lsi_execute_script_tc_cc_failed();
158349ab747fSPaolo Bonzini             }
158449ab747fSPaolo Bonzini         }
158549ab747fSPaolo Bonzini         break;
158649ab747fSPaolo Bonzini 
158749ab747fSPaolo Bonzini     case 3:
158849ab747fSPaolo Bonzini         if ((insn & (1 << 29)) == 0) {
158949ab747fSPaolo Bonzini             /* Memory move.  */
159049ab747fSPaolo Bonzini             uint32_t dest;
159149ab747fSPaolo Bonzini             /* ??? The docs imply the destination address is loaded into
159249ab747fSPaolo Bonzini                the TEMP register.  However the Linux drivers rely on
159349ab747fSPaolo Bonzini                the value being presrved.  */
159449ab747fSPaolo Bonzini             dest = read_dword(s, s->dsp);
159549ab747fSPaolo Bonzini             s->dsp += 4;
159649ab747fSPaolo Bonzini             lsi_memcpy(s, dest, addr, insn & 0xffffff);
159749ab747fSPaolo Bonzini         } else {
159849ab747fSPaolo Bonzini             uint8_t data[7];
159949ab747fSPaolo Bonzini             int reg;
160049ab747fSPaolo Bonzini             int n;
160149ab747fSPaolo Bonzini             int i;
160249ab747fSPaolo Bonzini 
160349ab747fSPaolo Bonzini             if (insn & (1 << 28)) {
160492794105SPeter Maydell                 addr = s->dsa + sextract32(addr, 0, 24);
160549ab747fSPaolo Bonzini             }
160649ab747fSPaolo Bonzini             n = (insn & 7);
160749ab747fSPaolo Bonzini             reg = (insn >> 16) & 0xff;
160849ab747fSPaolo Bonzini             if (insn & (1 << 24)) {
1609725eec70SAndreas Färber                 pci_dma_read(pci_dev, addr, data, n);
1610c921370bSMark Cave-Ayland                 trace_lsi_execute_script_mm_load(reg, n, addr, *(int *)data);
161149ab747fSPaolo Bonzini                 for (i = 0; i < n; i++) {
161249ab747fSPaolo Bonzini                     lsi_reg_writeb(s, reg + i, data[i]);
161349ab747fSPaolo Bonzini                 }
161449ab747fSPaolo Bonzini             } else {
1615c921370bSMark Cave-Ayland                 trace_lsi_execute_script_mm_store(reg, n, addr);
161649ab747fSPaolo Bonzini                 for (i = 0; i < n; i++) {
161749ab747fSPaolo Bonzini                     data[i] = lsi_reg_readb(s, reg + i);
161849ab747fSPaolo Bonzini                 }
1619725eec70SAndreas Färber                 pci_dma_write(pci_dev, addr, data, n);
162049ab747fSPaolo Bonzini             }
162149ab747fSPaolo Bonzini         }
162249ab747fSPaolo Bonzini     }
1623de594e47SPaolo Bonzini     if (s->istat1 & LSI_ISTAT1_SRUN && s->waiting == LSI_NOWAIT) {
162449ab747fSPaolo Bonzini         if (s->dcntl & LSI_DCNTL_SSM) {
162549ab747fSPaolo Bonzini             lsi_script_dma_interrupt(s, LSI_DSTAT_SSI);
162649ab747fSPaolo Bonzini         } else {
162749ab747fSPaolo Bonzini             goto again;
162849ab747fSPaolo Bonzini         }
162949ab747fSPaolo Bonzini     }
1630c921370bSMark Cave-Ayland     trace_lsi_execute_script_stop();
1631b987718bSThomas Huth 
1632b987718bSThomas Huth     reentrancy_level--;
163349ab747fSPaolo Bonzini }
163449ab747fSPaolo Bonzini 
lsi_reg_readb(LSIState * s,int offset)163549ab747fSPaolo Bonzini static uint8_t lsi_reg_readb(LSIState *s, int offset)
163649ab747fSPaolo Bonzini {
163764eb7491SHervé Poussineau     uint8_t ret;
163864eb7491SHervé Poussineau 
163949ab747fSPaolo Bonzini #define CASE_GET_REG24(name, addr) \
164064eb7491SHervé Poussineau     case addr: ret = s->name & 0xff; break; \
164164eb7491SHervé Poussineau     case addr + 1: ret = (s->name >> 8) & 0xff; break; \
164264eb7491SHervé Poussineau     case addr + 2: ret = (s->name >> 16) & 0xff; break;
164349ab747fSPaolo Bonzini 
164449ab747fSPaolo Bonzini #define CASE_GET_REG32(name, addr) \
164564eb7491SHervé Poussineau     case addr: ret = s->name & 0xff; break; \
164664eb7491SHervé Poussineau     case addr + 1: ret = (s->name >> 8) & 0xff; break; \
164764eb7491SHervé Poussineau     case addr + 2: ret = (s->name >> 16) & 0xff; break; \
164864eb7491SHervé Poussineau     case addr + 3: ret = (s->name >> 24) & 0xff; break;
164949ab747fSPaolo Bonzini 
165049ab747fSPaolo Bonzini     switch (offset) {
165149ab747fSPaolo Bonzini     case 0x00: /* SCNTL0 */
165264eb7491SHervé Poussineau         ret = s->scntl0;
165364eb7491SHervé Poussineau         break;
165449ab747fSPaolo Bonzini     case 0x01: /* SCNTL1 */
165564eb7491SHervé Poussineau         ret = s->scntl1;
165664eb7491SHervé Poussineau         break;
165749ab747fSPaolo Bonzini     case 0x02: /* SCNTL2 */
165864eb7491SHervé Poussineau         ret = s->scntl2;
165964eb7491SHervé Poussineau         break;
166049ab747fSPaolo Bonzini     case 0x03: /* SCNTL3 */
166164eb7491SHervé Poussineau         ret = s->scntl3;
166264eb7491SHervé Poussineau         break;
166349ab747fSPaolo Bonzini     case 0x04: /* SCID */
166464eb7491SHervé Poussineau         ret = s->scid;
166564eb7491SHervé Poussineau         break;
166649ab747fSPaolo Bonzini     case 0x05: /* SXFER */
166764eb7491SHervé Poussineau         ret = s->sxfer;
166864eb7491SHervé Poussineau         break;
166949ab747fSPaolo Bonzini     case 0x06: /* SDID */
167064eb7491SHervé Poussineau         ret = s->sdid;
167164eb7491SHervé Poussineau         break;
167249ab747fSPaolo Bonzini     case 0x07: /* GPREG0 */
167364eb7491SHervé Poussineau         ret = 0x7f;
167464eb7491SHervé Poussineau         break;
167549ab747fSPaolo Bonzini     case 0x08: /* Revision ID */
167664eb7491SHervé Poussineau         ret = 0x00;
167764eb7491SHervé Poussineau         break;
16786f84da3aSPeter Lieven     case 0x09: /* SOCL */
167964eb7491SHervé Poussineau         ret = s->socl;
168064eb7491SHervé Poussineau         break;
168149ab747fSPaolo Bonzini     case 0xa: /* SSID */
168264eb7491SHervé Poussineau         ret = s->ssid;
168364eb7491SHervé Poussineau         break;
168449ab747fSPaolo Bonzini     case 0xb: /* SBCL */
168512dd89f7SSven Schnelle         ret = s->sbcl;
168664eb7491SHervé Poussineau         break;
168749ab747fSPaolo Bonzini     case 0xc: /* DSTAT */
168864eb7491SHervé Poussineau         ret = s->dstat | LSI_DSTAT_DFE;
168949ab747fSPaolo Bonzini         if ((s->istat0 & LSI_ISTAT0_INTF) == 0)
169049ab747fSPaolo Bonzini             s->dstat = 0;
169149ab747fSPaolo Bonzini         lsi_update_irq(s);
169264eb7491SHervé Poussineau         break;
169349ab747fSPaolo Bonzini     case 0x0d: /* SSTAT0 */
169464eb7491SHervé Poussineau         ret = s->sstat0;
169564eb7491SHervé Poussineau         break;
169649ab747fSPaolo Bonzini     case 0x0e: /* SSTAT1 */
169764eb7491SHervé Poussineau         ret = s->sstat1;
169864eb7491SHervé Poussineau         break;
169949ab747fSPaolo Bonzini     case 0x0f: /* SSTAT2 */
170064eb7491SHervé Poussineau         ret = s->scntl1 & LSI_SCNTL1_CON ? 0 : 2;
170164eb7491SHervé Poussineau         break;
170249ab747fSPaolo Bonzini     CASE_GET_REG32(dsa, 0x10)
170349ab747fSPaolo Bonzini     case 0x14: /* ISTAT0 */
170464eb7491SHervé Poussineau         ret = s->istat0;
170564eb7491SHervé Poussineau         break;
170649ab747fSPaolo Bonzini     case 0x15: /* ISTAT1 */
170764eb7491SHervé Poussineau         ret = s->istat1;
170864eb7491SHervé Poussineau         break;
170949ab747fSPaolo Bonzini     case 0x16: /* MBOX0 */
171064eb7491SHervé Poussineau         ret = s->mbox0;
171164eb7491SHervé Poussineau         break;
171249ab747fSPaolo Bonzini     case 0x17: /* MBOX1 */
171364eb7491SHervé Poussineau         ret = s->mbox1;
171464eb7491SHervé Poussineau         break;
171549ab747fSPaolo Bonzini     case 0x18: /* CTEST0 */
171664eb7491SHervé Poussineau         ret = 0xff;
171764eb7491SHervé Poussineau         break;
171849ab747fSPaolo Bonzini     case 0x19: /* CTEST1 */
171964eb7491SHervé Poussineau         ret = 0;
172064eb7491SHervé Poussineau         break;
172149ab747fSPaolo Bonzini     case 0x1a: /* CTEST2 */
172264eb7491SHervé Poussineau         ret = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM;
172349ab747fSPaolo Bonzini         if (s->istat0 & LSI_ISTAT0_SIGP) {
172449ab747fSPaolo Bonzini             s->istat0 &= ~LSI_ISTAT0_SIGP;
172564eb7491SHervé Poussineau             ret |= LSI_CTEST2_SIGP;
172649ab747fSPaolo Bonzini         }
172764eb7491SHervé Poussineau         break;
172849ab747fSPaolo Bonzini     case 0x1b: /* CTEST3 */
172964eb7491SHervé Poussineau         ret = s->ctest3;
173064eb7491SHervé Poussineau         break;
173149ab747fSPaolo Bonzini     CASE_GET_REG32(temp, 0x1c)
173249ab747fSPaolo Bonzini     case 0x20: /* DFIFO */
173307163c99SSven Schnelle         ret = s->dfifo;
173464eb7491SHervé Poussineau         break;
173549ab747fSPaolo Bonzini     case 0x21: /* CTEST4 */
173664eb7491SHervé Poussineau         ret = s->ctest4;
173764eb7491SHervé Poussineau         break;
173849ab747fSPaolo Bonzini     case 0x22: /* CTEST5 */
173964eb7491SHervé Poussineau         ret = s->ctest5;
174064eb7491SHervé Poussineau         break;
174149ab747fSPaolo Bonzini     case 0x23: /* CTEST6 */
174264eb7491SHervé Poussineau         ret = 0;
174364eb7491SHervé Poussineau         break;
174449ab747fSPaolo Bonzini     CASE_GET_REG24(dbc, 0x24)
174549ab747fSPaolo Bonzini     case 0x27: /* DCMD */
174664eb7491SHervé Poussineau         ret = s->dcmd;
174764eb7491SHervé Poussineau         break;
174849ab747fSPaolo Bonzini     CASE_GET_REG32(dnad, 0x28)
174949ab747fSPaolo Bonzini     CASE_GET_REG32(dsp, 0x2c)
175049ab747fSPaolo Bonzini     CASE_GET_REG32(dsps, 0x30)
175149ab747fSPaolo Bonzini     CASE_GET_REG32(scratch[0], 0x34)
175249ab747fSPaolo Bonzini     case 0x38: /* DMODE */
175364eb7491SHervé Poussineau         ret = s->dmode;
175464eb7491SHervé Poussineau         break;
175549ab747fSPaolo Bonzini     case 0x39: /* DIEN */
175664eb7491SHervé Poussineau         ret = s->dien;
175764eb7491SHervé Poussineau         break;
175849ab747fSPaolo Bonzini     case 0x3a: /* SBR */
175964eb7491SHervé Poussineau         ret = s->sbr;
176064eb7491SHervé Poussineau         break;
176149ab747fSPaolo Bonzini     case 0x3b: /* DCNTL */
176264eb7491SHervé Poussineau         ret = s->dcntl;
176364eb7491SHervé Poussineau         break;
17646f84da3aSPeter Lieven     /* ADDER Output (Debug of relative jump address) */
17656f84da3aSPeter Lieven     CASE_GET_REG32(adder, 0x3c)
176649ab747fSPaolo Bonzini     case 0x40: /* SIEN0 */
176764eb7491SHervé Poussineau         ret = s->sien0;
176864eb7491SHervé Poussineau         break;
176949ab747fSPaolo Bonzini     case 0x41: /* SIEN1 */
177064eb7491SHervé Poussineau         ret = s->sien1;
177164eb7491SHervé Poussineau         break;
177249ab747fSPaolo Bonzini     case 0x42: /* SIST0 */
177364eb7491SHervé Poussineau         ret = s->sist0;
177449ab747fSPaolo Bonzini         s->sist0 = 0;
177549ab747fSPaolo Bonzini         lsi_update_irq(s);
177664eb7491SHervé Poussineau         break;
177749ab747fSPaolo Bonzini     case 0x43: /* SIST1 */
177864eb7491SHervé Poussineau         ret = s->sist1;
177949ab747fSPaolo Bonzini         s->sist1 = 0;
178049ab747fSPaolo Bonzini         lsi_update_irq(s);
178164eb7491SHervé Poussineau         break;
178249ab747fSPaolo Bonzini     case 0x46: /* MACNTL */
178364eb7491SHervé Poussineau         ret = 0x0f;
178464eb7491SHervé Poussineau         break;
178549ab747fSPaolo Bonzini     case 0x47: /* GPCNTL0 */
178664eb7491SHervé Poussineau         ret = 0x0f;
178764eb7491SHervé Poussineau         break;
178849ab747fSPaolo Bonzini     case 0x48: /* STIME0 */
178964eb7491SHervé Poussineau         ret = s->stime0;
179064eb7491SHervé Poussineau         break;
179149ab747fSPaolo Bonzini     case 0x4a: /* RESPID0 */
179264eb7491SHervé Poussineau         ret = s->respid0;
179364eb7491SHervé Poussineau         break;
179449ab747fSPaolo Bonzini     case 0x4b: /* RESPID1 */
179564eb7491SHervé Poussineau         ret = s->respid1;
179664eb7491SHervé Poussineau         break;
179749ab747fSPaolo Bonzini     case 0x4d: /* STEST1 */
179864eb7491SHervé Poussineau         ret = s->stest1;
179964eb7491SHervé Poussineau         break;
180049ab747fSPaolo Bonzini     case 0x4e: /* STEST2 */
180164eb7491SHervé Poussineau         ret = s->stest2;
180264eb7491SHervé Poussineau         break;
180349ab747fSPaolo Bonzini     case 0x4f: /* STEST3 */
180464eb7491SHervé Poussineau         ret = s->stest3;
180564eb7491SHervé Poussineau         break;
180649ab747fSPaolo Bonzini     case 0x50: /* SIDL */
180749ab747fSPaolo Bonzini         /* This is needed by the linux drivers.  We currently only update it
180849ab747fSPaolo Bonzini            during the MSG IN phase.  */
180964eb7491SHervé Poussineau         ret = s->sidl;
181064eb7491SHervé Poussineau         break;
181149ab747fSPaolo Bonzini     case 0x52: /* STEST4 */
181264eb7491SHervé Poussineau         ret = 0xe0;
181364eb7491SHervé Poussineau         break;
181449ab747fSPaolo Bonzini     case 0x56: /* CCNTL0 */
181564eb7491SHervé Poussineau         ret = s->ccntl0;
181664eb7491SHervé Poussineau         break;
181749ab747fSPaolo Bonzini     case 0x57: /* CCNTL1 */
181864eb7491SHervé Poussineau         ret = s->ccntl1;
181964eb7491SHervé Poussineau         break;
182049ab747fSPaolo Bonzini     case 0x58: /* SBDL */
182149ab747fSPaolo Bonzini         /* Some drivers peek at the data bus during the MSG IN phase.  */
1822e58ccf03SPrasad J Pandit         if ((s->sstat1 & PHASE_MASK) == PHASE_MI) {
1823e58ccf03SPrasad J Pandit             assert(s->msg_len > 0);
182449ab747fSPaolo Bonzini             return s->msg[0];
1825e58ccf03SPrasad J Pandit         }
182664eb7491SHervé Poussineau         ret = 0;
182764eb7491SHervé Poussineau         break;
182849ab747fSPaolo Bonzini     case 0x59: /* SBDL high */
182964eb7491SHervé Poussineau         ret = 0;
183064eb7491SHervé Poussineau         break;
183149ab747fSPaolo Bonzini     CASE_GET_REG32(mmrs, 0xa0)
183249ab747fSPaolo Bonzini     CASE_GET_REG32(mmws, 0xa4)
183349ab747fSPaolo Bonzini     CASE_GET_REG32(sfs, 0xa8)
183449ab747fSPaolo Bonzini     CASE_GET_REG32(drs, 0xac)
183549ab747fSPaolo Bonzini     CASE_GET_REG32(sbms, 0xb0)
183649ab747fSPaolo Bonzini     CASE_GET_REG32(dbms, 0xb4)
183749ab747fSPaolo Bonzini     CASE_GET_REG32(dnad64, 0xb8)
183849ab747fSPaolo Bonzini     CASE_GET_REG32(pmjad1, 0xc0)
183949ab747fSPaolo Bonzini     CASE_GET_REG32(pmjad2, 0xc4)
184049ab747fSPaolo Bonzini     CASE_GET_REG32(rbc, 0xc8)
184149ab747fSPaolo Bonzini     CASE_GET_REG32(ua, 0xcc)
184249ab747fSPaolo Bonzini     CASE_GET_REG32(ia, 0xd4)
184349ab747fSPaolo Bonzini     CASE_GET_REG32(sbc, 0xd8)
184449ab747fSPaolo Bonzini     CASE_GET_REG32(csbc, 0xdc)
184564eb7491SHervé Poussineau     case 0x5c ... 0x9f:
184664eb7491SHervé Poussineau     {
184749ab747fSPaolo Bonzini         int n;
184849ab747fSPaolo Bonzini         int shift;
184949ab747fSPaolo Bonzini         n = (offset - 0x58) >> 2;
185049ab747fSPaolo Bonzini         shift = (offset & 3) * 8;
185164eb7491SHervé Poussineau         ret = (s->scratch[n] >> shift) & 0xff;
185264eb7491SHervé Poussineau         break;
185349ab747fSPaolo Bonzini     }
185464eb7491SHervé Poussineau     default:
185585a20bc4SHervé Poussineau     {
185685a20bc4SHervé Poussineau         qemu_log_mask(LOG_GUEST_ERROR,
185785a20bc4SHervé Poussineau                       "lsi_scsi: invalid read from reg %s %x\n",
185885a20bc4SHervé Poussineau                       offset < ARRAY_SIZE(names) ? names[offset] : "???",
185985a20bc4SHervé Poussineau                       offset);
186085a20bc4SHervé Poussineau         ret = 0xff;
186185a20bc4SHervé Poussineau         break;
186285a20bc4SHervé Poussineau     }
186364eb7491SHervé Poussineau     }
186449ab747fSPaolo Bonzini #undef CASE_GET_REG24
186549ab747fSPaolo Bonzini #undef CASE_GET_REG32
186664eb7491SHervé Poussineau 
1867c921370bSMark Cave-Ayland     trace_lsi_reg_read(offset < ARRAY_SIZE(names) ? names[offset] : "???",
1868c921370bSMark Cave-Ayland                        offset, ret);
186964eb7491SHervé Poussineau 
187064eb7491SHervé Poussineau     return ret;
187149ab747fSPaolo Bonzini }
187249ab747fSPaolo Bonzini 
lsi_reg_writeb(LSIState * s,int offset,uint8_t val)187349ab747fSPaolo Bonzini static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
187449ab747fSPaolo Bonzini {
187549ab747fSPaolo Bonzini #define CASE_SET_REG24(name, addr) \
187649ab747fSPaolo Bonzini     case addr    : s->name &= 0xffffff00; s->name |= val;       break; \
187749ab747fSPaolo Bonzini     case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8;  break; \
187849ab747fSPaolo Bonzini     case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break;
187949ab747fSPaolo Bonzini 
188049ab747fSPaolo Bonzini #define CASE_SET_REG32(name, addr) \
188149ab747fSPaolo Bonzini     case addr    : s->name &= 0xffffff00; s->name |= val;       break; \
188249ab747fSPaolo Bonzini     case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8;  break; \
188349ab747fSPaolo Bonzini     case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
188449ab747fSPaolo Bonzini     case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
188549ab747fSPaolo Bonzini 
1886c921370bSMark Cave-Ayland     trace_lsi_reg_write(offset < ARRAY_SIZE(names) ? names[offset] : "???",
1887c921370bSMark Cave-Ayland                         offset, val);
1888c921370bSMark Cave-Ayland 
188949ab747fSPaolo Bonzini     switch (offset) {
189049ab747fSPaolo Bonzini     case 0x00: /* SCNTL0 */
189149ab747fSPaolo Bonzini         s->scntl0 = val;
189249ab747fSPaolo Bonzini         if (val & LSI_SCNTL0_START) {
1893c921370bSMark Cave-Ayland             qemu_log_mask(LOG_UNIMP,
1894c921370bSMark Cave-Ayland                           "lsi_scsi: Start sequence not implemented\n");
189549ab747fSPaolo Bonzini         }
189649ab747fSPaolo Bonzini         break;
189749ab747fSPaolo Bonzini     case 0x01: /* SCNTL1 */
189849ab747fSPaolo Bonzini         s->scntl1 = val & ~LSI_SCNTL1_SST;
189949ab747fSPaolo Bonzini         if (val & LSI_SCNTL1_IARB) {
1900c921370bSMark Cave-Ayland             qemu_log_mask(LOG_UNIMP,
1901c921370bSMark Cave-Ayland                       "lsi_scsi: Immediate Arbritration not implemented\n");
190249ab747fSPaolo Bonzini         }
190349ab747fSPaolo Bonzini         if (val & LSI_SCNTL1_RST) {
190449ab747fSPaolo Bonzini             if (!(s->sstat0 & LSI_SSTAT0_RST)) {
19054a5fc890SPeter Maydell                 bus_cold_reset(BUS(&s->bus));
190649ab747fSPaolo Bonzini                 s->sstat0 |= LSI_SSTAT0_RST;
190749ab747fSPaolo Bonzini                 lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
190849ab747fSPaolo Bonzini             }
190949ab747fSPaolo Bonzini         } else {
191049ab747fSPaolo Bonzini             s->sstat0 &= ~LSI_SSTAT0_RST;
191149ab747fSPaolo Bonzini         }
191249ab747fSPaolo Bonzini         break;
191349ab747fSPaolo Bonzini     case 0x02: /* SCNTL2 */
191449ab747fSPaolo Bonzini         val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS);
191549ab747fSPaolo Bonzini         s->scntl2 = val;
191649ab747fSPaolo Bonzini         break;
191749ab747fSPaolo Bonzini     case 0x03: /* SCNTL3 */
191849ab747fSPaolo Bonzini         s->scntl3 = val;
191949ab747fSPaolo Bonzini         break;
192049ab747fSPaolo Bonzini     case 0x04: /* SCID */
192149ab747fSPaolo Bonzini         s->scid = val;
192249ab747fSPaolo Bonzini         break;
192349ab747fSPaolo Bonzini     case 0x05: /* SXFER */
192449ab747fSPaolo Bonzini         s->sxfer = val;
192549ab747fSPaolo Bonzini         break;
192649ab747fSPaolo Bonzini     case 0x06: /* SDID */
1927c7ac9f40SHervé Poussineau         if ((s->ssid & 0x80) && (val & 0xf) != (s->ssid & 0xf)) {
1928c921370bSMark Cave-Ayland             qemu_log_mask(LOG_GUEST_ERROR,
1929c921370bSMark Cave-Ayland                           "lsi_scsi: Destination ID does not match SSID\n");
1930c7ac9f40SHervé Poussineau         }
193149ab747fSPaolo Bonzini         s->sdid = val & 0xf;
193249ab747fSPaolo Bonzini         break;
193349ab747fSPaolo Bonzini     case 0x07: /* GPREG0 */
193449ab747fSPaolo Bonzini         break;
193549ab747fSPaolo Bonzini     case 0x08: /* SFBR */
193649ab747fSPaolo Bonzini         /* The CPU is not allowed to write to this register.  However the
193749ab747fSPaolo Bonzini            SCRIPTS register move instructions are.  */
193849ab747fSPaolo Bonzini         s->sfbr = val;
193949ab747fSPaolo Bonzini         break;
194049ab747fSPaolo Bonzini     case 0x0a: case 0x0b:
194149ab747fSPaolo Bonzini         /* Openserver writes to these readonly registers on startup */
194249ab747fSPaolo Bonzini         return;
194349ab747fSPaolo Bonzini     case 0x0c: case 0x0d: case 0x0e: case 0x0f:
194449ab747fSPaolo Bonzini         /* Linux writes to these readonly registers on startup.  */
194549ab747fSPaolo Bonzini         return;
194649ab747fSPaolo Bonzini     CASE_SET_REG32(dsa, 0x10)
194749ab747fSPaolo Bonzini     case 0x14: /* ISTAT0 */
194849ab747fSPaolo Bonzini         s->istat0 = (s->istat0 & 0x0f) | (val & 0xf0);
194949ab747fSPaolo Bonzini         if (val & LSI_ISTAT0_ABRT) {
195049ab747fSPaolo Bonzini             lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT);
195149ab747fSPaolo Bonzini         }
195249ab747fSPaolo Bonzini         if (val & LSI_ISTAT0_INTF) {
195349ab747fSPaolo Bonzini             s->istat0 &= ~LSI_ISTAT0_INTF;
195449ab747fSPaolo Bonzini             lsi_update_irq(s);
195549ab747fSPaolo Bonzini         }
1956f08ec2b8SSven Schnelle         if (s->waiting == LSI_WAIT_RESELECT && val & LSI_ISTAT0_SIGP) {
1957c921370bSMark Cave-Ayland             trace_lsi_awoken();
1958f08ec2b8SSven Schnelle             s->waiting = LSI_NOWAIT;
195949ab747fSPaolo Bonzini             s->dsp = s->dnad;
196049ab747fSPaolo Bonzini             lsi_execute_script(s);
196149ab747fSPaolo Bonzini         }
196249ab747fSPaolo Bonzini         if (val & LSI_ISTAT0_SRST) {
19634a5fc890SPeter Maydell             device_cold_reset(DEVICE(s));
196449ab747fSPaolo Bonzini         }
196549ab747fSPaolo Bonzini         break;
196649ab747fSPaolo Bonzini     case 0x16: /* MBOX0 */
196749ab747fSPaolo Bonzini         s->mbox0 = val;
196849ab747fSPaolo Bonzini         break;
196949ab747fSPaolo Bonzini     case 0x17: /* MBOX1 */
197049ab747fSPaolo Bonzini         s->mbox1 = val;
197149ab747fSPaolo Bonzini         break;
19720903c35dSHervé Poussineau     case 0x18: /* CTEST0 */
19730903c35dSHervé Poussineau         /* nothing to do */
19740903c35dSHervé Poussineau         break;
197549ab747fSPaolo Bonzini     case 0x1a: /* CTEST2 */
197649ab747fSPaolo Bonzini         s->ctest2 = val & LSI_CTEST2_PCICIE;
197749ab747fSPaolo Bonzini         break;
197849ab747fSPaolo Bonzini     case 0x1b: /* CTEST3 */
197949ab747fSPaolo Bonzini         s->ctest3 = val & 0x0f;
198049ab747fSPaolo Bonzini         break;
198149ab747fSPaolo Bonzini     CASE_SET_REG32(temp, 0x1c)
198249ab747fSPaolo Bonzini     case 0x21: /* CTEST4 */
198349ab747fSPaolo Bonzini         if (val & 7) {
1984c921370bSMark Cave-Ayland             qemu_log_mask(LOG_UNIMP,
1985c921370bSMark Cave-Ayland                           "lsi_scsi: Unimplemented CTEST4-FBL 0x%x\n", val);
198649ab747fSPaolo Bonzini         }
198749ab747fSPaolo Bonzini         s->ctest4 = val;
198849ab747fSPaolo Bonzini         break;
198949ab747fSPaolo Bonzini     case 0x22: /* CTEST5 */
199049ab747fSPaolo Bonzini         if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) {
1991c921370bSMark Cave-Ayland             qemu_log_mask(LOG_UNIMP,
1992c921370bSMark Cave-Ayland                           "lsi_scsi: CTEST5 DMA increment not implemented\n");
199349ab747fSPaolo Bonzini         }
199449ab747fSPaolo Bonzini         s->ctest5 = val;
199549ab747fSPaolo Bonzini         break;
199649ab747fSPaolo Bonzini     CASE_SET_REG24(dbc, 0x24)
199749ab747fSPaolo Bonzini     CASE_SET_REG32(dnad, 0x28)
199849ab747fSPaolo Bonzini     case 0x2c: /* DSP[0:7] */
199949ab747fSPaolo Bonzini         s->dsp &= 0xffffff00;
200049ab747fSPaolo Bonzini         s->dsp |= val;
200149ab747fSPaolo Bonzini         break;
200249ab747fSPaolo Bonzini     case 0x2d: /* DSP[8:15] */
200349ab747fSPaolo Bonzini         s->dsp &= 0xffff00ff;
200449ab747fSPaolo Bonzini         s->dsp |= val << 8;
200549ab747fSPaolo Bonzini         break;
200649ab747fSPaolo Bonzini     case 0x2e: /* DSP[16:23] */
200749ab747fSPaolo Bonzini         s->dsp &= 0xff00ffff;
200849ab747fSPaolo Bonzini         s->dsp |= val << 16;
200949ab747fSPaolo Bonzini         break;
201049ab747fSPaolo Bonzini     case 0x2f: /* DSP[24:31] */
201149ab747fSPaolo Bonzini         s->dsp &= 0x00ffffff;
201249ab747fSPaolo Bonzini         s->dsp |= val << 24;
2013de594e47SPaolo Bonzini         /*
2014de594e47SPaolo Bonzini          * FIXME: if s->waiting != LSI_NOWAIT, this will only execute one
2015de594e47SPaolo Bonzini          * instruction.  Is this correct?
2016de594e47SPaolo Bonzini          */
201749ab747fSPaolo Bonzini         if ((s->dmode & LSI_DMODE_MAN) == 0
201849ab747fSPaolo Bonzini             && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
201949ab747fSPaolo Bonzini             lsi_execute_script(s);
202049ab747fSPaolo Bonzini         break;
202149ab747fSPaolo Bonzini     CASE_SET_REG32(dsps, 0x30)
202249ab747fSPaolo Bonzini     CASE_SET_REG32(scratch[0], 0x34)
202349ab747fSPaolo Bonzini     case 0x38: /* DMODE */
202449ab747fSPaolo Bonzini         s->dmode = val;
202549ab747fSPaolo Bonzini         break;
202649ab747fSPaolo Bonzini     case 0x39: /* DIEN */
202749ab747fSPaolo Bonzini         s->dien = val;
202849ab747fSPaolo Bonzini         lsi_update_irq(s);
202949ab747fSPaolo Bonzini         break;
203049ab747fSPaolo Bonzini     case 0x3a: /* SBR */
203149ab747fSPaolo Bonzini         s->sbr = val;
203249ab747fSPaolo Bonzini         break;
203349ab747fSPaolo Bonzini     case 0x3b: /* DCNTL */
203449ab747fSPaolo Bonzini         s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD);
2035de594e47SPaolo Bonzini         /*
2036de594e47SPaolo Bonzini          * FIXME: if s->waiting != LSI_NOWAIT, this will only execute one
2037de594e47SPaolo Bonzini          * instruction.  Is this correct?
2038de594e47SPaolo Bonzini          */
203949ab747fSPaolo Bonzini         if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
204049ab747fSPaolo Bonzini             lsi_execute_script(s);
204149ab747fSPaolo Bonzini         break;
204249ab747fSPaolo Bonzini     case 0x40: /* SIEN0 */
204349ab747fSPaolo Bonzini         s->sien0 = val;
204449ab747fSPaolo Bonzini         lsi_update_irq(s);
204549ab747fSPaolo Bonzini         break;
204649ab747fSPaolo Bonzini     case 0x41: /* SIEN1 */
204749ab747fSPaolo Bonzini         s->sien1 = val;
204849ab747fSPaolo Bonzini         lsi_update_irq(s);
204949ab747fSPaolo Bonzini         break;
205049ab747fSPaolo Bonzini     case 0x47: /* GPCNTL0 */
205149ab747fSPaolo Bonzini         break;
205249ab747fSPaolo Bonzini     case 0x48: /* STIME0 */
205349ab747fSPaolo Bonzini         s->stime0 = val;
205449ab747fSPaolo Bonzini         break;
205549ab747fSPaolo Bonzini     case 0x49: /* STIME1 */
205649ab747fSPaolo Bonzini         if (val & 0xf) {
2057c921370bSMark Cave-Ayland             qemu_log_mask(LOG_UNIMP,
2058c921370bSMark Cave-Ayland                           "lsi_scsi: General purpose timer not implemented\n");
205949ab747fSPaolo Bonzini             /* ??? Raising the interrupt immediately seems to be sufficient
206049ab747fSPaolo Bonzini                to keep the FreeBSD driver happy.  */
206149ab747fSPaolo Bonzini             lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN);
206249ab747fSPaolo Bonzini         }
206349ab747fSPaolo Bonzini         break;
206449ab747fSPaolo Bonzini     case 0x4a: /* RESPID0 */
206549ab747fSPaolo Bonzini         s->respid0 = val;
206649ab747fSPaolo Bonzini         break;
206749ab747fSPaolo Bonzini     case 0x4b: /* RESPID1 */
206849ab747fSPaolo Bonzini         s->respid1 = val;
206949ab747fSPaolo Bonzini         break;
207049ab747fSPaolo Bonzini     case 0x4d: /* STEST1 */
207149ab747fSPaolo Bonzini         s->stest1 = val;
207249ab747fSPaolo Bonzini         break;
207349ab747fSPaolo Bonzini     case 0x4e: /* STEST2 */
207449ab747fSPaolo Bonzini         if (val & 1) {
2075c921370bSMark Cave-Ayland             qemu_log_mask(LOG_UNIMP,
2076c921370bSMark Cave-Ayland                           "lsi_scsi: Low level mode not implemented\n");
207749ab747fSPaolo Bonzini         }
207849ab747fSPaolo Bonzini         s->stest2 = val;
207949ab747fSPaolo Bonzini         break;
208049ab747fSPaolo Bonzini     case 0x4f: /* STEST3 */
208149ab747fSPaolo Bonzini         if (val & 0x41) {
2082c921370bSMark Cave-Ayland             qemu_log_mask(LOG_UNIMP,
2083c921370bSMark Cave-Ayland                           "lsi_scsi: SCSI FIFO test mode not implemented\n");
208449ab747fSPaolo Bonzini         }
208549ab747fSPaolo Bonzini         s->stest3 = val;
208649ab747fSPaolo Bonzini         break;
208749ab747fSPaolo Bonzini     case 0x56: /* CCNTL0 */
208849ab747fSPaolo Bonzini         s->ccntl0 = val;
208949ab747fSPaolo Bonzini         break;
209049ab747fSPaolo Bonzini     case 0x57: /* CCNTL1 */
209149ab747fSPaolo Bonzini         s->ccntl1 = val;
209249ab747fSPaolo Bonzini         break;
209349ab747fSPaolo Bonzini     CASE_SET_REG32(mmrs, 0xa0)
209449ab747fSPaolo Bonzini     CASE_SET_REG32(mmws, 0xa4)
209549ab747fSPaolo Bonzini     CASE_SET_REG32(sfs, 0xa8)
209649ab747fSPaolo Bonzini     CASE_SET_REG32(drs, 0xac)
209749ab747fSPaolo Bonzini     CASE_SET_REG32(sbms, 0xb0)
209849ab747fSPaolo Bonzini     CASE_SET_REG32(dbms, 0xb4)
209949ab747fSPaolo Bonzini     CASE_SET_REG32(dnad64, 0xb8)
210049ab747fSPaolo Bonzini     CASE_SET_REG32(pmjad1, 0xc0)
210149ab747fSPaolo Bonzini     CASE_SET_REG32(pmjad2, 0xc4)
210249ab747fSPaolo Bonzini     CASE_SET_REG32(rbc, 0xc8)
210349ab747fSPaolo Bonzini     CASE_SET_REG32(ua, 0xcc)
210449ab747fSPaolo Bonzini     CASE_SET_REG32(ia, 0xd4)
210549ab747fSPaolo Bonzini     CASE_SET_REG32(sbc, 0xd8)
210649ab747fSPaolo Bonzini     CASE_SET_REG32(csbc, 0xdc)
210749ab747fSPaolo Bonzini     default:
210849ab747fSPaolo Bonzini         if (offset >= 0x5c && offset < 0xa0) {
210949ab747fSPaolo Bonzini             int n;
211049ab747fSPaolo Bonzini             int shift;
211149ab747fSPaolo Bonzini             n = (offset - 0x58) >> 2;
211249ab747fSPaolo Bonzini             shift = (offset & 3) * 8;
211357ffcc4cSPeter Maydell             s->scratch[n] = deposit32(s->scratch[n], shift, 8, val);
211449ab747fSPaolo Bonzini         } else {
211585a20bc4SHervé Poussineau             qemu_log_mask(LOG_GUEST_ERROR,
211685a20bc4SHervé Poussineau                           "lsi_scsi: invalid write to reg %s %x (0x%02x)\n",
211785a20bc4SHervé Poussineau                           offset < ARRAY_SIZE(names) ? names[offset] : "???",
211885a20bc4SHervé Poussineau                           offset, val);
211949ab747fSPaolo Bonzini         }
212049ab747fSPaolo Bonzini     }
212149ab747fSPaolo Bonzini #undef CASE_SET_REG24
212249ab747fSPaolo Bonzini #undef CASE_SET_REG32
212349ab747fSPaolo Bonzini }
212449ab747fSPaolo Bonzini 
lsi_mmio_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)212549ab747fSPaolo Bonzini static void lsi_mmio_write(void *opaque, hwaddr addr,
212649ab747fSPaolo Bonzini                            uint64_t val, unsigned size)
212749ab747fSPaolo Bonzini {
212849ab747fSPaolo Bonzini     LSIState *s = opaque;
212949ab747fSPaolo Bonzini 
213049ab747fSPaolo Bonzini     lsi_reg_writeb(s, addr & 0xff, val);
213149ab747fSPaolo Bonzini }
213249ab747fSPaolo Bonzini 
lsi_mmio_read(void * opaque,hwaddr addr,unsigned size)213349ab747fSPaolo Bonzini static uint64_t lsi_mmio_read(void *opaque, hwaddr addr,
213449ab747fSPaolo Bonzini                               unsigned size)
213549ab747fSPaolo Bonzini {
213649ab747fSPaolo Bonzini     LSIState *s = opaque;
213749ab747fSPaolo Bonzini     return lsi_reg_readb(s, addr & 0xff);
213849ab747fSPaolo Bonzini }
213949ab747fSPaolo Bonzini 
214049ab747fSPaolo Bonzini static const MemoryRegionOps lsi_mmio_ops = {
214149ab747fSPaolo Bonzini     .read = lsi_mmio_read,
214249ab747fSPaolo Bonzini     .write = lsi_mmio_write,
2143e6c165f3SSven Schnelle     .endianness = DEVICE_LITTLE_ENDIAN,
214449ab747fSPaolo Bonzini     .impl = {
214549ab747fSPaolo Bonzini         .min_access_size = 1,
214649ab747fSPaolo Bonzini         .max_access_size = 1,
214749ab747fSPaolo Bonzini     },
214849ab747fSPaolo Bonzini };
214949ab747fSPaolo Bonzini 
lsi_ram_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)215049ab747fSPaolo Bonzini static void lsi_ram_write(void *opaque, hwaddr addr,
215149ab747fSPaolo Bonzini                           uint64_t val, unsigned size)
215249ab747fSPaolo Bonzini {
215349ab747fSPaolo Bonzini     LSIState *s = opaque;
2154811a75baSSven Schnelle     stn_le_p(s->script_ram + addr, size, val);
215549ab747fSPaolo Bonzini }
215649ab747fSPaolo Bonzini 
lsi_ram_read(void * opaque,hwaddr addr,unsigned size)215749ab747fSPaolo Bonzini static uint64_t lsi_ram_read(void *opaque, hwaddr addr,
215849ab747fSPaolo Bonzini                              unsigned size)
215949ab747fSPaolo Bonzini {
216049ab747fSPaolo Bonzini     LSIState *s = opaque;
2161811a75baSSven Schnelle     return ldn_le_p(s->script_ram + addr, size);
216249ab747fSPaolo Bonzini }
216349ab747fSPaolo Bonzini 
216449ab747fSPaolo Bonzini static const MemoryRegionOps lsi_ram_ops = {
216549ab747fSPaolo Bonzini     .read = lsi_ram_read,
216649ab747fSPaolo Bonzini     .write = lsi_ram_write,
2167e6c165f3SSven Schnelle     .endianness = DEVICE_LITTLE_ENDIAN,
216849ab747fSPaolo Bonzini };
216949ab747fSPaolo Bonzini 
lsi_io_read(void * opaque,hwaddr addr,unsigned size)217049ab747fSPaolo Bonzini static uint64_t lsi_io_read(void *opaque, hwaddr addr,
217149ab747fSPaolo Bonzini                             unsigned size)
217249ab747fSPaolo Bonzini {
217349ab747fSPaolo Bonzini     LSIState *s = opaque;
217449ab747fSPaolo Bonzini     return lsi_reg_readb(s, addr & 0xff);
217549ab747fSPaolo Bonzini }
217649ab747fSPaolo Bonzini 
lsi_io_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)217749ab747fSPaolo Bonzini static void lsi_io_write(void *opaque, hwaddr addr,
217849ab747fSPaolo Bonzini                          uint64_t val, unsigned size)
217949ab747fSPaolo Bonzini {
218049ab747fSPaolo Bonzini     LSIState *s = opaque;
218149ab747fSPaolo Bonzini     lsi_reg_writeb(s, addr & 0xff, val);
218249ab747fSPaolo Bonzini }
218349ab747fSPaolo Bonzini 
218449ab747fSPaolo Bonzini static const MemoryRegionOps lsi_io_ops = {
218549ab747fSPaolo Bonzini     .read = lsi_io_read,
218649ab747fSPaolo Bonzini     .write = lsi_io_write,
2187e6c165f3SSven Schnelle     .endianness = DEVICE_LITTLE_ENDIAN,
218849ab747fSPaolo Bonzini     .impl = {
218949ab747fSPaolo Bonzini         .min_access_size = 1,
219049ab747fSPaolo Bonzini         .max_access_size = 1,
219149ab747fSPaolo Bonzini     },
219249ab747fSPaolo Bonzini };
219349ab747fSPaolo Bonzini 
lsi_scsi_reset(DeviceState * dev)219449ab747fSPaolo Bonzini static void lsi_scsi_reset(DeviceState *dev)
219549ab747fSPaolo Bonzini {
219671186c86SPeter Crosthwaite     LSIState *s = LSI53C895A(dev);
219749ab747fSPaolo Bonzini 
219849ab747fSPaolo Bonzini     lsi_soft_reset(s);
219949ab747fSPaolo Bonzini }
220049ab747fSPaolo Bonzini 
lsi_pre_save(void * opaque)220144b1ff31SDr. David Alan Gilbert static int lsi_pre_save(void *opaque)
220249ab747fSPaolo Bonzini {
220349ab747fSPaolo Bonzini     LSIState *s = opaque;
220449ab747fSPaolo Bonzini 
220549ab747fSPaolo Bonzini     if (s->current) {
220649ab747fSPaolo Bonzini         assert(s->current->dma_buf == NULL);
220749ab747fSPaolo Bonzini         assert(s->current->dma_len == 0);
220849ab747fSPaolo Bonzini     }
220949ab747fSPaolo Bonzini     assert(QTAILQ_EMPTY(&s->queue));
221044b1ff31SDr. David Alan Gilbert 
221144b1ff31SDr. David Alan Gilbert     return 0;
221249ab747fSPaolo Bonzini }
221349ab747fSPaolo Bonzini 
lsi_post_load(void * opaque,int version_id)2214e58ccf03SPrasad J Pandit static int lsi_post_load(void *opaque, int version_id)
2215e58ccf03SPrasad J Pandit {
2216e58ccf03SPrasad J Pandit     LSIState *s = opaque;
2217e58ccf03SPrasad J Pandit 
2218e58ccf03SPrasad J Pandit     if (s->msg_len < 0 || s->msg_len > LSI_MAX_MSGIN_LEN) {
2219e58ccf03SPrasad J Pandit         return -EINVAL;
2220e58ccf03SPrasad J Pandit     }
2221e58ccf03SPrasad J Pandit 
222298763599SSven Schnelle     if (s->waiting == LSI_WAIT_SCRIPTS) {
222398763599SSven Schnelle         lsi_scripts_timer_start(s);
222498763599SSven Schnelle     }
2225e58ccf03SPrasad J Pandit     return 0;
2226e58ccf03SPrasad J Pandit }
2227e58ccf03SPrasad J Pandit 
222849ab747fSPaolo Bonzini static const VMStateDescription vmstate_lsi_scsi = {
222949ab747fSPaolo Bonzini     .name = "lsiscsi",
223012dd89f7SSven Schnelle     .version_id = 1,
223149ab747fSPaolo Bonzini     .minimum_version_id = 0,
223249ab747fSPaolo Bonzini     .pre_save = lsi_pre_save,
2233e58ccf03SPrasad J Pandit     .post_load = lsi_post_load,
22342d7b39a6SRichard Henderson     .fields = (const VMStateField[]) {
2235725eec70SAndreas Färber         VMSTATE_PCI_DEVICE(parent_obj, LSIState),
223649ab747fSPaolo Bonzini 
223749ab747fSPaolo Bonzini         VMSTATE_INT32(carry, LSIState),
223849ab747fSPaolo Bonzini         VMSTATE_INT32(status, LSIState),
223949ab747fSPaolo Bonzini         VMSTATE_INT32(msg_action, LSIState),
224049ab747fSPaolo Bonzini         VMSTATE_INT32(msg_len, LSIState),
224149ab747fSPaolo Bonzini         VMSTATE_BUFFER(msg, LSIState),
224249ab747fSPaolo Bonzini         VMSTATE_INT32(waiting, LSIState),
224349ab747fSPaolo Bonzini 
224449ab747fSPaolo Bonzini         VMSTATE_UINT32(dsa, LSIState),
224549ab747fSPaolo Bonzini         VMSTATE_UINT32(temp, LSIState),
224649ab747fSPaolo Bonzini         VMSTATE_UINT32(dnad, LSIState),
224749ab747fSPaolo Bonzini         VMSTATE_UINT32(dbc, LSIState),
224849ab747fSPaolo Bonzini         VMSTATE_UINT8(istat0, LSIState),
224949ab747fSPaolo Bonzini         VMSTATE_UINT8(istat1, LSIState),
225049ab747fSPaolo Bonzini         VMSTATE_UINT8(dcmd, LSIState),
225149ab747fSPaolo Bonzini         VMSTATE_UINT8(dstat, LSIState),
225249ab747fSPaolo Bonzini         VMSTATE_UINT8(dien, LSIState),
225349ab747fSPaolo Bonzini         VMSTATE_UINT8(sist0, LSIState),
225449ab747fSPaolo Bonzini         VMSTATE_UINT8(sist1, LSIState),
225549ab747fSPaolo Bonzini         VMSTATE_UINT8(sien0, LSIState),
225649ab747fSPaolo Bonzini         VMSTATE_UINT8(sien1, LSIState),
225749ab747fSPaolo Bonzini         VMSTATE_UINT8(mbox0, LSIState),
225849ab747fSPaolo Bonzini         VMSTATE_UINT8(mbox1, LSIState),
225949ab747fSPaolo Bonzini         VMSTATE_UINT8(dfifo, LSIState),
226049ab747fSPaolo Bonzini         VMSTATE_UINT8(ctest2, LSIState),
226149ab747fSPaolo Bonzini         VMSTATE_UINT8(ctest3, LSIState),
226249ab747fSPaolo Bonzini         VMSTATE_UINT8(ctest4, LSIState),
226349ab747fSPaolo Bonzini         VMSTATE_UINT8(ctest5, LSIState),
226449ab747fSPaolo Bonzini         VMSTATE_UINT8(ccntl0, LSIState),
226549ab747fSPaolo Bonzini         VMSTATE_UINT8(ccntl1, LSIState),
226649ab747fSPaolo Bonzini         VMSTATE_UINT32(dsp, LSIState),
226749ab747fSPaolo Bonzini         VMSTATE_UINT32(dsps, LSIState),
226849ab747fSPaolo Bonzini         VMSTATE_UINT8(dmode, LSIState),
226949ab747fSPaolo Bonzini         VMSTATE_UINT8(dcntl, LSIState),
227049ab747fSPaolo Bonzini         VMSTATE_UINT8(scntl0, LSIState),
227149ab747fSPaolo Bonzini         VMSTATE_UINT8(scntl1, LSIState),
227249ab747fSPaolo Bonzini         VMSTATE_UINT8(scntl2, LSIState),
227349ab747fSPaolo Bonzini         VMSTATE_UINT8(scntl3, LSIState),
227449ab747fSPaolo Bonzini         VMSTATE_UINT8(sstat0, LSIState),
227549ab747fSPaolo Bonzini         VMSTATE_UINT8(sstat1, LSIState),
227649ab747fSPaolo Bonzini         VMSTATE_UINT8(scid, LSIState),
227749ab747fSPaolo Bonzini         VMSTATE_UINT8(sxfer, LSIState),
227849ab747fSPaolo Bonzini         VMSTATE_UINT8(socl, LSIState),
227949ab747fSPaolo Bonzini         VMSTATE_UINT8(sdid, LSIState),
228049ab747fSPaolo Bonzini         VMSTATE_UINT8(ssid, LSIState),
228149ab747fSPaolo Bonzini         VMSTATE_UINT8(sfbr, LSIState),
228249ab747fSPaolo Bonzini         VMSTATE_UINT8(stest1, LSIState),
228349ab747fSPaolo Bonzini         VMSTATE_UINT8(stest2, LSIState),
228449ab747fSPaolo Bonzini         VMSTATE_UINT8(stest3, LSIState),
228549ab747fSPaolo Bonzini         VMSTATE_UINT8(sidl, LSIState),
228649ab747fSPaolo Bonzini         VMSTATE_UINT8(stime0, LSIState),
228749ab747fSPaolo Bonzini         VMSTATE_UINT8(respid0, LSIState),
228849ab747fSPaolo Bonzini         VMSTATE_UINT8(respid1, LSIState),
228912dd89f7SSven Schnelle         VMSTATE_UINT8_V(sbcl, LSIState, 1),
229049ab747fSPaolo Bonzini         VMSTATE_UINT32(mmrs, LSIState),
229149ab747fSPaolo Bonzini         VMSTATE_UINT32(mmws, LSIState),
229249ab747fSPaolo Bonzini         VMSTATE_UINT32(sfs, LSIState),
229349ab747fSPaolo Bonzini         VMSTATE_UINT32(drs, LSIState),
229449ab747fSPaolo Bonzini         VMSTATE_UINT32(sbms, LSIState),
229549ab747fSPaolo Bonzini         VMSTATE_UINT32(dbms, LSIState),
229649ab747fSPaolo Bonzini         VMSTATE_UINT32(dnad64, LSIState),
229749ab747fSPaolo Bonzini         VMSTATE_UINT32(pmjad1, LSIState),
229849ab747fSPaolo Bonzini         VMSTATE_UINT32(pmjad2, LSIState),
229949ab747fSPaolo Bonzini         VMSTATE_UINT32(rbc, LSIState),
230049ab747fSPaolo Bonzini         VMSTATE_UINT32(ua, LSIState),
230149ab747fSPaolo Bonzini         VMSTATE_UINT32(ia, LSIState),
230249ab747fSPaolo Bonzini         VMSTATE_UINT32(sbc, LSIState),
230349ab747fSPaolo Bonzini         VMSTATE_UINT32(csbc, LSIState),
230449ab747fSPaolo Bonzini         VMSTATE_BUFFER_UNSAFE(scratch, LSIState, 0, 18 * sizeof(uint32_t)),
230549ab747fSPaolo Bonzini         VMSTATE_UINT8(sbr, LSIState),
230649ab747fSPaolo Bonzini 
2307811a75baSSven Schnelle         VMSTATE_BUFFER_UNSAFE(script_ram, LSIState, 0, 8192),
230849ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
230949ab747fSPaolo Bonzini     }
231049ab747fSPaolo Bonzini };
231149ab747fSPaolo Bonzini 
231249ab747fSPaolo Bonzini static const struct SCSIBusInfo lsi_scsi_info = {
231349ab747fSPaolo Bonzini     .tcq = true,
231449ab747fSPaolo Bonzini     .max_target = LSI_MAX_DEVS,
231549ab747fSPaolo Bonzini     .max_lun = 0,  /* LUN support is buggy */
231649ab747fSPaolo Bonzini 
231749ab747fSPaolo Bonzini     .transfer_data = lsi_transfer_data,
231849ab747fSPaolo Bonzini     .complete = lsi_command_complete,
231949ab747fSPaolo Bonzini     .cancel = lsi_request_cancelled
232049ab747fSPaolo Bonzini };
232149ab747fSPaolo Bonzini 
scripts_timer_cb(void * opaque)232298763599SSven Schnelle static void scripts_timer_cb(void *opaque)
232398763599SSven Schnelle {
232498763599SSven Schnelle     LSIState *s = opaque;
232598763599SSven Schnelle 
232698763599SSven Schnelle     trace_lsi_scripts_timer_triggered();
232798763599SSven Schnelle     s->waiting = LSI_NOWAIT;
232898763599SSven Schnelle     lsi_execute_script(s);
232998763599SSven Schnelle }
233098763599SSven Schnelle 
lsi_scsi_realize(PCIDevice * dev,Error ** errp)2331ae071cc8SMarkus Armbruster static void lsi_scsi_realize(PCIDevice *dev, Error **errp)
233249ab747fSPaolo Bonzini {
233371186c86SPeter Crosthwaite     LSIState *s = LSI53C895A(dev);
233471186c86SPeter Crosthwaite     DeviceState *d = DEVICE(dev);
233549ab747fSPaolo Bonzini     uint8_t *pci_conf;
233649ab747fSPaolo Bonzini 
2337725eec70SAndreas Färber     pci_conf = dev->config;
233849ab747fSPaolo Bonzini 
233949ab747fSPaolo Bonzini     /* PCI latency timer = 255 */
234049ab747fSPaolo Bonzini     pci_conf[PCI_LATENCY_TIMER] = 0xff;
234149ab747fSPaolo Bonzini     /* Interrupt pin A */
234249ab747fSPaolo Bonzini     pci_conf[PCI_INTERRUPT_PIN] = 0x01;
234349ab747fSPaolo Bonzini 
234429776739SPaolo Bonzini     memory_region_init_io(&s->mmio_io, OBJECT(s), &lsi_mmio_ops, s,
234529776739SPaolo Bonzini                           "lsi-mmio", 0x400);
234629776739SPaolo Bonzini     memory_region_init_io(&s->ram_io, OBJECT(s), &lsi_ram_ops, s,
234729776739SPaolo Bonzini                           "lsi-ram", 0x2000);
234829776739SPaolo Bonzini     memory_region_init_io(&s->io_io, OBJECT(s), &lsi_io_ops, s,
234929776739SPaolo Bonzini                           "lsi-io", 256);
235098763599SSven Schnelle     s->scripts_timer = timer_new_us(QEMU_CLOCK_VIRTUAL, scripts_timer_cb, s);
235149ab747fSPaolo Bonzini 
2352bfd6e7aeSAlexander Bulekov     /*
2353bfd6e7aeSAlexander Bulekov      * Since we use the address-space API to interact with ram_io, disable the
2354bfd6e7aeSAlexander Bulekov      * re-entrancy guard.
2355bfd6e7aeSAlexander Bulekov      */
2356bfd6e7aeSAlexander Bulekov     s->ram_io.disable_reentrancy_guard = true;
2357d139fe9aSThomas Huth     s->mmio_io.disable_reentrancy_guard = true;
2358bfd6e7aeSAlexander Bulekov 
2359a8632434SHervé Poussineau     address_space_init(&s->pci_io_as, pci_address_space_io(dev), "lsi-pci-io");
23603cc1b9cbSMark Cave-Ayland     qdev_init_gpio_out(d, &s->ext_irq, 1);
2361a8632434SHervé Poussineau 
2362725eec70SAndreas Färber     pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io);
236316b8ed1dSHervé Poussineau     pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_io);
2364725eec70SAndreas Färber     pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
236549ab747fSPaolo Bonzini     QTAILQ_INIT(&s->queue);
236649ab747fSPaolo Bonzini 
2367739e95f5SPeter Maydell     scsi_bus_init(&s->bus, sizeof(s->bus), d, &lsi_scsi_info);
236849ab747fSPaolo Bonzini }
236949ab747fSPaolo Bonzini 
lsi_scsi_exit(PCIDevice * dev)2370faabca42SPeng Liang static void lsi_scsi_exit(PCIDevice *dev)
2371a8632434SHervé Poussineau {
2372a8632434SHervé Poussineau     LSIState *s = LSI53C895A(dev);
2373a8632434SHervé Poussineau 
2374a8632434SHervé Poussineau     address_space_destroy(&s->pci_io_as);
237598763599SSven Schnelle     timer_del(s->scripts_timer);
2376a8632434SHervé Poussineau }
2377a8632434SHervé Poussineau 
lsi_class_init(ObjectClass * klass,void * data)237849ab747fSPaolo Bonzini static void lsi_class_init(ObjectClass *klass, void *data)
237949ab747fSPaolo Bonzini {
238049ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
238149ab747fSPaolo Bonzini     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
238249ab747fSPaolo Bonzini 
2383ae071cc8SMarkus Armbruster     k->realize = lsi_scsi_realize;
2384faabca42SPeng Liang     k->exit = lsi_scsi_exit;
238549ab747fSPaolo Bonzini     k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
238649ab747fSPaolo Bonzini     k->device_id = PCI_DEVICE_ID_LSI_53C895A;
238749ab747fSPaolo Bonzini     k->class_id = PCI_CLASS_STORAGE_SCSI;
238849ab747fSPaolo Bonzini     k->subsystem_id = 0x1000;
2389*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, lsi_scsi_reset);
239049ab747fSPaolo Bonzini     dc->vmsd = &vmstate_lsi_scsi;
2391125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
239249ab747fSPaolo Bonzini }
239349ab747fSPaolo Bonzini 
239449ab747fSPaolo Bonzini static const TypeInfo lsi_info = {
239571186c86SPeter Crosthwaite     .name          = TYPE_LSI53C895A,
239649ab747fSPaolo Bonzini     .parent        = TYPE_PCI_DEVICE,
239749ab747fSPaolo Bonzini     .instance_size = sizeof(LSIState),
239849ab747fSPaolo Bonzini     .class_init    = lsi_class_init,
2399fd3b02c8SEduardo Habkost     .interfaces = (InterfaceInfo[]) {
2400fd3b02c8SEduardo Habkost         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
2401fd3b02c8SEduardo Habkost         { },
2402fd3b02c8SEduardo Habkost     },
240349ab747fSPaolo Bonzini };
240449ab747fSPaolo Bonzini 
lsi53c810_class_init(ObjectClass * klass,void * data)2405ceae18bdSHervé Poussineau static void lsi53c810_class_init(ObjectClass *klass, void *data)
2406ceae18bdSHervé Poussineau {
2407ceae18bdSHervé Poussineau     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
2408ceae18bdSHervé Poussineau 
2409ceae18bdSHervé Poussineau     k->device_id = PCI_DEVICE_ID_LSI_53C810;
2410ceae18bdSHervé Poussineau }
2411ceae18bdSHervé Poussineau 
24125e78c98bSBernhard Beschow static const TypeInfo lsi53c810_info = {
2413ceae18bdSHervé Poussineau     .name          = TYPE_LSI53C810,
2414ceae18bdSHervé Poussineau     .parent        = TYPE_LSI53C895A,
2415ceae18bdSHervé Poussineau     .class_init    = lsi53c810_class_init,
2416ceae18bdSHervé Poussineau };
2417ceae18bdSHervé Poussineau 
lsi53c895a_register_types(void)241849ab747fSPaolo Bonzini static void lsi53c895a_register_types(void)
241949ab747fSPaolo Bonzini {
242049ab747fSPaolo Bonzini     type_register_static(&lsi_info);
2421ceae18bdSHervé Poussineau     type_register_static(&lsi53c810_info);
242249ab747fSPaolo Bonzini }
242349ab747fSPaolo Bonzini 
type_init(lsi53c895a_register_types)242449ab747fSPaolo Bonzini type_init(lsi53c895a_register_types)
2425a64aa578SMarkus Armbruster 
2426f74a4f3aSMark Cave-Ayland void lsi53c8xx_handle_legacy_cmdline(DeviceState *lsi_dev)
2427f74a4f3aSMark Cave-Ayland {
2428f74a4f3aSMark Cave-Ayland     LSIState *s = LSI53C895A(lsi_dev);
2429f74a4f3aSMark Cave-Ayland 
2430f74a4f3aSMark Cave-Ayland     scsi_bus_legacy_handle_cmdline(&s->bus);
2431f74a4f3aSMark Cave-Ayland }
2432