16f7e9aecSbellard /* 267e999beSbellard * QEMU ESP/NCR53C9x emulation 36f7e9aecSbellard * 44e9aec74Spbrook * Copyright (c) 2005-2006 Fabrice Bellard 5fabaaf1dSHervé Poussineau * Copyright (c) 2012 Herve Poussineau 66f7e9aecSbellard * 76f7e9aecSbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 86f7e9aecSbellard * of this software and associated documentation files (the "Software"), to deal 96f7e9aecSbellard * in the Software without restriction, including without limitation the rights 106f7e9aecSbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 116f7e9aecSbellard * copies of the Software, and to permit persons to whom the Software is 126f7e9aecSbellard * furnished to do so, subject to the following conditions: 136f7e9aecSbellard * 146f7e9aecSbellard * The above copyright notice and this permission notice shall be included in 156f7e9aecSbellard * all copies or substantial portions of the Software. 166f7e9aecSbellard * 176f7e9aecSbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 186f7e9aecSbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 196f7e9aecSbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 206f7e9aecSbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 216f7e9aecSbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 226f7e9aecSbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 236f7e9aecSbellard * THE SOFTWARE. 246f7e9aecSbellard */ 255d20fa6bSblueswir1 26a4ab4792SPeter Maydell #include "qemu/osdep.h" 2783c9f4caSPaolo Bonzini #include "hw/sysbus.h" 28d6454270SMarkus Armbruster #include "migration/vmstate.h" 2964552b6bSMarkus Armbruster #include "hw/irq.h" 300d09e41aSPaolo Bonzini #include "hw/scsi/esp.h" 31bf4b9889SBlue Swirl #include "trace.h" 321de7afc9SPaolo Bonzini #include "qemu/log.h" 330b8fa32fSMarkus Armbruster #include "qemu/module.h" 346f7e9aecSbellard 3567e999beSbellard /* 365ad6bb97Sblueswir1 * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O), 375ad6bb97Sblueswir1 * also produced as NCR89C100. See 3867e999beSbellard * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt 3967e999beSbellard * and 4067e999beSbellard * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt 4174d71ea1SLaurent Vivier * 4274d71ea1SLaurent Vivier * On Macintosh Quadra it is a NCR53C96. 4367e999beSbellard */ 4467e999beSbellard 45c73f96fdSblueswir1 static void esp_raise_irq(ESPState *s) 46c73f96fdSblueswir1 { 47c73f96fdSblueswir1 if (!(s->rregs[ESP_RSTAT] & STAT_INT)) { 48c73f96fdSblueswir1 s->rregs[ESP_RSTAT] |= STAT_INT; 49c73f96fdSblueswir1 qemu_irq_raise(s->irq); 50bf4b9889SBlue Swirl trace_esp_raise_irq(); 51c73f96fdSblueswir1 } 52c73f96fdSblueswir1 } 53c73f96fdSblueswir1 54c73f96fdSblueswir1 static void esp_lower_irq(ESPState *s) 55c73f96fdSblueswir1 { 56c73f96fdSblueswir1 if (s->rregs[ESP_RSTAT] & STAT_INT) { 57c73f96fdSblueswir1 s->rregs[ESP_RSTAT] &= ~STAT_INT; 58c73f96fdSblueswir1 qemu_irq_lower(s->irq); 59bf4b9889SBlue Swirl trace_esp_lower_irq(); 60c73f96fdSblueswir1 } 61c73f96fdSblueswir1 } 62c73f96fdSblueswir1 6374d71ea1SLaurent Vivier static void esp_raise_drq(ESPState *s) 6474d71ea1SLaurent Vivier { 6574d71ea1SLaurent Vivier qemu_irq_raise(s->irq_data); 66960ebfd9SMark Cave-Ayland trace_esp_raise_drq(); 6774d71ea1SLaurent Vivier } 6874d71ea1SLaurent Vivier 6974d71ea1SLaurent Vivier static void esp_lower_drq(ESPState *s) 7074d71ea1SLaurent Vivier { 7174d71ea1SLaurent Vivier qemu_irq_lower(s->irq_data); 72960ebfd9SMark Cave-Ayland trace_esp_lower_drq(); 7374d71ea1SLaurent Vivier } 7474d71ea1SLaurent Vivier 759c7e23fcSHervé Poussineau void esp_dma_enable(ESPState *s, int irq, int level) 7673d74342SBlue Swirl { 7773d74342SBlue Swirl if (level) { 7873d74342SBlue Swirl s->dma_enabled = 1; 79bf4b9889SBlue Swirl trace_esp_dma_enable(); 8073d74342SBlue Swirl if (s->dma_cb) { 8173d74342SBlue Swirl s->dma_cb(s); 8273d74342SBlue Swirl s->dma_cb = NULL; 8373d74342SBlue Swirl } 8473d74342SBlue Swirl } else { 85bf4b9889SBlue Swirl trace_esp_dma_disable(); 8673d74342SBlue Swirl s->dma_enabled = 0; 8773d74342SBlue Swirl } 8873d74342SBlue Swirl } 8973d74342SBlue Swirl 909c7e23fcSHervé Poussineau void esp_request_cancelled(SCSIRequest *req) 9194d3f98aSPaolo Bonzini { 92e6810db8SHervé Poussineau ESPState *s = req->hba_private; 9394d3f98aSPaolo Bonzini 9494d3f98aSPaolo Bonzini if (req == s->current_req) { 9594d3f98aSPaolo Bonzini scsi_req_unref(s->current_req); 9694d3f98aSPaolo Bonzini s->current_req = NULL; 9794d3f98aSPaolo Bonzini s->current_dev = NULL; 9894d3f98aSPaolo Bonzini } 9994d3f98aSPaolo Bonzini } 10094d3f98aSPaolo Bonzini 101c47b5835SMark Cave-Ayland static uint32_t esp_get_tc(ESPState *s) 102c47b5835SMark Cave-Ayland { 103c47b5835SMark Cave-Ayland uint32_t dmalen; 104c47b5835SMark Cave-Ayland 105c47b5835SMark Cave-Ayland dmalen = s->rregs[ESP_TCLO]; 106c47b5835SMark Cave-Ayland dmalen |= s->rregs[ESP_TCMID] << 8; 107c47b5835SMark Cave-Ayland dmalen |= s->rregs[ESP_TCHI] << 16; 108c47b5835SMark Cave-Ayland 109c47b5835SMark Cave-Ayland return dmalen; 110c47b5835SMark Cave-Ayland } 111c47b5835SMark Cave-Ayland 112c47b5835SMark Cave-Ayland static void esp_set_tc(ESPState *s, uint32_t dmalen) 113c47b5835SMark Cave-Ayland { 114c47b5835SMark Cave-Ayland s->rregs[ESP_TCLO] = dmalen; 115c47b5835SMark Cave-Ayland s->rregs[ESP_TCMID] = dmalen >> 8; 116c47b5835SMark Cave-Ayland s->rregs[ESP_TCHI] = dmalen >> 16; 117c47b5835SMark Cave-Ayland } 118c47b5835SMark Cave-Ayland 119c04ed569SMark Cave-Ayland static uint32_t esp_get_stc(ESPState *s) 120c04ed569SMark Cave-Ayland { 121c04ed569SMark Cave-Ayland uint32_t dmalen; 122c04ed569SMark Cave-Ayland 123c04ed569SMark Cave-Ayland dmalen = s->wregs[ESP_TCLO]; 124c04ed569SMark Cave-Ayland dmalen |= s->wregs[ESP_TCMID] << 8; 125c04ed569SMark Cave-Ayland dmalen |= s->wregs[ESP_TCHI] << 16; 126c04ed569SMark Cave-Ayland 127c04ed569SMark Cave-Ayland return dmalen; 128c04ed569SMark Cave-Ayland } 129c04ed569SMark Cave-Ayland 1303c421400SMark Cave-Ayland static void set_pdma(ESPState *s, enum pdma_origin_id origin) 13174d71ea1SLaurent Vivier { 13274d71ea1SLaurent Vivier s->pdma_origin = origin; 13374d71ea1SLaurent Vivier } 13474d71ea1SLaurent Vivier 135761bef75SMark Cave-Ayland static uint8_t esp_pdma_read(ESPState *s) 136761bef75SMark Cave-Ayland { 1378da90e81SMark Cave-Ayland uint32_t dmalen = esp_get_tc(s); 1388da90e81SMark Cave-Ayland uint8_t val; 1398da90e81SMark Cave-Ayland 1403c421400SMark Cave-Ayland if (dmalen == 0) { 1418da90e81SMark Cave-Ayland return 0; 1428da90e81SMark Cave-Ayland } 1438da90e81SMark Cave-Ayland 1446e3fafa8SMark Cave-Ayland switch (s->pdma_origin) { 1456e3fafa8SMark Cave-Ayland case TI: 14602abe246SMark Cave-Ayland if (s->do_cmd) { 147bb0bc7bbSMark Cave-Ayland val = s->cmdbuf[s->cmdlen++]; 14802abe246SMark Cave-Ayland } else { 14902abe246SMark Cave-Ayland val = s->ti_buf[s->ti_rptr++]; 15002abe246SMark Cave-Ayland } 1518da90e81SMark Cave-Ayland break; 1526e3fafa8SMark Cave-Ayland case ASYNC: 15393efe2e6SMark Cave-Ayland val = s->async_buf[0]; 15493efe2e6SMark Cave-Ayland if (s->async_len > 0) { 15593efe2e6SMark Cave-Ayland s->async_len--; 15693efe2e6SMark Cave-Ayland s->async_buf++; 15793efe2e6SMark Cave-Ayland } 1588da90e81SMark Cave-Ayland break; 1596e3fafa8SMark Cave-Ayland default: 1606e3fafa8SMark Cave-Ayland g_assert_not_reached(); 1616e3fafa8SMark Cave-Ayland } 1628da90e81SMark Cave-Ayland 16393efe2e6SMark Cave-Ayland s->ti_size--; 1648da90e81SMark Cave-Ayland dmalen--; 1658da90e81SMark Cave-Ayland esp_set_tc(s, dmalen); 1668da90e81SMark Cave-Ayland 1678da90e81SMark Cave-Ayland return val; 168761bef75SMark Cave-Ayland } 169761bef75SMark Cave-Ayland 170761bef75SMark Cave-Ayland static void esp_pdma_write(ESPState *s, uint8_t val) 171761bef75SMark Cave-Ayland { 1728da90e81SMark Cave-Ayland uint32_t dmalen = esp_get_tc(s); 1738da90e81SMark Cave-Ayland 1743c421400SMark Cave-Ayland if (dmalen == 0) { 1758da90e81SMark Cave-Ayland return; 1768da90e81SMark Cave-Ayland } 1778da90e81SMark Cave-Ayland 1786e3fafa8SMark Cave-Ayland switch (s->pdma_origin) { 1796e3fafa8SMark Cave-Ayland case TI: 18002abe246SMark Cave-Ayland if (s->do_cmd) { 181bb0bc7bbSMark Cave-Ayland s->cmdbuf[s->cmdlen++] = val; 18202abe246SMark Cave-Ayland } else { 18302abe246SMark Cave-Ayland s->ti_buf[s->ti_wptr++] = val; 18402abe246SMark Cave-Ayland } 1856e3fafa8SMark Cave-Ayland break; 1866e3fafa8SMark Cave-Ayland case ASYNC: 18793efe2e6SMark Cave-Ayland s->async_buf[0] = val; 18893efe2e6SMark Cave-Ayland if (s->async_len > 0) { 18993efe2e6SMark Cave-Ayland s->async_len--; 19093efe2e6SMark Cave-Ayland s->async_buf++; 19193efe2e6SMark Cave-Ayland } 1926e3fafa8SMark Cave-Ayland break; 1936e3fafa8SMark Cave-Ayland default: 1946e3fafa8SMark Cave-Ayland g_assert_not_reached(); 1956e3fafa8SMark Cave-Ayland } 1968da90e81SMark Cave-Ayland 19793efe2e6SMark Cave-Ayland s->ti_size++; 1988da90e81SMark Cave-Ayland dmalen--; 1998da90e81SMark Cave-Ayland esp_set_tc(s, dmalen); 200761bef75SMark Cave-Ayland } 201761bef75SMark Cave-Ayland 202*c7bce09cSMark Cave-Ayland static int esp_select(ESPState *s) 2036130b188SLaurent Vivier { 2046130b188SLaurent Vivier int target; 2056130b188SLaurent Vivier 2066130b188SLaurent Vivier target = s->wregs[ESP_WBUSID] & BUSID_DID; 2076130b188SLaurent Vivier 2086130b188SLaurent Vivier s->ti_size = 0; 2096130b188SLaurent Vivier s->ti_rptr = 0; 2106130b188SLaurent Vivier s->ti_wptr = 0; 2116130b188SLaurent Vivier 2126130b188SLaurent Vivier if (s->current_req) { 2136130b188SLaurent Vivier /* Started a new command before the old one finished. Cancel it. */ 2146130b188SLaurent Vivier scsi_req_cancel(s->current_req); 2156130b188SLaurent Vivier s->async_len = 0; 2166130b188SLaurent Vivier } 2176130b188SLaurent Vivier 2186130b188SLaurent Vivier s->current_dev = scsi_device_find(&s->bus, 0, target, 0); 2196130b188SLaurent Vivier if (!s->current_dev) { 2206130b188SLaurent Vivier /* No such drive */ 2216130b188SLaurent Vivier s->rregs[ESP_RSTAT] = 0; 2226130b188SLaurent Vivier s->rregs[ESP_RINTR] = INTR_DC; 2236130b188SLaurent Vivier s->rregs[ESP_RSEQ] = SEQ_0; 2246130b188SLaurent Vivier esp_raise_irq(s); 2256130b188SLaurent Vivier return -1; 2266130b188SLaurent Vivier } 2276130b188SLaurent Vivier return 0; 2286130b188SLaurent Vivier } 2296130b188SLaurent Vivier 230cfcea0f9SMark Cave-Ayland static uint32_t get_cmd(ESPState *s) 2312f275b8fSbellard { 232cfcea0f9SMark Cave-Ayland uint8_t *buf = s->cmdbuf; 233a917d384Spbrook uint32_t dmalen; 2342f275b8fSbellard int target; 2352f275b8fSbellard 2368dea1dd4Sblueswir1 target = s->wregs[ESP_WBUSID] & BUSID_DID; 2374f6200f0Sbellard if (s->dma) { 238c47b5835SMark Cave-Ayland dmalen = esp_get_tc(s); 239cfcea0f9SMark Cave-Ayland if (dmalen > ESP_CMDBUF_SZ) { 2406c1fef6bSPrasad J Pandit return 0; 2416c1fef6bSPrasad J Pandit } 24274d71ea1SLaurent Vivier if (s->dma_memory_read) { 2438b17de88Sblueswir1 s->dma_memory_read(s->dma_opaque, buf, dmalen); 2444f6200f0Sbellard } else { 24502abe246SMark Cave-Ayland set_pdma(s, TI); 24674d71ea1SLaurent Vivier esp_raise_drq(s); 24774d71ea1SLaurent Vivier return 0; 24874d71ea1SLaurent Vivier } 24974d71ea1SLaurent Vivier } else { 250fc4d65daSblueswir1 dmalen = s->ti_size; 251d3cdc491SPrasad J Pandit if (dmalen > TI_BUFSZ) { 252d3cdc491SPrasad J Pandit return 0; 253d3cdc491SPrasad J Pandit } 254fc4d65daSblueswir1 memcpy(buf, s->ti_buf, dmalen); 25575ef8496SHervé Poussineau buf[0] = buf[2] >> 5; 2564f6200f0Sbellard } 257bf4b9889SBlue Swirl trace_esp_get_cmd(dmalen, target); 2582e5d83bbSpbrook 259*c7bce09cSMark Cave-Ayland if (esp_select(s) < 0) { 2609f149aa9Spbrook return 0; 2612f275b8fSbellard } 2629f149aa9Spbrook return dmalen; 2639f149aa9Spbrook } 2649f149aa9Spbrook 265f2818f22SArtyom Tarasenko static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) 2669f149aa9Spbrook { 2679f149aa9Spbrook int32_t datalen; 2689f149aa9Spbrook int lun; 269f48a7a6eSPaolo Bonzini SCSIDevice *current_lun; 2709f149aa9Spbrook 271bf4b9889SBlue Swirl trace_esp_do_busid_cmd(busid); 272f2818f22SArtyom Tarasenko lun = busid & 7; 2730d3545e7SPaolo Bonzini current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun); 274e6810db8SHervé Poussineau s->current_req = scsi_req_new(current_lun, 0, lun, buf, s); 275c39ce112SPaolo Bonzini datalen = scsi_req_enqueue(s->current_req); 27667e999beSbellard s->ti_size = datalen; 27767e999beSbellard if (datalen != 0) { 278c73f96fdSblueswir1 s->rregs[ESP_RSTAT] = STAT_TC; 2796cc88d6bSMark Cave-Ayland esp_set_tc(s, 0); 2802e5d83bbSpbrook if (datalen > 0) { 2815ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] |= STAT_DI; 2824f6200f0Sbellard } else { 2835ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] |= STAT_DO; 2844f6200f0Sbellard } 285ad3376ccSPaolo Bonzini scsi_req_continue(s->current_req); 2864e9aec74Spbrook } 2875ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 2885ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = SEQ_CD; 289c73f96fdSblueswir1 esp_raise_irq(s); 2902f275b8fSbellard } 2912f275b8fSbellard 292c959f218SMark Cave-Ayland static void do_cmd(ESPState *s) 293f2818f22SArtyom Tarasenko { 294c959f218SMark Cave-Ayland uint8_t *buf = s->cmdbuf; 295f2818f22SArtyom Tarasenko uint8_t busid = buf[0]; 296f2818f22SArtyom Tarasenko 297f2818f22SArtyom Tarasenko do_busid_cmd(s, &buf[1], busid); 298f2818f22SArtyom Tarasenko } 299f2818f22SArtyom Tarasenko 30074d71ea1SLaurent Vivier static void satn_pdma_cb(ESPState *s) 30174d71ea1SLaurent Vivier { 302*c7bce09cSMark Cave-Ayland if (esp_select(s) < 0) { 30374d71ea1SLaurent Vivier return; 30474d71ea1SLaurent Vivier } 305bb0bc7bbSMark Cave-Ayland s->do_cmd = 0; 306bb0bc7bbSMark Cave-Ayland if (s->cmdlen) { 307c959f218SMark Cave-Ayland do_cmd(s); 30874d71ea1SLaurent Vivier } 30974d71ea1SLaurent Vivier } 31074d71ea1SLaurent Vivier 3119f149aa9Spbrook static void handle_satn(ESPState *s) 3129f149aa9Spbrook { 3131b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 31473d74342SBlue Swirl s->dma_cb = handle_satn; 31573d74342SBlue Swirl return; 31673d74342SBlue Swirl } 31774d71ea1SLaurent Vivier s->pdma_cb = satn_pdma_cb; 318cfcea0f9SMark Cave-Ayland s->cmdlen = get_cmd(s); 319bb0bc7bbSMark Cave-Ayland if (s->cmdlen) { 320c959f218SMark Cave-Ayland do_cmd(s); 321bb0bc7bbSMark Cave-Ayland } else { 322bb0bc7bbSMark Cave-Ayland s->do_cmd = 1; 3239f149aa9Spbrook } 32494d5c79dSMark Cave-Ayland } 3259f149aa9Spbrook 32674d71ea1SLaurent Vivier static void s_without_satn_pdma_cb(ESPState *s) 32774d71ea1SLaurent Vivier { 328*c7bce09cSMark Cave-Ayland if (esp_select(s) < 0) { 32974d71ea1SLaurent Vivier return; 33074d71ea1SLaurent Vivier } 331bb0bc7bbSMark Cave-Ayland s->do_cmd = 0; 332bb0bc7bbSMark Cave-Ayland if (s->cmdlen) { 3332c573cfeSMark Cave-Ayland do_busid_cmd(s, s->cmdbuf, 0); 33474d71ea1SLaurent Vivier } 33574d71ea1SLaurent Vivier } 33674d71ea1SLaurent Vivier 337f2818f22SArtyom Tarasenko static void handle_s_without_atn(ESPState *s) 338f2818f22SArtyom Tarasenko { 3391b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 34073d74342SBlue Swirl s->dma_cb = handle_s_without_atn; 34173d74342SBlue Swirl return; 34273d74342SBlue Swirl } 34374d71ea1SLaurent Vivier s->pdma_cb = s_without_satn_pdma_cb; 344cfcea0f9SMark Cave-Ayland s->cmdlen = get_cmd(s); 345bb0bc7bbSMark Cave-Ayland if (s->cmdlen) { 346bb0bc7bbSMark Cave-Ayland do_busid_cmd(s, s->cmdbuf, 0); 347bb0bc7bbSMark Cave-Ayland } else { 348bb0bc7bbSMark Cave-Ayland s->do_cmd = 1; 349f2818f22SArtyom Tarasenko } 350f2818f22SArtyom Tarasenko } 351f2818f22SArtyom Tarasenko 35274d71ea1SLaurent Vivier static void satn_stop_pdma_cb(ESPState *s) 35374d71ea1SLaurent Vivier { 354*c7bce09cSMark Cave-Ayland if (esp_select(s) < 0) { 35574d71ea1SLaurent Vivier return; 35674d71ea1SLaurent Vivier } 357bb0bc7bbSMark Cave-Ayland s->do_cmd = 0; 35874d71ea1SLaurent Vivier if (s->cmdlen) { 35974d71ea1SLaurent Vivier trace_esp_handle_satn_stop(s->cmdlen); 36074d71ea1SLaurent Vivier s->do_cmd = 1; 36174d71ea1SLaurent Vivier s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; 36274d71ea1SLaurent Vivier s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 36374d71ea1SLaurent Vivier s->rregs[ESP_RSEQ] = SEQ_CD; 36474d71ea1SLaurent Vivier esp_raise_irq(s); 36574d71ea1SLaurent Vivier } 36674d71ea1SLaurent Vivier } 36774d71ea1SLaurent Vivier 3689f149aa9Spbrook static void handle_satn_stop(ESPState *s) 3699f149aa9Spbrook { 3701b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 37173d74342SBlue Swirl s->dma_cb = handle_satn_stop; 37273d74342SBlue Swirl return; 37373d74342SBlue Swirl } 374c62c1fa0SPhilippe Mathieu-Daudé s->pdma_cb = satn_stop_pdma_cb; 375cfcea0f9SMark Cave-Ayland s->cmdlen = get_cmd(s); 3769f149aa9Spbrook if (s->cmdlen) { 377bf4b9889SBlue Swirl trace_esp_handle_satn_stop(s->cmdlen); 3789f149aa9Spbrook s->do_cmd = 1; 379c73f96fdSblueswir1 s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; 3805ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 3815ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = SEQ_CD; 382c73f96fdSblueswir1 esp_raise_irq(s); 383bb0bc7bbSMark Cave-Ayland } else { 384bb0bc7bbSMark Cave-Ayland s->do_cmd = 1; 3859f149aa9Spbrook } 3869f149aa9Spbrook } 3879f149aa9Spbrook 38874d71ea1SLaurent Vivier static void write_response_pdma_cb(ESPState *s) 38974d71ea1SLaurent Vivier { 39074d71ea1SLaurent Vivier s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; 39174d71ea1SLaurent Vivier s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 39274d71ea1SLaurent Vivier s->rregs[ESP_RSEQ] = SEQ_CD; 39374d71ea1SLaurent Vivier esp_raise_irq(s); 39474d71ea1SLaurent Vivier } 39574d71ea1SLaurent Vivier 3960fc5c15aSpbrook static void write_response(ESPState *s) 3972f275b8fSbellard { 398bf4b9889SBlue Swirl trace_esp_write_response(s->status); 3993944966dSPaolo Bonzini s->ti_buf[0] = s->status; 4000fc5c15aSpbrook s->ti_buf[1] = 0; 4014f6200f0Sbellard if (s->dma) { 40274d71ea1SLaurent Vivier if (s->dma_memory_write) { 4038b17de88Sblueswir1 s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); 404c73f96fdSblueswir1 s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; 4055ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 4065ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = SEQ_CD; 4074f6200f0Sbellard } else { 4083c421400SMark Cave-Ayland set_pdma(s, TI); 40974d71ea1SLaurent Vivier s->pdma_cb = write_response_pdma_cb; 41074d71ea1SLaurent Vivier esp_raise_drq(s); 41174d71ea1SLaurent Vivier return; 41274d71ea1SLaurent Vivier } 41374d71ea1SLaurent Vivier } else { 4140fc5c15aSpbrook s->ti_size = 2; 4154f6200f0Sbellard s->ti_rptr = 0; 416d020aa50SPaolo Bonzini s->ti_wptr = 2; 4175ad6bb97Sblueswir1 s->rregs[ESP_RFLAGS] = 2; 4184f6200f0Sbellard } 419c73f96fdSblueswir1 esp_raise_irq(s); 4202f275b8fSbellard } 4214f6200f0Sbellard 422a917d384Spbrook static void esp_dma_done(ESPState *s) 4234d611c9aSpbrook { 424c73f96fdSblueswir1 s->rregs[ESP_RSTAT] |= STAT_TC; 4255ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_BS; 4265ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = 0; 4275ad6bb97Sblueswir1 s->rregs[ESP_RFLAGS] = 0; 428c47b5835SMark Cave-Ayland esp_set_tc(s, 0); 429c73f96fdSblueswir1 esp_raise_irq(s); 4304d611c9aSpbrook } 431a917d384Spbrook 43274d71ea1SLaurent Vivier static void do_dma_pdma_cb(ESPState *s) 43374d71ea1SLaurent Vivier { 4344ca2ba6fSMark Cave-Ayland int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO); 4356cc88d6bSMark Cave-Ayland 43674d71ea1SLaurent Vivier if (s->do_cmd) { 43774d71ea1SLaurent Vivier s->ti_size = 0; 43874d71ea1SLaurent Vivier s->cmdlen = 0; 43974d71ea1SLaurent Vivier s->do_cmd = 0; 440c959f218SMark Cave-Ayland do_cmd(s); 44174d71ea1SLaurent Vivier return; 44274d71ea1SLaurent Vivier } 44374d71ea1SLaurent Vivier if (s->async_len == 0) { 44474d71ea1SLaurent Vivier scsi_req_continue(s->current_req); 44574d71ea1SLaurent Vivier /* 44674d71ea1SLaurent Vivier * If there is still data to be read from the device then 44774d71ea1SLaurent Vivier * complete the DMA operation immediately. Otherwise defer 44874d71ea1SLaurent Vivier * until the scsi layer has completed. 44974d71ea1SLaurent Vivier */ 4506cc88d6bSMark Cave-Ayland if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) { 45174d71ea1SLaurent Vivier return; 45274d71ea1SLaurent Vivier } 45374d71ea1SLaurent Vivier } 45474d71ea1SLaurent Vivier 45574d71ea1SLaurent Vivier /* Partially filled a scsi buffer. Complete immediately. */ 45674d71ea1SLaurent Vivier esp_dma_done(s); 45774d71ea1SLaurent Vivier } 45874d71ea1SLaurent Vivier 459a917d384Spbrook static void esp_do_dma(ESPState *s) 460a917d384Spbrook { 46167e999beSbellard uint32_t len; 4624ca2ba6fSMark Cave-Ayland int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO); 463a917d384Spbrook 4646cc88d6bSMark Cave-Ayland len = esp_get_tc(s); 465a917d384Spbrook if (s->do_cmd) { 46615407433SLaurent Vivier /* 46715407433SLaurent Vivier * handle_ti_cmd() case: esp_do_dma() is called only from 46815407433SLaurent Vivier * handle_ti_cmd() with do_cmd != NULL (see the assert()) 46915407433SLaurent Vivier */ 470bf4b9889SBlue Swirl trace_esp_do_dma(s->cmdlen, len); 471926cde5fSPrasad J Pandit assert(s->cmdlen <= sizeof(s->cmdbuf) && 472926cde5fSPrasad J Pandit len <= sizeof(s->cmdbuf) - s->cmdlen); 47374d71ea1SLaurent Vivier if (s->dma_memory_read) { 4748b17de88Sblueswir1 s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); 47574d71ea1SLaurent Vivier } else { 47602abe246SMark Cave-Ayland set_pdma(s, TI); 47774d71ea1SLaurent Vivier s->pdma_cb = do_dma_pdma_cb; 47874d71ea1SLaurent Vivier esp_raise_drq(s); 47974d71ea1SLaurent Vivier return; 48074d71ea1SLaurent Vivier } 48115407433SLaurent Vivier trace_esp_handle_ti_cmd(s->cmdlen); 48215407433SLaurent Vivier s->ti_size = 0; 48315407433SLaurent Vivier s->cmdlen = 0; 48415407433SLaurent Vivier s->do_cmd = 0; 485c959f218SMark Cave-Ayland do_cmd(s); 486a917d384Spbrook return; 487a917d384Spbrook } 488a917d384Spbrook if (s->async_len == 0) { 489a917d384Spbrook /* Defer until data is available. */ 490a917d384Spbrook return; 491a917d384Spbrook } 492a917d384Spbrook if (len > s->async_len) { 493a917d384Spbrook len = s->async_len; 494a917d384Spbrook } 495a917d384Spbrook if (to_device) { 49674d71ea1SLaurent Vivier if (s->dma_memory_read) { 4978b17de88Sblueswir1 s->dma_memory_read(s->dma_opaque, s->async_buf, len); 498a917d384Spbrook } else { 4993c421400SMark Cave-Ayland set_pdma(s, ASYNC); 50074d71ea1SLaurent Vivier s->pdma_cb = do_dma_pdma_cb; 50174d71ea1SLaurent Vivier esp_raise_drq(s); 50274d71ea1SLaurent Vivier return; 50374d71ea1SLaurent Vivier } 50474d71ea1SLaurent Vivier } else { 50574d71ea1SLaurent Vivier if (s->dma_memory_write) { 5068b17de88Sblueswir1 s->dma_memory_write(s->dma_opaque, s->async_buf, len); 50774d71ea1SLaurent Vivier } else { 5083c421400SMark Cave-Ayland set_pdma(s, ASYNC); 50974d71ea1SLaurent Vivier s->pdma_cb = do_dma_pdma_cb; 51074d71ea1SLaurent Vivier esp_raise_drq(s); 51174d71ea1SLaurent Vivier return; 51274d71ea1SLaurent Vivier } 513a917d384Spbrook } 5146cc88d6bSMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 515a917d384Spbrook s->async_buf += len; 516a917d384Spbrook s->async_len -= len; 51794d5c79dSMark Cave-Ayland if (to_device) { 5186787f5faSpbrook s->ti_size += len; 51994d5c79dSMark Cave-Ayland } else { 5206787f5faSpbrook s->ti_size -= len; 52194d5c79dSMark Cave-Ayland } 522a917d384Spbrook if (s->async_len == 0) { 523ad3376ccSPaolo Bonzini scsi_req_continue(s->current_req); 52494d5c79dSMark Cave-Ayland /* 52594d5c79dSMark Cave-Ayland * If there is still data to be read from the device then 52694d5c79dSMark Cave-Ayland * complete the DMA operation immediately. Otherwise defer 52794d5c79dSMark Cave-Ayland * until the scsi layer has completed. 52894d5c79dSMark Cave-Ayland */ 5296cc88d6bSMark Cave-Ayland if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) { 530ad3376ccSPaolo Bonzini return; 531a917d384Spbrook } 532a917d384Spbrook } 533ad3376ccSPaolo Bonzini 5346787f5faSpbrook /* Partially filled a scsi buffer. Complete immediately. */ 535a917d384Spbrook esp_dma_done(s); 536a917d384Spbrook } 537a917d384Spbrook 538ea84a442SGuenter Roeck static void esp_report_command_complete(ESPState *s, uint32_t status) 539a917d384Spbrook { 540bf4b9889SBlue Swirl trace_esp_command_complete(); 541c6df7102SPaolo Bonzini if (s->ti_size != 0) { 542bf4b9889SBlue Swirl trace_esp_command_complete_unexpected(); 543c6df7102SPaolo Bonzini } 544a917d384Spbrook s->ti_size = 0; 545a917d384Spbrook s->async_len = 0; 546aba1f023SPaolo Bonzini if (status) { 547bf4b9889SBlue Swirl trace_esp_command_complete_fail(); 548c6df7102SPaolo Bonzini } 549aba1f023SPaolo Bonzini s->status = status; 5505ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] = STAT_ST; 551a917d384Spbrook esp_dma_done(s); 5525c6c0e51SHannes Reinecke if (s->current_req) { 5535c6c0e51SHannes Reinecke scsi_req_unref(s->current_req); 5545c6c0e51SHannes Reinecke s->current_req = NULL; 555a917d384Spbrook s->current_dev = NULL; 5565c6c0e51SHannes Reinecke } 557c6df7102SPaolo Bonzini } 558c6df7102SPaolo Bonzini 55917ea26c2SHannes Reinecke void esp_command_complete(SCSIRequest *req, size_t resid) 560ea84a442SGuenter Roeck { 561ea84a442SGuenter Roeck ESPState *s = req->hba_private; 562ea84a442SGuenter Roeck 563ea84a442SGuenter Roeck if (s->rregs[ESP_RSTAT] & STAT_INT) { 56494d5c79dSMark Cave-Ayland /* 56594d5c79dSMark Cave-Ayland * Defer handling command complete until the previous 566ea84a442SGuenter Roeck * interrupt has been handled. 567ea84a442SGuenter Roeck */ 568ea84a442SGuenter Roeck trace_esp_command_complete_deferred(); 56917ea26c2SHannes Reinecke s->deferred_status = req->status; 570ea84a442SGuenter Roeck s->deferred_complete = true; 571ea84a442SGuenter Roeck return; 572ea84a442SGuenter Roeck } 57317ea26c2SHannes Reinecke esp_report_command_complete(s, req->status); 574ea84a442SGuenter Roeck } 575ea84a442SGuenter Roeck 5769c7e23fcSHervé Poussineau void esp_transfer_data(SCSIRequest *req, uint32_t len) 577c6df7102SPaolo Bonzini { 578e6810db8SHervé Poussineau ESPState *s = req->hba_private; 5796cc88d6bSMark Cave-Ayland uint32_t dmalen = esp_get_tc(s); 580c6df7102SPaolo Bonzini 5817f0b6e11SPaolo Bonzini assert(!s->do_cmd); 5826cc88d6bSMark Cave-Ayland trace_esp_transfer_data(dmalen, s->ti_size); 583aba1f023SPaolo Bonzini s->async_len = len; 5840c34459bSPaolo Bonzini s->async_buf = scsi_req_get_buf(req); 5856cc88d6bSMark Cave-Ayland if (dmalen) { 586a917d384Spbrook esp_do_dma(s); 5875eb7a23fSMark Cave-Ayland } else if (s->ti_size <= 0) { 58894d5c79dSMark Cave-Ayland /* 58994d5c79dSMark Cave-Ayland * If this was the last part of a DMA transfer then the 59094d5c79dSMark Cave-Ayland * completion interrupt is deferred to here. 59194d5c79dSMark Cave-Ayland */ 5926787f5faSpbrook esp_dma_done(s); 5936787f5faSpbrook } 594a917d384Spbrook } 5952e5d83bbSpbrook 5962f275b8fSbellard static void handle_ti(ESPState *s) 5972f275b8fSbellard { 598b76624deSMark Cave-Ayland uint32_t dmalen; 5992f275b8fSbellard 6007246e160SHervé Poussineau if (s->dma && !s->dma_enabled) { 6017246e160SHervé Poussineau s->dma_cb = handle_ti; 6027246e160SHervé Poussineau return; 6037246e160SHervé Poussineau } 6047246e160SHervé Poussineau 605c47b5835SMark Cave-Ayland dmalen = esp_get_tc(s); 6064f6200f0Sbellard if (s->dma) { 607b76624deSMark Cave-Ayland trace_esp_handle_ti(dmalen); 6085ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] &= ~STAT_TC; 6094d611c9aSpbrook esp_do_dma(s); 61015407433SLaurent Vivier } else if (s->do_cmd) { 611bf4b9889SBlue Swirl trace_esp_handle_ti_cmd(s->cmdlen); 6129f149aa9Spbrook s->ti_size = 0; 6139f149aa9Spbrook s->cmdlen = 0; 6149f149aa9Spbrook s->do_cmd = 0; 615c959f218SMark Cave-Ayland do_cmd(s); 6164f6200f0Sbellard } 6172f275b8fSbellard } 6182f275b8fSbellard 6199c7e23fcSHervé Poussineau void esp_hard_reset(ESPState *s) 6206f7e9aecSbellard { 6215aca8c3bSblueswir1 memset(s->rregs, 0, ESP_REGS); 6225aca8c3bSblueswir1 memset(s->wregs, 0, ESP_REGS); 623c9cf45c1SHannes Reinecke s->tchi_written = 0; 6244e9aec74Spbrook s->ti_size = 0; 6254e9aec74Spbrook s->ti_rptr = 0; 6264e9aec74Spbrook s->ti_wptr = 0; 6274e9aec74Spbrook s->dma = 0; 6289f149aa9Spbrook s->do_cmd = 0; 62973d74342SBlue Swirl s->dma_cb = NULL; 6308dea1dd4Sblueswir1 6318dea1dd4Sblueswir1 s->rregs[ESP_CFG1] = 7; 6326f7e9aecSbellard } 6336f7e9aecSbellard 634a391fdbcSHervé Poussineau static void esp_soft_reset(ESPState *s) 63585948643SBlue Swirl { 63685948643SBlue Swirl qemu_irq_lower(s->irq); 63774d71ea1SLaurent Vivier qemu_irq_lower(s->irq_data); 638a391fdbcSHervé Poussineau esp_hard_reset(s); 63985948643SBlue Swirl } 64085948643SBlue Swirl 641a391fdbcSHervé Poussineau static void parent_esp_reset(ESPState *s, int irq, int level) 6422d069babSblueswir1 { 64385948643SBlue Swirl if (level) { 644a391fdbcSHervé Poussineau esp_soft_reset(s); 64585948643SBlue Swirl } 6462d069babSblueswir1 } 6472d069babSblueswir1 6489c7e23fcSHervé Poussineau uint64_t esp_reg_read(ESPState *s, uint32_t saddr) 64973d74342SBlue Swirl { 650b630c075SMark Cave-Ayland uint32_t val; 65173d74342SBlue Swirl 6526f7e9aecSbellard switch (saddr) { 6535ad6bb97Sblueswir1 case ESP_FIFO: 6545ad6bb97Sblueswir1 if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) { 6558dea1dd4Sblueswir1 /* Data out. */ 656ff589551SPrasad J Pandit qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n"); 6575ad6bb97Sblueswir1 s->rregs[ESP_FIFO] = 0; 658ff589551SPrasad J Pandit } else if (s->ti_rptr < s->ti_wptr) { 659ff589551SPrasad J Pandit s->ti_size--; 6605ad6bb97Sblueswir1 s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; 6614f6200f0Sbellard } 662ff589551SPrasad J Pandit if (s->ti_rptr == s->ti_wptr) { 6634f6200f0Sbellard s->ti_rptr = 0; 6644f6200f0Sbellard s->ti_wptr = 0; 6654f6200f0Sbellard } 666b630c075SMark Cave-Ayland val = s->rregs[ESP_FIFO]; 6674f6200f0Sbellard break; 6685ad6bb97Sblueswir1 case ESP_RINTR: 66994d5c79dSMark Cave-Ayland /* 67094d5c79dSMark Cave-Ayland * Clear sequence step, interrupt register and all status bits 67194d5c79dSMark Cave-Ayland * except TC 67294d5c79dSMark Cave-Ayland */ 673b630c075SMark Cave-Ayland val = s->rregs[ESP_RINTR]; 6742814df28SBlue Swirl s->rregs[ESP_RINTR] = 0; 6752814df28SBlue Swirl s->rregs[ESP_RSTAT] &= ~STAT_TC; 6762814df28SBlue Swirl s->rregs[ESP_RSEQ] = SEQ_CD; 677c73f96fdSblueswir1 esp_lower_irq(s); 678ea84a442SGuenter Roeck if (s->deferred_complete) { 679ea84a442SGuenter Roeck esp_report_command_complete(s, s->deferred_status); 680ea84a442SGuenter Roeck s->deferred_complete = false; 681ea84a442SGuenter Roeck } 682b630c075SMark Cave-Ayland break; 683c9cf45c1SHannes Reinecke case ESP_TCHI: 684c9cf45c1SHannes Reinecke /* Return the unique id if the value has never been written */ 685c9cf45c1SHannes Reinecke if (!s->tchi_written) { 686b630c075SMark Cave-Ayland val = s->chip_id; 687b630c075SMark Cave-Ayland } else { 688b630c075SMark Cave-Ayland val = s->rregs[saddr]; 689c9cf45c1SHannes Reinecke } 690b630c075SMark Cave-Ayland break; 6916f7e9aecSbellard default: 692b630c075SMark Cave-Ayland val = s->rregs[saddr]; 6936f7e9aecSbellard break; 6946f7e9aecSbellard } 695b630c075SMark Cave-Ayland 696b630c075SMark Cave-Ayland trace_esp_mem_readb(saddr, val); 697b630c075SMark Cave-Ayland return val; 6986f7e9aecSbellard } 6996f7e9aecSbellard 7009c7e23fcSHervé Poussineau void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) 7016f7e9aecSbellard { 702bf4b9889SBlue Swirl trace_esp_mem_writeb(saddr, s->wregs[saddr], val); 7036f7e9aecSbellard switch (saddr) { 704c9cf45c1SHannes Reinecke case ESP_TCHI: 705c9cf45c1SHannes Reinecke s->tchi_written = true; 706c9cf45c1SHannes Reinecke /* fall through */ 7075ad6bb97Sblueswir1 case ESP_TCLO: 7085ad6bb97Sblueswir1 case ESP_TCMID: 7095ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] &= ~STAT_TC; 7104f6200f0Sbellard break; 7115ad6bb97Sblueswir1 case ESP_FIFO: 7129f149aa9Spbrook if (s->do_cmd) { 713926cde5fSPrasad J Pandit if (s->cmdlen < ESP_CMDBUF_SZ) { 7149f149aa9Spbrook s->cmdbuf[s->cmdlen++] = val & 0xff; 715c98c6c10SPrasad J Pandit } else { 716c98c6c10SPrasad J Pandit trace_esp_error_fifo_overrun(); 717c98c6c10SPrasad J Pandit } 718ff589551SPrasad J Pandit } else if (s->ti_wptr == TI_BUFSZ - 1) { 7193af4e9aaSHervé Poussineau trace_esp_error_fifo_overrun(); 7202e5d83bbSpbrook } else { 7214f6200f0Sbellard s->ti_size++; 7224f6200f0Sbellard s->ti_buf[s->ti_wptr++] = val & 0xff; 7232e5d83bbSpbrook } 7244f6200f0Sbellard break; 7255ad6bb97Sblueswir1 case ESP_CMD: 7264f6200f0Sbellard s->rregs[saddr] = val; 7275ad6bb97Sblueswir1 if (val & CMD_DMA) { 7284f6200f0Sbellard s->dma = 1; 7296787f5faSpbrook /* Reload DMA counter. */ 73096676c2fSMark Cave-Ayland if (esp_get_stc(s) == 0) { 73196676c2fSMark Cave-Ayland esp_set_tc(s, 0x10000); 73296676c2fSMark Cave-Ayland } else { 733c04ed569SMark Cave-Ayland esp_set_tc(s, esp_get_stc(s)); 73496676c2fSMark Cave-Ayland } 7354f6200f0Sbellard } else { 7364f6200f0Sbellard s->dma = 0; 7374f6200f0Sbellard } 7385ad6bb97Sblueswir1 switch (val & CMD_CMD) { 7395ad6bb97Sblueswir1 case CMD_NOP: 740bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_nop(val); 7412f275b8fSbellard break; 7425ad6bb97Sblueswir1 case CMD_FLUSH: 743bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_flush(val); 74494d5c79dSMark Cave-Ayland /*s->ti_size = 0;*/ 7455ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_FC; 7465ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = 0; 747a214c598Sblueswir1 s->rregs[ESP_RFLAGS] = 0; 7486f7e9aecSbellard break; 7495ad6bb97Sblueswir1 case CMD_RESET: 750bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_reset(val); 751a391fdbcSHervé Poussineau esp_soft_reset(s); 7526f7e9aecSbellard break; 7535ad6bb97Sblueswir1 case CMD_BUSRESET: 754bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_bus_reset(val); 7555ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_RST; 7565ad6bb97Sblueswir1 if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) { 757c73f96fdSblueswir1 esp_raise_irq(s); 7589e61bde5Sbellard } 7592f275b8fSbellard break; 7605ad6bb97Sblueswir1 case CMD_TI: 7610097d3ecSMark Cave-Ayland trace_esp_mem_writeb_cmd_ti(val); 7622f275b8fSbellard handle_ti(s); 7632f275b8fSbellard break; 7645ad6bb97Sblueswir1 case CMD_ICCS: 765bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_iccs(val); 7660fc5c15aSpbrook write_response(s); 7674bf5801dSblueswir1 s->rregs[ESP_RINTR] = INTR_FC; 7684bf5801dSblueswir1 s->rregs[ESP_RSTAT] |= STAT_MI; 7692f275b8fSbellard break; 7705ad6bb97Sblueswir1 case CMD_MSGACC: 771bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_msgacc(val); 7725ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_DC; 7735ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = 0; 7744e2a68c1SArtyom Tarasenko s->rregs[ESP_RFLAGS] = 0; 7754e2a68c1SArtyom Tarasenko esp_raise_irq(s); 7766f7e9aecSbellard break; 7770fd0eb21SBlue Swirl case CMD_PAD: 778bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_pad(val); 7790fd0eb21SBlue Swirl s->rregs[ESP_RSTAT] = STAT_TC; 7800fd0eb21SBlue Swirl s->rregs[ESP_RINTR] = INTR_FC; 7810fd0eb21SBlue Swirl s->rregs[ESP_RSEQ] = 0; 7820fd0eb21SBlue Swirl break; 7835ad6bb97Sblueswir1 case CMD_SATN: 784bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_satn(val); 7856f7e9aecSbellard break; 7866915bff1SHervé Poussineau case CMD_RSTATN: 7876915bff1SHervé Poussineau trace_esp_mem_writeb_cmd_rstatn(val); 7886915bff1SHervé Poussineau break; 7895e1e0a3bSBlue Swirl case CMD_SEL: 790bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_sel(val); 791f2818f22SArtyom Tarasenko handle_s_without_atn(s); 7925e1e0a3bSBlue Swirl break; 7935ad6bb97Sblueswir1 case CMD_SELATN: 794bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_selatn(val); 7952f275b8fSbellard handle_satn(s); 7962f275b8fSbellard break; 7975ad6bb97Sblueswir1 case CMD_SELATNS: 798bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_selatns(val); 7999f149aa9Spbrook handle_satn_stop(s); 8002f275b8fSbellard break; 8015ad6bb97Sblueswir1 case CMD_ENSEL: 802bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_ensel(val); 803e3926838Sblueswir1 s->rregs[ESP_RINTR] = 0; 80474ec6048Sblueswir1 break; 8056fe84c18SHervé Poussineau case CMD_DISSEL: 8066fe84c18SHervé Poussineau trace_esp_mem_writeb_cmd_dissel(val); 8076fe84c18SHervé Poussineau s->rregs[ESP_RINTR] = 0; 8086fe84c18SHervé Poussineau esp_raise_irq(s); 8096fe84c18SHervé Poussineau break; 8102f275b8fSbellard default: 8113af4e9aaSHervé Poussineau trace_esp_error_unhandled_command(val); 8126f7e9aecSbellard break; 8136f7e9aecSbellard } 8146f7e9aecSbellard break; 8155ad6bb97Sblueswir1 case ESP_WBUSID ... ESP_WSYNO: 8164f6200f0Sbellard break; 8175ad6bb97Sblueswir1 case ESP_CFG1: 8189ea73f8bSPaolo Bonzini case ESP_CFG2: case ESP_CFG3: 8199ea73f8bSPaolo Bonzini case ESP_RES3: case ESP_RES4: 8204f6200f0Sbellard s->rregs[saddr] = val; 8214f6200f0Sbellard break; 8225ad6bb97Sblueswir1 case ESP_WCCF ... ESP_WTEST: 8234f6200f0Sbellard break; 8246f7e9aecSbellard default: 8253af4e9aaSHervé Poussineau trace_esp_error_invalid_write(val, saddr); 8268dea1dd4Sblueswir1 return; 8276f7e9aecSbellard } 8282f275b8fSbellard s->wregs[saddr] = val; 8296f7e9aecSbellard } 8306f7e9aecSbellard 831a8170e5eSAvi Kivity static bool esp_mem_accepts(void *opaque, hwaddr addr, 8328372d383SPeter Maydell unsigned size, bool is_write, 8338372d383SPeter Maydell MemTxAttrs attrs) 83467bb5314SAvi Kivity { 83567bb5314SAvi Kivity return (size == 1) || (is_write && size == 4); 83667bb5314SAvi Kivity } 8376f7e9aecSbellard 83874d71ea1SLaurent Vivier static bool esp_pdma_needed(void *opaque) 83974d71ea1SLaurent Vivier { 84074d71ea1SLaurent Vivier ESPState *s = opaque; 84174d71ea1SLaurent Vivier return s->dma_memory_read == NULL && s->dma_memory_write == NULL && 84274d71ea1SLaurent Vivier s->dma_enabled; 84374d71ea1SLaurent Vivier } 84474d71ea1SLaurent Vivier 84574d71ea1SLaurent Vivier static const VMStateDescription vmstate_esp_pdma = { 84674d71ea1SLaurent Vivier .name = "esp/pdma", 847bb0bc7bbSMark Cave-Ayland .version_id = 2, 848bb0bc7bbSMark Cave-Ayland .minimum_version_id = 2, 84974d71ea1SLaurent Vivier .needed = esp_pdma_needed, 85074d71ea1SLaurent Vivier .fields = (VMStateField[]) { 85174d71ea1SLaurent Vivier VMSTATE_INT32(pdma_origin, ESPState), 85274d71ea1SLaurent Vivier VMSTATE_END_OF_LIST() 85374d71ea1SLaurent Vivier } 85474d71ea1SLaurent Vivier }; 85574d71ea1SLaurent Vivier 8566cc88d6bSMark Cave-Ayland static bool esp_is_before_version_5(void *opaque, int version_id) 8576cc88d6bSMark Cave-Ayland { 8586cc88d6bSMark Cave-Ayland ESPState *s = ESP(opaque); 8596cc88d6bSMark Cave-Ayland 8606cc88d6bSMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 8616cc88d6bSMark Cave-Ayland return version_id < 5; 8626cc88d6bSMark Cave-Ayland } 8636cc88d6bSMark Cave-Ayland 8640bd005beSMark Cave-Ayland static int esp_pre_save(void *opaque) 8650bd005beSMark Cave-Ayland { 8660bd005beSMark Cave-Ayland ESPState *s = ESP(opaque); 8670bd005beSMark Cave-Ayland 8680bd005beSMark Cave-Ayland s->mig_version_id = vmstate_esp.version_id; 8690bd005beSMark Cave-Ayland return 0; 8700bd005beSMark Cave-Ayland } 8710bd005beSMark Cave-Ayland 8720bd005beSMark Cave-Ayland static int esp_post_load(void *opaque, int version_id) 8730bd005beSMark Cave-Ayland { 8740bd005beSMark Cave-Ayland ESPState *s = ESP(opaque); 8750bd005beSMark Cave-Ayland 8766cc88d6bSMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 8776cc88d6bSMark Cave-Ayland 8786cc88d6bSMark Cave-Ayland if (version_id < 5) { 8796cc88d6bSMark Cave-Ayland esp_set_tc(s, s->mig_dma_left); 8806cc88d6bSMark Cave-Ayland } 8816cc88d6bSMark Cave-Ayland 8820bd005beSMark Cave-Ayland s->mig_version_id = vmstate_esp.version_id; 8830bd005beSMark Cave-Ayland return 0; 8840bd005beSMark Cave-Ayland } 8850bd005beSMark Cave-Ayland 8869c7e23fcSHervé Poussineau const VMStateDescription vmstate_esp = { 887cc9952f3SBlue Swirl .name = "esp", 8880bd005beSMark Cave-Ayland .version_id = 5, 889cc9952f3SBlue Swirl .minimum_version_id = 3, 8900bd005beSMark Cave-Ayland .pre_save = esp_pre_save, 8910bd005beSMark Cave-Ayland .post_load = esp_post_load, 892cc9952f3SBlue Swirl .fields = (VMStateField[]) { 893cc9952f3SBlue Swirl VMSTATE_BUFFER(rregs, ESPState), 894cc9952f3SBlue Swirl VMSTATE_BUFFER(wregs, ESPState), 895cc9952f3SBlue Swirl VMSTATE_INT32(ti_size, ESPState), 896cc9952f3SBlue Swirl VMSTATE_UINT32(ti_rptr, ESPState), 897cc9952f3SBlue Swirl VMSTATE_UINT32(ti_wptr, ESPState), 898cc9952f3SBlue Swirl VMSTATE_BUFFER(ti_buf, ESPState), 8993944966dSPaolo Bonzini VMSTATE_UINT32(status, ESPState), 900ea84a442SGuenter Roeck VMSTATE_UINT32(deferred_status, ESPState), 901ea84a442SGuenter Roeck VMSTATE_BOOL(deferred_complete, ESPState), 902cc9952f3SBlue Swirl VMSTATE_UINT32(dma, ESPState), 903cc966774SPaolo Bonzini VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16), 904cc966774SPaolo Bonzini VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4), 905cc9952f3SBlue Swirl VMSTATE_UINT32(cmdlen, ESPState), 906cc9952f3SBlue Swirl VMSTATE_UINT32(do_cmd, ESPState), 9076cc88d6bSMark Cave-Ayland VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5), 908cc9952f3SBlue Swirl VMSTATE_END_OF_LIST() 90974d71ea1SLaurent Vivier }, 91074d71ea1SLaurent Vivier .subsections = (const VMStateDescription * []) { 91174d71ea1SLaurent Vivier &vmstate_esp_pdma, 91274d71ea1SLaurent Vivier NULL 9136f7e9aecSbellard } 914cc9952f3SBlue Swirl }; 9156f7e9aecSbellard 916a8170e5eSAvi Kivity static void sysbus_esp_mem_write(void *opaque, hwaddr addr, 917a391fdbcSHervé Poussineau uint64_t val, unsigned int size) 918a391fdbcSHervé Poussineau { 919a391fdbcSHervé Poussineau SysBusESPState *sysbus = opaque; 920eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 921a391fdbcSHervé Poussineau uint32_t saddr; 922a391fdbcSHervé Poussineau 923a391fdbcSHervé Poussineau saddr = addr >> sysbus->it_shift; 924eb169c76SMark Cave-Ayland esp_reg_write(s, saddr, val); 925a391fdbcSHervé Poussineau } 926a391fdbcSHervé Poussineau 927a8170e5eSAvi Kivity static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr, 928a391fdbcSHervé Poussineau unsigned int size) 929a391fdbcSHervé Poussineau { 930a391fdbcSHervé Poussineau SysBusESPState *sysbus = opaque; 931eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 932a391fdbcSHervé Poussineau uint32_t saddr; 933a391fdbcSHervé Poussineau 934a391fdbcSHervé Poussineau saddr = addr >> sysbus->it_shift; 935eb169c76SMark Cave-Ayland return esp_reg_read(s, saddr); 936a391fdbcSHervé Poussineau } 937a391fdbcSHervé Poussineau 938a391fdbcSHervé Poussineau static const MemoryRegionOps sysbus_esp_mem_ops = { 939a391fdbcSHervé Poussineau .read = sysbus_esp_mem_read, 940a391fdbcSHervé Poussineau .write = sysbus_esp_mem_write, 941a391fdbcSHervé Poussineau .endianness = DEVICE_NATIVE_ENDIAN, 942a391fdbcSHervé Poussineau .valid.accepts = esp_mem_accepts, 943a391fdbcSHervé Poussineau }; 944a391fdbcSHervé Poussineau 94574d71ea1SLaurent Vivier static void sysbus_esp_pdma_write(void *opaque, hwaddr addr, 94674d71ea1SLaurent Vivier uint64_t val, unsigned int size) 94774d71ea1SLaurent Vivier { 94874d71ea1SLaurent Vivier SysBusESPState *sysbus = opaque; 949eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 9503c421400SMark Cave-Ayland uint32_t dmalen; 95174d71ea1SLaurent Vivier 952960ebfd9SMark Cave-Ayland trace_esp_pdma_write(size); 953960ebfd9SMark Cave-Ayland 95474d71ea1SLaurent Vivier switch (size) { 95574d71ea1SLaurent Vivier case 1: 956761bef75SMark Cave-Ayland esp_pdma_write(s, val); 95774d71ea1SLaurent Vivier break; 95874d71ea1SLaurent Vivier case 2: 959761bef75SMark Cave-Ayland esp_pdma_write(s, val >> 8); 960761bef75SMark Cave-Ayland esp_pdma_write(s, val); 96174d71ea1SLaurent Vivier break; 96274d71ea1SLaurent Vivier } 9633c421400SMark Cave-Ayland dmalen = esp_get_tc(s); 9643c421400SMark Cave-Ayland if (dmalen == 0 && s->pdma_cb) { 96574d71ea1SLaurent Vivier esp_lower_drq(s); 96674d71ea1SLaurent Vivier s->pdma_cb(s); 96774d71ea1SLaurent Vivier s->pdma_cb = NULL; 96874d71ea1SLaurent Vivier } 96974d71ea1SLaurent Vivier } 97074d71ea1SLaurent Vivier 97174d71ea1SLaurent Vivier static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr, 97274d71ea1SLaurent Vivier unsigned int size) 97374d71ea1SLaurent Vivier { 97474d71ea1SLaurent Vivier SysBusESPState *sysbus = opaque; 975eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 9766cc88d6bSMark Cave-Ayland uint32_t dmalen = esp_get_tc(s); 97774d71ea1SLaurent Vivier uint64_t val = 0; 97874d71ea1SLaurent Vivier 979960ebfd9SMark Cave-Ayland trace_esp_pdma_read(size); 980960ebfd9SMark Cave-Ayland 9813c421400SMark Cave-Ayland if (dmalen == 0) { 98274d71ea1SLaurent Vivier return 0; 98374d71ea1SLaurent Vivier } 98474d71ea1SLaurent Vivier switch (size) { 98574d71ea1SLaurent Vivier case 1: 986761bef75SMark Cave-Ayland val = esp_pdma_read(s); 98774d71ea1SLaurent Vivier break; 98874d71ea1SLaurent Vivier case 2: 989761bef75SMark Cave-Ayland val = esp_pdma_read(s); 990761bef75SMark Cave-Ayland val = (val << 8) | esp_pdma_read(s); 99174d71ea1SLaurent Vivier break; 99274d71ea1SLaurent Vivier } 9938da90e81SMark Cave-Ayland dmalen = esp_get_tc(s); 9943c421400SMark Cave-Ayland if (dmalen == 0 && s->pdma_cb) { 99574d71ea1SLaurent Vivier esp_lower_drq(s); 99674d71ea1SLaurent Vivier s->pdma_cb(s); 99774d71ea1SLaurent Vivier s->pdma_cb = NULL; 99874d71ea1SLaurent Vivier } 99974d71ea1SLaurent Vivier return val; 100074d71ea1SLaurent Vivier } 100174d71ea1SLaurent Vivier 100274d71ea1SLaurent Vivier static const MemoryRegionOps sysbus_esp_pdma_ops = { 100374d71ea1SLaurent Vivier .read = sysbus_esp_pdma_read, 100474d71ea1SLaurent Vivier .write = sysbus_esp_pdma_write, 100574d71ea1SLaurent Vivier .endianness = DEVICE_NATIVE_ENDIAN, 100674d71ea1SLaurent Vivier .valid.min_access_size = 1, 100774d71ea1SLaurent Vivier .valid.max_access_size = 2, 100874d71ea1SLaurent Vivier }; 100974d71ea1SLaurent Vivier 1010afd4030cSPaolo Bonzini static const struct SCSIBusInfo esp_scsi_info = { 1011afd4030cSPaolo Bonzini .tcq = false, 10127e0380b9SPaolo Bonzini .max_target = ESP_MAX_DEVS, 10137e0380b9SPaolo Bonzini .max_lun = 7, 1014afd4030cSPaolo Bonzini 1015c6df7102SPaolo Bonzini .transfer_data = esp_transfer_data, 101694d3f98aSPaolo Bonzini .complete = esp_command_complete, 101794d3f98aSPaolo Bonzini .cancel = esp_request_cancelled 1018cfdc1bb0SPaolo Bonzini }; 1019cfdc1bb0SPaolo Bonzini 1020a391fdbcSHervé Poussineau static void sysbus_esp_gpio_demux(void *opaque, int irq, int level) 1021cfb9de9cSPaul Brook { 102284fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(opaque); 1023eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1024a391fdbcSHervé Poussineau 1025a391fdbcSHervé Poussineau switch (irq) { 1026a391fdbcSHervé Poussineau case 0: 1027a391fdbcSHervé Poussineau parent_esp_reset(s, irq, level); 1028a391fdbcSHervé Poussineau break; 1029a391fdbcSHervé Poussineau case 1: 1030a391fdbcSHervé Poussineau esp_dma_enable(opaque, irq, level); 1031a391fdbcSHervé Poussineau break; 1032a391fdbcSHervé Poussineau } 1033a391fdbcSHervé Poussineau } 1034a391fdbcSHervé Poussineau 1035b09318caSHu Tao static void sysbus_esp_realize(DeviceState *dev, Error **errp) 1036a391fdbcSHervé Poussineau { 1037b09318caSHu Tao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 103884fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(dev); 1039eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1040eb169c76SMark Cave-Ayland 1041eb169c76SMark Cave-Ayland if (!qdev_realize(DEVICE(s), NULL, errp)) { 1042eb169c76SMark Cave-Ayland return; 1043eb169c76SMark Cave-Ayland } 10446f7e9aecSbellard 1045b09318caSHu Tao sysbus_init_irq(sbd, &s->irq); 104674d71ea1SLaurent Vivier sysbus_init_irq(sbd, &s->irq_data); 1047a391fdbcSHervé Poussineau assert(sysbus->it_shift != -1); 10486f7e9aecSbellard 1049d32e4b3dSHervé Poussineau s->chip_id = TCHI_FAS100A; 105029776739SPaolo Bonzini memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_ops, 105174d71ea1SLaurent Vivier sysbus, "esp-regs", ESP_REGS << sysbus->it_shift); 1052b09318caSHu Tao sysbus_init_mmio(sbd, &sysbus->iomem); 105374d71ea1SLaurent Vivier memory_region_init_io(&sysbus->pdma, OBJECT(sysbus), &sysbus_esp_pdma_ops, 105474d71ea1SLaurent Vivier sysbus, "esp-pdma", 2); 105574d71ea1SLaurent Vivier sysbus_init_mmio(sbd, &sysbus->pdma); 10566f7e9aecSbellard 1057b09318caSHu Tao qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2); 10582d069babSblueswir1 1059b1187b51SAndreas Färber scsi_bus_new(&s->bus, sizeof(s->bus), dev, &esp_scsi_info, NULL); 106067e999beSbellard } 1061cfb9de9cSPaul Brook 1062a391fdbcSHervé Poussineau static void sysbus_esp_hard_reset(DeviceState *dev) 1063a391fdbcSHervé Poussineau { 106484fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(dev); 1065eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1066eb169c76SMark Cave-Ayland 1067eb169c76SMark Cave-Ayland esp_hard_reset(s); 1068eb169c76SMark Cave-Ayland } 1069eb169c76SMark Cave-Ayland 1070eb169c76SMark Cave-Ayland static void sysbus_esp_init(Object *obj) 1071eb169c76SMark Cave-Ayland { 1072eb169c76SMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(obj); 1073eb169c76SMark Cave-Ayland 1074eb169c76SMark Cave-Ayland object_initialize_child(obj, "esp", &sysbus->esp, TYPE_ESP); 1075a391fdbcSHervé Poussineau } 1076a391fdbcSHervé Poussineau 1077a391fdbcSHervé Poussineau static const VMStateDescription vmstate_sysbus_esp_scsi = { 1078a391fdbcSHervé Poussineau .name = "sysbusespscsi", 10790bd005beSMark Cave-Ayland .version_id = 2, 1080ea84a442SGuenter Roeck .minimum_version_id = 1, 1081a391fdbcSHervé Poussineau .fields = (VMStateField[]) { 10820bd005beSMark Cave-Ayland VMSTATE_UINT8_V(esp.mig_version_id, SysBusESPState, 2), 1083a391fdbcSHervé Poussineau VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState), 1084a391fdbcSHervé Poussineau VMSTATE_END_OF_LIST() 1085a391fdbcSHervé Poussineau } 1086999e12bbSAnthony Liguori }; 1087999e12bbSAnthony Liguori 1088a391fdbcSHervé Poussineau static void sysbus_esp_class_init(ObjectClass *klass, void *data) 1089999e12bbSAnthony Liguori { 109039bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 1091999e12bbSAnthony Liguori 1092b09318caSHu Tao dc->realize = sysbus_esp_realize; 1093a391fdbcSHervé Poussineau dc->reset = sysbus_esp_hard_reset; 1094a391fdbcSHervé Poussineau dc->vmsd = &vmstate_sysbus_esp_scsi; 1095125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 109663235df8SBlue Swirl } 1097999e12bbSAnthony Liguori 10981f077308SHervé Poussineau static const TypeInfo sysbus_esp_info = { 109984fbefedSMark Cave-Ayland .name = TYPE_SYSBUS_ESP, 110039bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 1101eb169c76SMark Cave-Ayland .instance_init = sysbus_esp_init, 1102a391fdbcSHervé Poussineau .instance_size = sizeof(SysBusESPState), 1103a391fdbcSHervé Poussineau .class_init = sysbus_esp_class_init, 110463235df8SBlue Swirl }; 110563235df8SBlue Swirl 1106eb169c76SMark Cave-Ayland static void esp_class_init(ObjectClass *klass, void *data) 1107eb169c76SMark Cave-Ayland { 1108eb169c76SMark Cave-Ayland DeviceClass *dc = DEVICE_CLASS(klass); 1109eb169c76SMark Cave-Ayland 1110eb169c76SMark Cave-Ayland /* internal device for sysbusesp/pciespscsi, not user-creatable */ 1111eb169c76SMark Cave-Ayland dc->user_creatable = false; 1112eb169c76SMark Cave-Ayland set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 1113eb169c76SMark Cave-Ayland } 1114eb169c76SMark Cave-Ayland 1115eb169c76SMark Cave-Ayland static const TypeInfo esp_info = { 1116eb169c76SMark Cave-Ayland .name = TYPE_ESP, 1117eb169c76SMark Cave-Ayland .parent = TYPE_DEVICE, 1118eb169c76SMark Cave-Ayland .instance_size = sizeof(ESPState), 1119eb169c76SMark Cave-Ayland .class_init = esp_class_init, 1120eb169c76SMark Cave-Ayland }; 1121eb169c76SMark Cave-Ayland 112283f7d43aSAndreas Färber static void esp_register_types(void) 1123cfb9de9cSPaul Brook { 1124a391fdbcSHervé Poussineau type_register_static(&sysbus_esp_info); 1125eb169c76SMark Cave-Ayland type_register_static(&esp_info); 1126cfb9de9cSPaul Brook } 1127cfb9de9cSPaul Brook 112883f7d43aSAndreas Färber type_init(esp_register_types) 1129