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 130761bef75SMark Cave-Ayland static uint8_t esp_pdma_read(ESPState *s) 131761bef75SMark Cave-Ayland { 1328da90e81SMark Cave-Ayland uint8_t val; 1338da90e81SMark Cave-Ayland 13402abe246SMark Cave-Ayland if (s->do_cmd) { 135bb0bc7bbSMark Cave-Ayland val = s->cmdbuf[s->cmdlen++]; 13602abe246SMark Cave-Ayland } else { 13702abe246SMark Cave-Ayland val = s->ti_buf[s->ti_rptr++]; 13802abe246SMark Cave-Ayland } 1398da90e81SMark Cave-Ayland 1408da90e81SMark Cave-Ayland return val; 141761bef75SMark Cave-Ayland } 142761bef75SMark Cave-Ayland 143761bef75SMark Cave-Ayland static void esp_pdma_write(ESPState *s, uint8_t val) 144761bef75SMark Cave-Ayland { 1458da90e81SMark Cave-Ayland uint32_t dmalen = esp_get_tc(s); 1468da90e81SMark Cave-Ayland 1473c421400SMark Cave-Ayland if (dmalen == 0) { 1488da90e81SMark Cave-Ayland return; 1498da90e81SMark Cave-Ayland } 1508da90e81SMark Cave-Ayland 15102abe246SMark Cave-Ayland if (s->do_cmd) { 152bb0bc7bbSMark Cave-Ayland s->cmdbuf[s->cmdlen++] = val; 15302abe246SMark Cave-Ayland } else { 15402abe246SMark Cave-Ayland s->ti_buf[s->ti_wptr++] = val; 15502abe246SMark Cave-Ayland } 1568da90e81SMark Cave-Ayland 1578da90e81SMark Cave-Ayland dmalen--; 1588da90e81SMark Cave-Ayland esp_set_tc(s, dmalen); 159761bef75SMark Cave-Ayland } 160761bef75SMark Cave-Ayland 161c7bce09cSMark Cave-Ayland static int esp_select(ESPState *s) 1626130b188SLaurent Vivier { 1636130b188SLaurent Vivier int target; 1646130b188SLaurent Vivier 1656130b188SLaurent Vivier target = s->wregs[ESP_WBUSID] & BUSID_DID; 1666130b188SLaurent Vivier 1676130b188SLaurent Vivier s->ti_size = 0; 1686130b188SLaurent Vivier s->ti_rptr = 0; 1696130b188SLaurent Vivier s->ti_wptr = 0; 1706130b188SLaurent Vivier 1716130b188SLaurent Vivier if (s->current_req) { 1726130b188SLaurent Vivier /* Started a new command before the old one finished. Cancel it. */ 1736130b188SLaurent Vivier scsi_req_cancel(s->current_req); 1746130b188SLaurent Vivier s->async_len = 0; 1756130b188SLaurent Vivier } 1766130b188SLaurent Vivier 1776130b188SLaurent Vivier s->current_dev = scsi_device_find(&s->bus, 0, target, 0); 1786130b188SLaurent Vivier if (!s->current_dev) { 1796130b188SLaurent Vivier /* No such drive */ 1806130b188SLaurent Vivier s->rregs[ESP_RSTAT] = 0; 181*cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_DC; 1826130b188SLaurent Vivier s->rregs[ESP_RSEQ] = SEQ_0; 1836130b188SLaurent Vivier esp_raise_irq(s); 1846130b188SLaurent Vivier return -1; 1856130b188SLaurent Vivier } 1866130b188SLaurent Vivier return 0; 1876130b188SLaurent Vivier } 1886130b188SLaurent Vivier 189cfcea0f9SMark Cave-Ayland static uint32_t get_cmd(ESPState *s) 1902f275b8fSbellard { 191cfcea0f9SMark Cave-Ayland uint8_t *buf = s->cmdbuf; 192a917d384Spbrook uint32_t dmalen; 1932f275b8fSbellard int target; 1942f275b8fSbellard 1958dea1dd4Sblueswir1 target = s->wregs[ESP_WBUSID] & BUSID_DID; 1964f6200f0Sbellard if (s->dma) { 197c47b5835SMark Cave-Ayland dmalen = esp_get_tc(s); 198cfcea0f9SMark Cave-Ayland if (dmalen > ESP_CMDBUF_SZ) { 1996c1fef6bSPrasad J Pandit return 0; 2006c1fef6bSPrasad J Pandit } 20174d71ea1SLaurent Vivier if (s->dma_memory_read) { 2028b17de88Sblueswir1 s->dma_memory_read(s->dma_opaque, buf, dmalen); 2034f6200f0Sbellard } else { 20449691315SMark Cave-Ayland if (esp_select(s) < 0) { 20549691315SMark Cave-Ayland return -1; 20649691315SMark Cave-Ayland } 20774d71ea1SLaurent Vivier esp_raise_drq(s); 20874d71ea1SLaurent Vivier return 0; 20974d71ea1SLaurent Vivier } 21074d71ea1SLaurent Vivier } else { 211fc4d65daSblueswir1 dmalen = s->ti_size; 212d3cdc491SPrasad J Pandit if (dmalen > TI_BUFSZ) { 213d3cdc491SPrasad J Pandit return 0; 214d3cdc491SPrasad J Pandit } 215fc4d65daSblueswir1 memcpy(buf, s->ti_buf, dmalen); 21675ef8496SHervé Poussineau buf[0] = buf[2] >> 5; 2174f6200f0Sbellard } 218bf4b9889SBlue Swirl trace_esp_get_cmd(dmalen, target); 2192e5d83bbSpbrook 220c7bce09cSMark Cave-Ayland if (esp_select(s) < 0) { 22149691315SMark Cave-Ayland return -1; 2222f275b8fSbellard } 2239f149aa9Spbrook return dmalen; 2249f149aa9Spbrook } 2259f149aa9Spbrook 226f2818f22SArtyom Tarasenko static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) 2279f149aa9Spbrook { 2289f149aa9Spbrook int32_t datalen; 2299f149aa9Spbrook int lun; 230f48a7a6eSPaolo Bonzini SCSIDevice *current_lun; 2319f149aa9Spbrook 232bf4b9889SBlue Swirl trace_esp_do_busid_cmd(busid); 233f2818f22SArtyom Tarasenko lun = busid & 7; 2340d3545e7SPaolo Bonzini current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun); 235e6810db8SHervé Poussineau s->current_req = scsi_req_new(current_lun, 0, lun, buf, s); 236c39ce112SPaolo Bonzini datalen = scsi_req_enqueue(s->current_req); 23767e999beSbellard s->ti_size = datalen; 23867e999beSbellard if (datalen != 0) { 239c73f96fdSblueswir1 s->rregs[ESP_RSTAT] = STAT_TC; 2406cc88d6bSMark Cave-Ayland esp_set_tc(s, 0); 2412e5d83bbSpbrook if (datalen > 0) { 2425ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] |= STAT_DI; 2434f6200f0Sbellard } else { 2445ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] |= STAT_DO; 2454f6200f0Sbellard } 246ad3376ccSPaolo Bonzini scsi_req_continue(s->current_req); 2474e9aec74Spbrook } 248*cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 2495ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = SEQ_CD; 250c73f96fdSblueswir1 esp_raise_irq(s); 25182141c8bSMark Cave-Ayland esp_lower_drq(s); 2522f275b8fSbellard } 2532f275b8fSbellard 254c959f218SMark Cave-Ayland static void do_cmd(ESPState *s) 255f2818f22SArtyom Tarasenko { 256c959f218SMark Cave-Ayland uint8_t *buf = s->cmdbuf; 257f2818f22SArtyom Tarasenko uint8_t busid = buf[0]; 258f2818f22SArtyom Tarasenko 259f2818f22SArtyom Tarasenko do_busid_cmd(s, &buf[1], busid); 260f2818f22SArtyom Tarasenko } 261f2818f22SArtyom Tarasenko 26274d71ea1SLaurent Vivier static void satn_pdma_cb(ESPState *s) 26374d71ea1SLaurent Vivier { 264bb0bc7bbSMark Cave-Ayland s->do_cmd = 0; 265bb0bc7bbSMark Cave-Ayland if (s->cmdlen) { 266c959f218SMark Cave-Ayland do_cmd(s); 26774d71ea1SLaurent Vivier } 26874d71ea1SLaurent Vivier } 26974d71ea1SLaurent Vivier 2709f149aa9Spbrook static void handle_satn(ESPState *s) 2719f149aa9Spbrook { 27249691315SMark Cave-Ayland int32_t cmdlen; 27349691315SMark Cave-Ayland 2741b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 27573d74342SBlue Swirl s->dma_cb = handle_satn; 27673d74342SBlue Swirl return; 27773d74342SBlue Swirl } 27874d71ea1SLaurent Vivier s->pdma_cb = satn_pdma_cb; 27949691315SMark Cave-Ayland cmdlen = get_cmd(s); 28049691315SMark Cave-Ayland if (cmdlen > 0) { 28149691315SMark Cave-Ayland s->cmdlen = cmdlen; 282c959f218SMark Cave-Ayland do_cmd(s); 28349691315SMark Cave-Ayland } else if (cmdlen == 0) { 28449691315SMark Cave-Ayland s->cmdlen = 0; 285bb0bc7bbSMark Cave-Ayland s->do_cmd = 1; 28649691315SMark Cave-Ayland /* Target present, but no cmd yet - switch to command phase */ 28749691315SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 28849691315SMark Cave-Ayland s->rregs[ESP_RSTAT] = STAT_CD; 2899f149aa9Spbrook } 29094d5c79dSMark Cave-Ayland } 2919f149aa9Spbrook 29274d71ea1SLaurent Vivier static void s_without_satn_pdma_cb(ESPState *s) 29374d71ea1SLaurent Vivier { 294bb0bc7bbSMark Cave-Ayland s->do_cmd = 0; 295bb0bc7bbSMark Cave-Ayland if (s->cmdlen) { 2962c573cfeSMark Cave-Ayland do_busid_cmd(s, s->cmdbuf, 0); 29774d71ea1SLaurent Vivier } 29874d71ea1SLaurent Vivier } 29974d71ea1SLaurent Vivier 300f2818f22SArtyom Tarasenko static void handle_s_without_atn(ESPState *s) 301f2818f22SArtyom Tarasenko { 30249691315SMark Cave-Ayland int32_t cmdlen; 30349691315SMark Cave-Ayland 3041b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 30573d74342SBlue Swirl s->dma_cb = handle_s_without_atn; 30673d74342SBlue Swirl return; 30773d74342SBlue Swirl } 30874d71ea1SLaurent Vivier s->pdma_cb = s_without_satn_pdma_cb; 30949691315SMark Cave-Ayland cmdlen = get_cmd(s); 31049691315SMark Cave-Ayland if (cmdlen > 0) { 31149691315SMark Cave-Ayland s->cmdlen = cmdlen; 312bb0bc7bbSMark Cave-Ayland do_busid_cmd(s, s->cmdbuf, 0); 31349691315SMark Cave-Ayland } else if (cmdlen == 0) { 31449691315SMark Cave-Ayland s->cmdlen = 0; 315bb0bc7bbSMark Cave-Ayland s->do_cmd = 1; 31649691315SMark Cave-Ayland /* Target present, but no cmd yet - switch to command phase */ 31749691315SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 31849691315SMark Cave-Ayland s->rregs[ESP_RSTAT] = STAT_CD; 319f2818f22SArtyom Tarasenko } 320f2818f22SArtyom Tarasenko } 321f2818f22SArtyom Tarasenko 32274d71ea1SLaurent Vivier static void satn_stop_pdma_cb(ESPState *s) 32374d71ea1SLaurent Vivier { 324bb0bc7bbSMark Cave-Ayland s->do_cmd = 0; 32574d71ea1SLaurent Vivier if (s->cmdlen) { 32674d71ea1SLaurent Vivier trace_esp_handle_satn_stop(s->cmdlen); 32774d71ea1SLaurent Vivier s->do_cmd = 1; 32874d71ea1SLaurent Vivier s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; 329*cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 33074d71ea1SLaurent Vivier s->rregs[ESP_RSEQ] = SEQ_CD; 33174d71ea1SLaurent Vivier esp_raise_irq(s); 33274d71ea1SLaurent Vivier } 33374d71ea1SLaurent Vivier } 33474d71ea1SLaurent Vivier 3359f149aa9Spbrook static void handle_satn_stop(ESPState *s) 3369f149aa9Spbrook { 33749691315SMark Cave-Ayland int32_t cmdlen; 33849691315SMark Cave-Ayland 3391b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 34073d74342SBlue Swirl s->dma_cb = handle_satn_stop; 34173d74342SBlue Swirl return; 34273d74342SBlue Swirl } 343c62c1fa0SPhilippe Mathieu-Daudé s->pdma_cb = satn_stop_pdma_cb; 34449691315SMark Cave-Ayland cmdlen = get_cmd(s); 34549691315SMark Cave-Ayland if (cmdlen > 0) { 346bf4b9889SBlue Swirl trace_esp_handle_satn_stop(s->cmdlen); 34749691315SMark Cave-Ayland s->cmdlen = cmdlen; 3489f149aa9Spbrook s->do_cmd = 1; 349*cf47a41eSMark Cave-Ayland s->rregs[ESP_RSTAT] = STAT_CD; 350*cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 3515ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = SEQ_CD; 352c73f96fdSblueswir1 esp_raise_irq(s); 35349691315SMark Cave-Ayland } else if (cmdlen == 0) { 35449691315SMark Cave-Ayland s->cmdlen = 0; 355bb0bc7bbSMark Cave-Ayland s->do_cmd = 1; 35649691315SMark Cave-Ayland /* Target present, but no cmd yet - switch to command phase */ 35749691315SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 35849691315SMark Cave-Ayland s->rregs[ESP_RSTAT] = STAT_CD; 3599f149aa9Spbrook } 3609f149aa9Spbrook } 3619f149aa9Spbrook 36274d71ea1SLaurent Vivier static void write_response_pdma_cb(ESPState *s) 36374d71ea1SLaurent Vivier { 36474d71ea1SLaurent Vivier s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; 365*cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 36674d71ea1SLaurent Vivier s->rregs[ESP_RSEQ] = SEQ_CD; 36774d71ea1SLaurent Vivier esp_raise_irq(s); 36874d71ea1SLaurent Vivier } 36974d71ea1SLaurent Vivier 3700fc5c15aSpbrook static void write_response(ESPState *s) 3712f275b8fSbellard { 372bf4b9889SBlue Swirl trace_esp_write_response(s->status); 3733944966dSPaolo Bonzini s->ti_buf[0] = s->status; 3740fc5c15aSpbrook s->ti_buf[1] = 0; 3754f6200f0Sbellard if (s->dma) { 37674d71ea1SLaurent Vivier if (s->dma_memory_write) { 3778b17de88Sblueswir1 s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); 378c73f96fdSblueswir1 s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; 379*cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 3805ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = SEQ_CD; 3814f6200f0Sbellard } else { 38274d71ea1SLaurent Vivier s->pdma_cb = write_response_pdma_cb; 38374d71ea1SLaurent Vivier esp_raise_drq(s); 38474d71ea1SLaurent Vivier return; 38574d71ea1SLaurent Vivier } 38674d71ea1SLaurent Vivier } else { 3870fc5c15aSpbrook s->ti_size = 2; 3884f6200f0Sbellard s->ti_rptr = 0; 389d020aa50SPaolo Bonzini s->ti_wptr = 2; 3905ad6bb97Sblueswir1 s->rregs[ESP_RFLAGS] = 2; 3914f6200f0Sbellard } 392c73f96fdSblueswir1 esp_raise_irq(s); 3932f275b8fSbellard } 3944f6200f0Sbellard 395a917d384Spbrook static void esp_dma_done(ESPState *s) 3964d611c9aSpbrook { 397c73f96fdSblueswir1 s->rregs[ESP_RSTAT] |= STAT_TC; 398*cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 3995ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = 0; 4005ad6bb97Sblueswir1 s->rregs[ESP_RFLAGS] = 0; 401c47b5835SMark Cave-Ayland esp_set_tc(s, 0); 402c73f96fdSblueswir1 esp_raise_irq(s); 4034d611c9aSpbrook } 404a917d384Spbrook 40574d71ea1SLaurent Vivier static void do_dma_pdma_cb(ESPState *s) 40674d71ea1SLaurent Vivier { 4074ca2ba6fSMark Cave-Ayland int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO); 40882141c8bSMark Cave-Ayland int len; 4096cc88d6bSMark Cave-Ayland 41074d71ea1SLaurent Vivier if (s->do_cmd) { 41174d71ea1SLaurent Vivier s->ti_size = 0; 41274d71ea1SLaurent Vivier s->cmdlen = 0; 41374d71ea1SLaurent Vivier s->do_cmd = 0; 414c959f218SMark Cave-Ayland do_cmd(s); 41582141c8bSMark Cave-Ayland esp_lower_drq(s); 41674d71ea1SLaurent Vivier return; 41774d71ea1SLaurent Vivier } 41882141c8bSMark Cave-Ayland 41982141c8bSMark Cave-Ayland if (to_device) { 42082141c8bSMark Cave-Ayland /* Copy FIFO data to device */ 42182141c8bSMark Cave-Ayland len = MIN(s->ti_wptr, TI_BUFSZ); 42282141c8bSMark Cave-Ayland memcpy(s->async_buf, s->ti_buf, len); 42382141c8bSMark Cave-Ayland s->ti_wptr = 0; 42482141c8bSMark Cave-Ayland s->ti_rptr = 0; 42582141c8bSMark Cave-Ayland s->async_buf += len; 42682141c8bSMark Cave-Ayland s->async_len -= len; 42782141c8bSMark Cave-Ayland s->ti_size += len; 42874d71ea1SLaurent Vivier if (s->async_len == 0) { 42974d71ea1SLaurent Vivier scsi_req_continue(s->current_req); 43082141c8bSMark Cave-Ayland return; 43182141c8bSMark Cave-Ayland } 43282141c8bSMark Cave-Ayland 43382141c8bSMark Cave-Ayland if (esp_get_tc(s) == 0) { 43482141c8bSMark Cave-Ayland esp_lower_drq(s); 43582141c8bSMark Cave-Ayland esp_dma_done(s); 43682141c8bSMark Cave-Ayland } 43782141c8bSMark Cave-Ayland 43882141c8bSMark Cave-Ayland return; 43982141c8bSMark Cave-Ayland } else { 44082141c8bSMark Cave-Ayland if (s->async_len == 0) { 44182141c8bSMark Cave-Ayland if (s->current_req) { 44282141c8bSMark Cave-Ayland scsi_req_continue(s->current_req); 44382141c8bSMark Cave-Ayland } 44482141c8bSMark Cave-Ayland 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 */ 45082141c8bSMark Cave-Ayland if (esp_get_tc(s) != 0 || s->ti_size == 0) { 45174d71ea1SLaurent Vivier return; 45274d71ea1SLaurent Vivier } 45374d71ea1SLaurent Vivier } 45474d71ea1SLaurent Vivier 45582141c8bSMark Cave-Ayland if (esp_get_tc(s) != 0) { 45682141c8bSMark Cave-Ayland /* Copy device data to FIFO */ 45782141c8bSMark Cave-Ayland s->ti_wptr = 0; 45882141c8bSMark Cave-Ayland s->ti_rptr = 0; 45982141c8bSMark Cave-Ayland len = MIN(s->async_len, TI_BUFSZ); 46082141c8bSMark Cave-Ayland memcpy(s->ti_buf, s->async_buf, len); 46182141c8bSMark Cave-Ayland s->ti_wptr += len; 46282141c8bSMark Cave-Ayland s->async_buf += len; 46382141c8bSMark Cave-Ayland s->async_len -= len; 46482141c8bSMark Cave-Ayland s->ti_size -= len; 46582141c8bSMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 46682141c8bSMark Cave-Ayland return; 46782141c8bSMark Cave-Ayland } 46882141c8bSMark Cave-Ayland 46974d71ea1SLaurent Vivier /* Partially filled a scsi buffer. Complete immediately. */ 47082141c8bSMark Cave-Ayland esp_lower_drq(s); 47174d71ea1SLaurent Vivier esp_dma_done(s); 47274d71ea1SLaurent Vivier } 47382141c8bSMark Cave-Ayland } 47474d71ea1SLaurent Vivier 475a917d384Spbrook static void esp_do_dma(ESPState *s) 476a917d384Spbrook { 47767e999beSbellard uint32_t len; 4784ca2ba6fSMark Cave-Ayland int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO); 479a917d384Spbrook 4806cc88d6bSMark Cave-Ayland len = esp_get_tc(s); 481a917d384Spbrook if (s->do_cmd) { 48215407433SLaurent Vivier /* 48315407433SLaurent Vivier * handle_ti_cmd() case: esp_do_dma() is called only from 48415407433SLaurent Vivier * handle_ti_cmd() with do_cmd != NULL (see the assert()) 48515407433SLaurent Vivier */ 486bf4b9889SBlue Swirl trace_esp_do_dma(s->cmdlen, len); 487926cde5fSPrasad J Pandit assert(s->cmdlen <= sizeof(s->cmdbuf) && 488926cde5fSPrasad J Pandit len <= sizeof(s->cmdbuf) - s->cmdlen); 48974d71ea1SLaurent Vivier if (s->dma_memory_read) { 4908b17de88Sblueswir1 s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); 49174d71ea1SLaurent Vivier } else { 49274d71ea1SLaurent Vivier s->pdma_cb = do_dma_pdma_cb; 49374d71ea1SLaurent Vivier esp_raise_drq(s); 49474d71ea1SLaurent Vivier return; 49574d71ea1SLaurent Vivier } 49615407433SLaurent Vivier trace_esp_handle_ti_cmd(s->cmdlen); 49715407433SLaurent Vivier s->ti_size = 0; 49815407433SLaurent Vivier s->cmdlen = 0; 49915407433SLaurent Vivier s->do_cmd = 0; 500c959f218SMark Cave-Ayland do_cmd(s); 501a917d384Spbrook return; 502a917d384Spbrook } 503a917d384Spbrook if (s->async_len == 0) { 504a917d384Spbrook /* Defer until data is available. */ 505a917d384Spbrook return; 506a917d384Spbrook } 507a917d384Spbrook if (len > s->async_len) { 508a917d384Spbrook len = s->async_len; 509a917d384Spbrook } 510a917d384Spbrook if (to_device) { 51174d71ea1SLaurent Vivier if (s->dma_memory_read) { 5128b17de88Sblueswir1 s->dma_memory_read(s->dma_opaque, s->async_buf, len); 513a917d384Spbrook } else { 51474d71ea1SLaurent Vivier s->pdma_cb = do_dma_pdma_cb; 51574d71ea1SLaurent Vivier esp_raise_drq(s); 51674d71ea1SLaurent Vivier return; 51774d71ea1SLaurent Vivier } 51874d71ea1SLaurent Vivier } else { 51974d71ea1SLaurent Vivier if (s->dma_memory_write) { 5208b17de88Sblueswir1 s->dma_memory_write(s->dma_opaque, s->async_buf, len); 52174d71ea1SLaurent Vivier } else { 52282141c8bSMark Cave-Ayland /* Copy device data to FIFO */ 52382141c8bSMark Cave-Ayland len = MIN(len, TI_BUFSZ - s->ti_wptr); 52482141c8bSMark Cave-Ayland memcpy(&s->ti_buf[s->ti_wptr], s->async_buf, len); 52582141c8bSMark Cave-Ayland s->ti_wptr += len; 52682141c8bSMark Cave-Ayland s->async_buf += len; 52782141c8bSMark Cave-Ayland s->async_len -= len; 52882141c8bSMark Cave-Ayland s->ti_size -= len; 52982141c8bSMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 53074d71ea1SLaurent Vivier s->pdma_cb = do_dma_pdma_cb; 53174d71ea1SLaurent Vivier esp_raise_drq(s); 53282141c8bSMark Cave-Ayland 53382141c8bSMark Cave-Ayland /* Indicate transfer to FIFO is complete */ 53482141c8bSMark Cave-Ayland s->rregs[ESP_RSTAT] |= STAT_TC; 53574d71ea1SLaurent Vivier return; 53674d71ea1SLaurent Vivier } 537a917d384Spbrook } 5386cc88d6bSMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 539a917d384Spbrook s->async_buf += len; 540a917d384Spbrook s->async_len -= len; 54194d5c79dSMark Cave-Ayland if (to_device) { 5426787f5faSpbrook s->ti_size += len; 54394d5c79dSMark Cave-Ayland } else { 5446787f5faSpbrook s->ti_size -= len; 54594d5c79dSMark Cave-Ayland } 546a917d384Spbrook if (s->async_len == 0) { 547ad3376ccSPaolo Bonzini scsi_req_continue(s->current_req); 54894d5c79dSMark Cave-Ayland /* 54994d5c79dSMark Cave-Ayland * If there is still data to be read from the device then 55094d5c79dSMark Cave-Ayland * complete the DMA operation immediately. Otherwise defer 55194d5c79dSMark Cave-Ayland * until the scsi layer has completed. 55294d5c79dSMark Cave-Ayland */ 5536cc88d6bSMark Cave-Ayland if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) { 554ad3376ccSPaolo Bonzini return; 555a917d384Spbrook } 556a917d384Spbrook } 557ad3376ccSPaolo Bonzini 5586787f5faSpbrook /* Partially filled a scsi buffer. Complete immediately. */ 559a917d384Spbrook esp_dma_done(s); 56082141c8bSMark Cave-Ayland esp_lower_drq(s); 561a917d384Spbrook } 562a917d384Spbrook 563ea84a442SGuenter Roeck static void esp_report_command_complete(ESPState *s, uint32_t status) 564a917d384Spbrook { 565bf4b9889SBlue Swirl trace_esp_command_complete(); 566c6df7102SPaolo Bonzini if (s->ti_size != 0) { 567bf4b9889SBlue Swirl trace_esp_command_complete_unexpected(); 568c6df7102SPaolo Bonzini } 569a917d384Spbrook s->ti_size = 0; 570a917d384Spbrook s->async_len = 0; 571aba1f023SPaolo Bonzini if (status) { 572bf4b9889SBlue Swirl trace_esp_command_complete_fail(); 573c6df7102SPaolo Bonzini } 574aba1f023SPaolo Bonzini s->status = status; 5755ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] = STAT_ST; 576a917d384Spbrook esp_dma_done(s); 57782141c8bSMark Cave-Ayland esp_lower_drq(s); 5785c6c0e51SHannes Reinecke if (s->current_req) { 5795c6c0e51SHannes Reinecke scsi_req_unref(s->current_req); 5805c6c0e51SHannes Reinecke s->current_req = NULL; 581a917d384Spbrook s->current_dev = NULL; 5825c6c0e51SHannes Reinecke } 583c6df7102SPaolo Bonzini } 584c6df7102SPaolo Bonzini 58517ea26c2SHannes Reinecke void esp_command_complete(SCSIRequest *req, size_t resid) 586ea84a442SGuenter Roeck { 587ea84a442SGuenter Roeck ESPState *s = req->hba_private; 588ea84a442SGuenter Roeck 589ea84a442SGuenter Roeck if (s->rregs[ESP_RSTAT] & STAT_INT) { 59094d5c79dSMark Cave-Ayland /* 59194d5c79dSMark Cave-Ayland * Defer handling command complete until the previous 592ea84a442SGuenter Roeck * interrupt has been handled. 593ea84a442SGuenter Roeck */ 594ea84a442SGuenter Roeck trace_esp_command_complete_deferred(); 59517ea26c2SHannes Reinecke s->deferred_status = req->status; 596ea84a442SGuenter Roeck s->deferred_complete = true; 597ea84a442SGuenter Roeck return; 598ea84a442SGuenter Roeck } 59917ea26c2SHannes Reinecke esp_report_command_complete(s, req->status); 600ea84a442SGuenter Roeck } 601ea84a442SGuenter Roeck 6029c7e23fcSHervé Poussineau void esp_transfer_data(SCSIRequest *req, uint32_t len) 603c6df7102SPaolo Bonzini { 604e6810db8SHervé Poussineau ESPState *s = req->hba_private; 6056cc88d6bSMark Cave-Ayland uint32_t dmalen = esp_get_tc(s); 606c6df7102SPaolo Bonzini 6077f0b6e11SPaolo Bonzini assert(!s->do_cmd); 6086cc88d6bSMark Cave-Ayland trace_esp_transfer_data(dmalen, s->ti_size); 609aba1f023SPaolo Bonzini s->async_len = len; 6100c34459bSPaolo Bonzini s->async_buf = scsi_req_get_buf(req); 6116cc88d6bSMark Cave-Ayland if (dmalen) { 612a917d384Spbrook esp_do_dma(s); 6135eb7a23fSMark Cave-Ayland } else if (s->ti_size <= 0) { 61494d5c79dSMark Cave-Ayland /* 61594d5c79dSMark Cave-Ayland * If this was the last part of a DMA transfer then the 61694d5c79dSMark Cave-Ayland * completion interrupt is deferred to here. 61794d5c79dSMark Cave-Ayland */ 6186787f5faSpbrook esp_dma_done(s); 61982141c8bSMark Cave-Ayland esp_lower_drq(s); 6206787f5faSpbrook } 621a917d384Spbrook } 6222e5d83bbSpbrook 6232f275b8fSbellard static void handle_ti(ESPState *s) 6242f275b8fSbellard { 625b76624deSMark Cave-Ayland uint32_t dmalen; 6262f275b8fSbellard 6277246e160SHervé Poussineau if (s->dma && !s->dma_enabled) { 6287246e160SHervé Poussineau s->dma_cb = handle_ti; 6297246e160SHervé Poussineau return; 6307246e160SHervé Poussineau } 6317246e160SHervé Poussineau 632c47b5835SMark Cave-Ayland dmalen = esp_get_tc(s); 6334f6200f0Sbellard if (s->dma) { 634b76624deSMark Cave-Ayland trace_esp_handle_ti(dmalen); 6355ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] &= ~STAT_TC; 6364d611c9aSpbrook esp_do_dma(s); 63715407433SLaurent Vivier } else if (s->do_cmd) { 638bf4b9889SBlue Swirl trace_esp_handle_ti_cmd(s->cmdlen); 6399f149aa9Spbrook s->ti_size = 0; 6409f149aa9Spbrook s->cmdlen = 0; 6419f149aa9Spbrook s->do_cmd = 0; 642c959f218SMark Cave-Ayland do_cmd(s); 6434f6200f0Sbellard } 6442f275b8fSbellard } 6452f275b8fSbellard 6469c7e23fcSHervé Poussineau void esp_hard_reset(ESPState *s) 6476f7e9aecSbellard { 6485aca8c3bSblueswir1 memset(s->rregs, 0, ESP_REGS); 6495aca8c3bSblueswir1 memset(s->wregs, 0, ESP_REGS); 650c9cf45c1SHannes Reinecke s->tchi_written = 0; 6514e9aec74Spbrook s->ti_size = 0; 6524e9aec74Spbrook s->ti_rptr = 0; 6534e9aec74Spbrook s->ti_wptr = 0; 6544e9aec74Spbrook s->dma = 0; 6559f149aa9Spbrook s->do_cmd = 0; 65673d74342SBlue Swirl s->dma_cb = NULL; 6578dea1dd4Sblueswir1 6588dea1dd4Sblueswir1 s->rregs[ESP_CFG1] = 7; 6596f7e9aecSbellard } 6606f7e9aecSbellard 661a391fdbcSHervé Poussineau static void esp_soft_reset(ESPState *s) 66285948643SBlue Swirl { 66385948643SBlue Swirl qemu_irq_lower(s->irq); 66474d71ea1SLaurent Vivier qemu_irq_lower(s->irq_data); 665a391fdbcSHervé Poussineau esp_hard_reset(s); 66685948643SBlue Swirl } 66785948643SBlue Swirl 668a391fdbcSHervé Poussineau static void parent_esp_reset(ESPState *s, int irq, int level) 6692d069babSblueswir1 { 67085948643SBlue Swirl if (level) { 671a391fdbcSHervé Poussineau esp_soft_reset(s); 67285948643SBlue Swirl } 6732d069babSblueswir1 } 6742d069babSblueswir1 6759c7e23fcSHervé Poussineau uint64_t esp_reg_read(ESPState *s, uint32_t saddr) 67673d74342SBlue Swirl { 677b630c075SMark Cave-Ayland uint32_t val; 67873d74342SBlue Swirl 6796f7e9aecSbellard switch (saddr) { 6805ad6bb97Sblueswir1 case ESP_FIFO: 6815ad6bb97Sblueswir1 if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) { 6828dea1dd4Sblueswir1 /* Data out. */ 683ff589551SPrasad J Pandit qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n"); 6845ad6bb97Sblueswir1 s->rregs[ESP_FIFO] = 0; 685ff589551SPrasad J Pandit } else if (s->ti_rptr < s->ti_wptr) { 686ff589551SPrasad J Pandit s->ti_size--; 6875ad6bb97Sblueswir1 s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; 6884f6200f0Sbellard } 689ff589551SPrasad J Pandit if (s->ti_rptr == s->ti_wptr) { 6904f6200f0Sbellard s->ti_rptr = 0; 6914f6200f0Sbellard s->ti_wptr = 0; 6924f6200f0Sbellard } 693b630c075SMark Cave-Ayland val = s->rregs[ESP_FIFO]; 6944f6200f0Sbellard break; 6955ad6bb97Sblueswir1 case ESP_RINTR: 69694d5c79dSMark Cave-Ayland /* 69794d5c79dSMark Cave-Ayland * Clear sequence step, interrupt register and all status bits 69894d5c79dSMark Cave-Ayland * except TC 69994d5c79dSMark Cave-Ayland */ 700b630c075SMark Cave-Ayland val = s->rregs[ESP_RINTR]; 7012814df28SBlue Swirl s->rregs[ESP_RINTR] = 0; 7022814df28SBlue Swirl s->rregs[ESP_RSTAT] &= ~STAT_TC; 703*cf47a41eSMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_0; 704c73f96fdSblueswir1 esp_lower_irq(s); 705ea84a442SGuenter Roeck if (s->deferred_complete) { 706ea84a442SGuenter Roeck esp_report_command_complete(s, s->deferred_status); 707ea84a442SGuenter Roeck s->deferred_complete = false; 708ea84a442SGuenter Roeck } 709b630c075SMark Cave-Ayland break; 710c9cf45c1SHannes Reinecke case ESP_TCHI: 711c9cf45c1SHannes Reinecke /* Return the unique id if the value has never been written */ 712c9cf45c1SHannes Reinecke if (!s->tchi_written) { 713b630c075SMark Cave-Ayland val = s->chip_id; 714b630c075SMark Cave-Ayland } else { 715b630c075SMark Cave-Ayland val = s->rregs[saddr]; 716c9cf45c1SHannes Reinecke } 717b630c075SMark Cave-Ayland break; 7186f7e9aecSbellard default: 719b630c075SMark Cave-Ayland val = s->rregs[saddr]; 7206f7e9aecSbellard break; 7216f7e9aecSbellard } 722b630c075SMark Cave-Ayland 723b630c075SMark Cave-Ayland trace_esp_mem_readb(saddr, val); 724b630c075SMark Cave-Ayland return val; 7256f7e9aecSbellard } 7266f7e9aecSbellard 7279c7e23fcSHervé Poussineau void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) 7286f7e9aecSbellard { 729bf4b9889SBlue Swirl trace_esp_mem_writeb(saddr, s->wregs[saddr], val); 7306f7e9aecSbellard switch (saddr) { 731c9cf45c1SHannes Reinecke case ESP_TCHI: 732c9cf45c1SHannes Reinecke s->tchi_written = true; 733c9cf45c1SHannes Reinecke /* fall through */ 7345ad6bb97Sblueswir1 case ESP_TCLO: 7355ad6bb97Sblueswir1 case ESP_TCMID: 7365ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] &= ~STAT_TC; 7374f6200f0Sbellard break; 7385ad6bb97Sblueswir1 case ESP_FIFO: 7399f149aa9Spbrook if (s->do_cmd) { 740926cde5fSPrasad J Pandit if (s->cmdlen < ESP_CMDBUF_SZ) { 7419f149aa9Spbrook s->cmdbuf[s->cmdlen++] = val & 0xff; 742c98c6c10SPrasad J Pandit } else { 743c98c6c10SPrasad J Pandit trace_esp_error_fifo_overrun(); 744c98c6c10SPrasad J Pandit } 745ff589551SPrasad J Pandit } else if (s->ti_wptr == TI_BUFSZ - 1) { 7463af4e9aaSHervé Poussineau trace_esp_error_fifo_overrun(); 7472e5d83bbSpbrook } else { 7484f6200f0Sbellard s->ti_size++; 7494f6200f0Sbellard s->ti_buf[s->ti_wptr++] = val & 0xff; 7502e5d83bbSpbrook } 7514f6200f0Sbellard break; 7525ad6bb97Sblueswir1 case ESP_CMD: 7534f6200f0Sbellard s->rregs[saddr] = val; 7545ad6bb97Sblueswir1 if (val & CMD_DMA) { 7554f6200f0Sbellard s->dma = 1; 7566787f5faSpbrook /* Reload DMA counter. */ 75796676c2fSMark Cave-Ayland if (esp_get_stc(s) == 0) { 75896676c2fSMark Cave-Ayland esp_set_tc(s, 0x10000); 75996676c2fSMark Cave-Ayland } else { 760c04ed569SMark Cave-Ayland esp_set_tc(s, esp_get_stc(s)); 76196676c2fSMark Cave-Ayland } 7624f6200f0Sbellard } else { 7634f6200f0Sbellard s->dma = 0; 7644f6200f0Sbellard } 7655ad6bb97Sblueswir1 switch (val & CMD_CMD) { 7665ad6bb97Sblueswir1 case CMD_NOP: 767bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_nop(val); 7682f275b8fSbellard break; 7695ad6bb97Sblueswir1 case CMD_FLUSH: 770bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_flush(val); 77194d5c79dSMark Cave-Ayland /*s->ti_size = 0;*/ 772bb27b13dSMark Cave-Ayland s->ti_wptr = 0; 773bb27b13dSMark Cave-Ayland s->ti_rptr = 0; 7746f7e9aecSbellard break; 7755ad6bb97Sblueswir1 case CMD_RESET: 776bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_reset(val); 777a391fdbcSHervé Poussineau esp_soft_reset(s); 7786f7e9aecSbellard break; 7795ad6bb97Sblueswir1 case CMD_BUSRESET: 780bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_bus_reset(val); 7815ad6bb97Sblueswir1 if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) { 782*cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_RST; 783c73f96fdSblueswir1 esp_raise_irq(s); 7849e61bde5Sbellard } 7852f275b8fSbellard break; 7865ad6bb97Sblueswir1 case CMD_TI: 7870097d3ecSMark Cave-Ayland trace_esp_mem_writeb_cmd_ti(val); 7882f275b8fSbellard handle_ti(s); 7892f275b8fSbellard break; 7905ad6bb97Sblueswir1 case CMD_ICCS: 791bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_iccs(val); 7920fc5c15aSpbrook write_response(s); 793*cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_FC; 7944bf5801dSblueswir1 s->rregs[ESP_RSTAT] |= STAT_MI; 7952f275b8fSbellard break; 7965ad6bb97Sblueswir1 case CMD_MSGACC: 797bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_msgacc(val); 798*cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_DC; 7995ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = 0; 8004e2a68c1SArtyom Tarasenko s->rregs[ESP_RFLAGS] = 0; 8014e2a68c1SArtyom Tarasenko esp_raise_irq(s); 8026f7e9aecSbellard break; 8030fd0eb21SBlue Swirl case CMD_PAD: 804bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_pad(val); 8050fd0eb21SBlue Swirl s->rregs[ESP_RSTAT] = STAT_TC; 806*cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_FC; 8070fd0eb21SBlue Swirl s->rregs[ESP_RSEQ] = 0; 8080fd0eb21SBlue Swirl break; 8095ad6bb97Sblueswir1 case CMD_SATN: 810bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_satn(val); 8116f7e9aecSbellard break; 8126915bff1SHervé Poussineau case CMD_RSTATN: 8136915bff1SHervé Poussineau trace_esp_mem_writeb_cmd_rstatn(val); 8146915bff1SHervé Poussineau break; 8155e1e0a3bSBlue Swirl case CMD_SEL: 816bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_sel(val); 817f2818f22SArtyom Tarasenko handle_s_without_atn(s); 8185e1e0a3bSBlue Swirl break; 8195ad6bb97Sblueswir1 case CMD_SELATN: 820bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_selatn(val); 8212f275b8fSbellard handle_satn(s); 8222f275b8fSbellard break; 8235ad6bb97Sblueswir1 case CMD_SELATNS: 824bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_selatns(val); 8259f149aa9Spbrook handle_satn_stop(s); 8262f275b8fSbellard break; 8275ad6bb97Sblueswir1 case CMD_ENSEL: 828bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_ensel(val); 829e3926838Sblueswir1 s->rregs[ESP_RINTR] = 0; 83074ec6048Sblueswir1 break; 8316fe84c18SHervé Poussineau case CMD_DISSEL: 8326fe84c18SHervé Poussineau trace_esp_mem_writeb_cmd_dissel(val); 8336fe84c18SHervé Poussineau s->rregs[ESP_RINTR] = 0; 8346fe84c18SHervé Poussineau esp_raise_irq(s); 8356fe84c18SHervé Poussineau break; 8362f275b8fSbellard default: 8373af4e9aaSHervé Poussineau trace_esp_error_unhandled_command(val); 8386f7e9aecSbellard break; 8396f7e9aecSbellard } 8406f7e9aecSbellard break; 8415ad6bb97Sblueswir1 case ESP_WBUSID ... ESP_WSYNO: 8424f6200f0Sbellard break; 8435ad6bb97Sblueswir1 case ESP_CFG1: 8449ea73f8bSPaolo Bonzini case ESP_CFG2: case ESP_CFG3: 8459ea73f8bSPaolo Bonzini case ESP_RES3: case ESP_RES4: 8464f6200f0Sbellard s->rregs[saddr] = val; 8474f6200f0Sbellard break; 8485ad6bb97Sblueswir1 case ESP_WCCF ... ESP_WTEST: 8494f6200f0Sbellard break; 8506f7e9aecSbellard default: 8513af4e9aaSHervé Poussineau trace_esp_error_invalid_write(val, saddr); 8528dea1dd4Sblueswir1 return; 8536f7e9aecSbellard } 8542f275b8fSbellard s->wregs[saddr] = val; 8556f7e9aecSbellard } 8566f7e9aecSbellard 857a8170e5eSAvi Kivity static bool esp_mem_accepts(void *opaque, hwaddr addr, 8588372d383SPeter Maydell unsigned size, bool is_write, 8598372d383SPeter Maydell MemTxAttrs attrs) 86067bb5314SAvi Kivity { 86167bb5314SAvi Kivity return (size == 1) || (is_write && size == 4); 86267bb5314SAvi Kivity } 8636f7e9aecSbellard 8646cc88d6bSMark Cave-Ayland static bool esp_is_before_version_5(void *opaque, int version_id) 8656cc88d6bSMark Cave-Ayland { 8666cc88d6bSMark Cave-Ayland ESPState *s = ESP(opaque); 8676cc88d6bSMark Cave-Ayland 8686cc88d6bSMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 8696cc88d6bSMark Cave-Ayland return version_id < 5; 8706cc88d6bSMark Cave-Ayland } 8716cc88d6bSMark Cave-Ayland 8720bd005beSMark Cave-Ayland static int esp_pre_save(void *opaque) 8730bd005beSMark Cave-Ayland { 8740bd005beSMark Cave-Ayland ESPState *s = ESP(opaque); 8750bd005beSMark Cave-Ayland 8760bd005beSMark Cave-Ayland s->mig_version_id = vmstate_esp.version_id; 8770bd005beSMark Cave-Ayland return 0; 8780bd005beSMark Cave-Ayland } 8790bd005beSMark Cave-Ayland 8800bd005beSMark Cave-Ayland static int esp_post_load(void *opaque, int version_id) 8810bd005beSMark Cave-Ayland { 8820bd005beSMark Cave-Ayland ESPState *s = ESP(opaque); 8830bd005beSMark Cave-Ayland 8846cc88d6bSMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 8856cc88d6bSMark Cave-Ayland 8866cc88d6bSMark Cave-Ayland if (version_id < 5) { 8876cc88d6bSMark Cave-Ayland esp_set_tc(s, s->mig_dma_left); 8886cc88d6bSMark Cave-Ayland } 8896cc88d6bSMark Cave-Ayland 8900bd005beSMark Cave-Ayland s->mig_version_id = vmstate_esp.version_id; 8910bd005beSMark Cave-Ayland return 0; 8920bd005beSMark Cave-Ayland } 8930bd005beSMark Cave-Ayland 8949c7e23fcSHervé Poussineau const VMStateDescription vmstate_esp = { 895cc9952f3SBlue Swirl .name = "esp", 8960bd005beSMark Cave-Ayland .version_id = 5, 897cc9952f3SBlue Swirl .minimum_version_id = 3, 8980bd005beSMark Cave-Ayland .pre_save = esp_pre_save, 8990bd005beSMark Cave-Ayland .post_load = esp_post_load, 900cc9952f3SBlue Swirl .fields = (VMStateField[]) { 901cc9952f3SBlue Swirl VMSTATE_BUFFER(rregs, ESPState), 902cc9952f3SBlue Swirl VMSTATE_BUFFER(wregs, ESPState), 903cc9952f3SBlue Swirl VMSTATE_INT32(ti_size, ESPState), 904cc9952f3SBlue Swirl VMSTATE_UINT32(ti_rptr, ESPState), 905cc9952f3SBlue Swirl VMSTATE_UINT32(ti_wptr, ESPState), 906cc9952f3SBlue Swirl VMSTATE_BUFFER(ti_buf, ESPState), 9073944966dSPaolo Bonzini VMSTATE_UINT32(status, ESPState), 908ea84a442SGuenter Roeck VMSTATE_UINT32(deferred_status, ESPState), 909ea84a442SGuenter Roeck VMSTATE_BOOL(deferred_complete, ESPState), 910cc9952f3SBlue Swirl VMSTATE_UINT32(dma, ESPState), 911cc966774SPaolo Bonzini VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16), 912cc966774SPaolo Bonzini VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4), 913cc9952f3SBlue Swirl VMSTATE_UINT32(cmdlen, ESPState), 914cc9952f3SBlue Swirl VMSTATE_UINT32(do_cmd, ESPState), 9156cc88d6bSMark Cave-Ayland VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5), 916cc9952f3SBlue Swirl VMSTATE_END_OF_LIST() 91774d71ea1SLaurent Vivier }, 918cc9952f3SBlue Swirl }; 9196f7e9aecSbellard 920a8170e5eSAvi Kivity static void sysbus_esp_mem_write(void *opaque, hwaddr addr, 921a391fdbcSHervé Poussineau uint64_t val, unsigned int size) 922a391fdbcSHervé Poussineau { 923a391fdbcSHervé Poussineau SysBusESPState *sysbus = opaque; 924eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 925a391fdbcSHervé Poussineau uint32_t saddr; 926a391fdbcSHervé Poussineau 927a391fdbcSHervé Poussineau saddr = addr >> sysbus->it_shift; 928eb169c76SMark Cave-Ayland esp_reg_write(s, saddr, val); 929a391fdbcSHervé Poussineau } 930a391fdbcSHervé Poussineau 931a8170e5eSAvi Kivity static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr, 932a391fdbcSHervé Poussineau unsigned int size) 933a391fdbcSHervé Poussineau { 934a391fdbcSHervé Poussineau SysBusESPState *sysbus = opaque; 935eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 936a391fdbcSHervé Poussineau uint32_t saddr; 937a391fdbcSHervé Poussineau 938a391fdbcSHervé Poussineau saddr = addr >> sysbus->it_shift; 939eb169c76SMark Cave-Ayland return esp_reg_read(s, saddr); 940a391fdbcSHervé Poussineau } 941a391fdbcSHervé Poussineau 942a391fdbcSHervé Poussineau static const MemoryRegionOps sysbus_esp_mem_ops = { 943a391fdbcSHervé Poussineau .read = sysbus_esp_mem_read, 944a391fdbcSHervé Poussineau .write = sysbus_esp_mem_write, 945a391fdbcSHervé Poussineau .endianness = DEVICE_NATIVE_ENDIAN, 946a391fdbcSHervé Poussineau .valid.accepts = esp_mem_accepts, 947a391fdbcSHervé Poussineau }; 948a391fdbcSHervé Poussineau 94974d71ea1SLaurent Vivier static void sysbus_esp_pdma_write(void *opaque, hwaddr addr, 95074d71ea1SLaurent Vivier uint64_t val, unsigned int size) 95174d71ea1SLaurent Vivier { 95274d71ea1SLaurent Vivier SysBusESPState *sysbus = opaque; 953eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 9543c421400SMark Cave-Ayland uint32_t dmalen; 95574d71ea1SLaurent Vivier 956960ebfd9SMark Cave-Ayland trace_esp_pdma_write(size); 957960ebfd9SMark Cave-Ayland 95874d71ea1SLaurent Vivier switch (size) { 95974d71ea1SLaurent Vivier case 1: 960761bef75SMark Cave-Ayland esp_pdma_write(s, val); 96174d71ea1SLaurent Vivier break; 96274d71ea1SLaurent Vivier case 2: 963761bef75SMark Cave-Ayland esp_pdma_write(s, val >> 8); 964761bef75SMark Cave-Ayland esp_pdma_write(s, val); 96574d71ea1SLaurent Vivier break; 96674d71ea1SLaurent Vivier } 9673c421400SMark Cave-Ayland dmalen = esp_get_tc(s); 96882141c8bSMark Cave-Ayland if (dmalen == 0 || (s->ti_wptr == TI_BUFSZ)) { 96974d71ea1SLaurent Vivier s->pdma_cb(s); 97074d71ea1SLaurent Vivier } 97174d71ea1SLaurent Vivier } 97274d71ea1SLaurent Vivier 97374d71ea1SLaurent Vivier static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr, 97474d71ea1SLaurent Vivier unsigned int size) 97574d71ea1SLaurent Vivier { 97674d71ea1SLaurent Vivier SysBusESPState *sysbus = opaque; 977eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 97874d71ea1SLaurent Vivier uint64_t val = 0; 97974d71ea1SLaurent Vivier 980960ebfd9SMark Cave-Ayland trace_esp_pdma_read(size); 981960ebfd9SMark Cave-Ayland 98274d71ea1SLaurent Vivier switch (size) { 98374d71ea1SLaurent Vivier case 1: 984761bef75SMark Cave-Ayland val = esp_pdma_read(s); 98574d71ea1SLaurent Vivier break; 98674d71ea1SLaurent Vivier case 2: 987761bef75SMark Cave-Ayland val = esp_pdma_read(s); 988761bef75SMark Cave-Ayland val = (val << 8) | esp_pdma_read(s); 98974d71ea1SLaurent Vivier break; 99074d71ea1SLaurent Vivier } 99182141c8bSMark Cave-Ayland if (s->ti_rptr == s->ti_wptr) { 99282141c8bSMark Cave-Ayland s->ti_wptr = 0; 99382141c8bSMark Cave-Ayland s->ti_rptr = 0; 99474d71ea1SLaurent Vivier s->pdma_cb(s); 99574d71ea1SLaurent Vivier } 99674d71ea1SLaurent Vivier return val; 99774d71ea1SLaurent Vivier } 99874d71ea1SLaurent Vivier 99974d71ea1SLaurent Vivier static const MemoryRegionOps sysbus_esp_pdma_ops = { 100074d71ea1SLaurent Vivier .read = sysbus_esp_pdma_read, 100174d71ea1SLaurent Vivier .write = sysbus_esp_pdma_write, 100274d71ea1SLaurent Vivier .endianness = DEVICE_NATIVE_ENDIAN, 100374d71ea1SLaurent Vivier .valid.min_access_size = 1, 1004cf1b8286SMark Cave-Ayland .valid.max_access_size = 4, 1005cf1b8286SMark Cave-Ayland .impl.min_access_size = 1, 1006cf1b8286SMark Cave-Ayland .impl.max_access_size = 2, 100774d71ea1SLaurent Vivier }; 100874d71ea1SLaurent Vivier 1009afd4030cSPaolo Bonzini static const struct SCSIBusInfo esp_scsi_info = { 1010afd4030cSPaolo Bonzini .tcq = false, 10117e0380b9SPaolo Bonzini .max_target = ESP_MAX_DEVS, 10127e0380b9SPaolo Bonzini .max_lun = 7, 1013afd4030cSPaolo Bonzini 1014c6df7102SPaolo Bonzini .transfer_data = esp_transfer_data, 101594d3f98aSPaolo Bonzini .complete = esp_command_complete, 101694d3f98aSPaolo Bonzini .cancel = esp_request_cancelled 1017cfdc1bb0SPaolo Bonzini }; 1018cfdc1bb0SPaolo Bonzini 1019a391fdbcSHervé Poussineau static void sysbus_esp_gpio_demux(void *opaque, int irq, int level) 1020cfb9de9cSPaul Brook { 102184fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(opaque); 1022eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1023a391fdbcSHervé Poussineau 1024a391fdbcSHervé Poussineau switch (irq) { 1025a391fdbcSHervé Poussineau case 0: 1026a391fdbcSHervé Poussineau parent_esp_reset(s, irq, level); 1027a391fdbcSHervé Poussineau break; 1028a391fdbcSHervé Poussineau case 1: 1029a391fdbcSHervé Poussineau esp_dma_enable(opaque, irq, level); 1030a391fdbcSHervé Poussineau break; 1031a391fdbcSHervé Poussineau } 1032a391fdbcSHervé Poussineau } 1033a391fdbcSHervé Poussineau 1034b09318caSHu Tao static void sysbus_esp_realize(DeviceState *dev, Error **errp) 1035a391fdbcSHervé Poussineau { 1036b09318caSHu Tao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 103784fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(dev); 1038eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1039eb169c76SMark Cave-Ayland 1040eb169c76SMark Cave-Ayland if (!qdev_realize(DEVICE(s), NULL, errp)) { 1041eb169c76SMark Cave-Ayland return; 1042eb169c76SMark Cave-Ayland } 10436f7e9aecSbellard 1044b09318caSHu Tao sysbus_init_irq(sbd, &s->irq); 104574d71ea1SLaurent Vivier sysbus_init_irq(sbd, &s->irq_data); 1046a391fdbcSHervé Poussineau assert(sysbus->it_shift != -1); 10476f7e9aecSbellard 1048d32e4b3dSHervé Poussineau s->chip_id = TCHI_FAS100A; 104929776739SPaolo Bonzini memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_ops, 105074d71ea1SLaurent Vivier sysbus, "esp-regs", ESP_REGS << sysbus->it_shift); 1051b09318caSHu Tao sysbus_init_mmio(sbd, &sysbus->iomem); 105274d71ea1SLaurent Vivier memory_region_init_io(&sysbus->pdma, OBJECT(sysbus), &sysbus_esp_pdma_ops, 1053cf1b8286SMark Cave-Ayland sysbus, "esp-pdma", 4); 105474d71ea1SLaurent Vivier sysbus_init_mmio(sbd, &sysbus->pdma); 10556f7e9aecSbellard 1056b09318caSHu Tao qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2); 10572d069babSblueswir1 1058b1187b51SAndreas Färber scsi_bus_new(&s->bus, sizeof(s->bus), dev, &esp_scsi_info, NULL); 105967e999beSbellard } 1060cfb9de9cSPaul Brook 1061a391fdbcSHervé Poussineau static void sysbus_esp_hard_reset(DeviceState *dev) 1062a391fdbcSHervé Poussineau { 106384fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(dev); 1064eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1065eb169c76SMark Cave-Ayland 1066eb169c76SMark Cave-Ayland esp_hard_reset(s); 1067eb169c76SMark Cave-Ayland } 1068eb169c76SMark Cave-Ayland 1069eb169c76SMark Cave-Ayland static void sysbus_esp_init(Object *obj) 1070eb169c76SMark Cave-Ayland { 1071eb169c76SMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(obj); 1072eb169c76SMark Cave-Ayland 1073eb169c76SMark Cave-Ayland object_initialize_child(obj, "esp", &sysbus->esp, TYPE_ESP); 1074a391fdbcSHervé Poussineau } 1075a391fdbcSHervé Poussineau 1076a391fdbcSHervé Poussineau static const VMStateDescription vmstate_sysbus_esp_scsi = { 1077a391fdbcSHervé Poussineau .name = "sysbusespscsi", 10780bd005beSMark Cave-Ayland .version_id = 2, 1079ea84a442SGuenter Roeck .minimum_version_id = 1, 1080a391fdbcSHervé Poussineau .fields = (VMStateField[]) { 10810bd005beSMark Cave-Ayland VMSTATE_UINT8_V(esp.mig_version_id, SysBusESPState, 2), 1082a391fdbcSHervé Poussineau VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState), 1083a391fdbcSHervé Poussineau VMSTATE_END_OF_LIST() 1084a391fdbcSHervé Poussineau } 1085999e12bbSAnthony Liguori }; 1086999e12bbSAnthony Liguori 1087a391fdbcSHervé Poussineau static void sysbus_esp_class_init(ObjectClass *klass, void *data) 1088999e12bbSAnthony Liguori { 108939bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 1090999e12bbSAnthony Liguori 1091b09318caSHu Tao dc->realize = sysbus_esp_realize; 1092a391fdbcSHervé Poussineau dc->reset = sysbus_esp_hard_reset; 1093a391fdbcSHervé Poussineau dc->vmsd = &vmstate_sysbus_esp_scsi; 1094125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 109563235df8SBlue Swirl } 1096999e12bbSAnthony Liguori 10971f077308SHervé Poussineau static const TypeInfo sysbus_esp_info = { 109884fbefedSMark Cave-Ayland .name = TYPE_SYSBUS_ESP, 109939bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 1100eb169c76SMark Cave-Ayland .instance_init = sysbus_esp_init, 1101a391fdbcSHervé Poussineau .instance_size = sizeof(SysBusESPState), 1102a391fdbcSHervé Poussineau .class_init = sysbus_esp_class_init, 110363235df8SBlue Swirl }; 110463235df8SBlue Swirl 1105eb169c76SMark Cave-Ayland static void esp_class_init(ObjectClass *klass, void *data) 1106eb169c76SMark Cave-Ayland { 1107eb169c76SMark Cave-Ayland DeviceClass *dc = DEVICE_CLASS(klass); 1108eb169c76SMark Cave-Ayland 1109eb169c76SMark Cave-Ayland /* internal device for sysbusesp/pciespscsi, not user-creatable */ 1110eb169c76SMark Cave-Ayland dc->user_creatable = false; 1111eb169c76SMark Cave-Ayland set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 1112eb169c76SMark Cave-Ayland } 1113eb169c76SMark Cave-Ayland 1114eb169c76SMark Cave-Ayland static const TypeInfo esp_info = { 1115eb169c76SMark Cave-Ayland .name = TYPE_ESP, 1116eb169c76SMark Cave-Ayland .parent = TYPE_DEVICE, 1117eb169c76SMark Cave-Ayland .instance_size = sizeof(ESPState), 1118eb169c76SMark Cave-Ayland .class_init = esp_class_init, 1119eb169c76SMark Cave-Ayland }; 1120eb169c76SMark Cave-Ayland 112183f7d43aSAndreas Färber static void esp_register_types(void) 1122cfb9de9cSPaul Brook { 1123a391fdbcSHervé Poussineau type_register_static(&sysbus_esp_info); 1124eb169c76SMark Cave-Ayland type_register_static(&esp_info); 1125cfb9de9cSPaul Brook } 1126cfb9de9cSPaul Brook 112783f7d43aSAndreas Färber type_init(esp_register_types) 1128