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