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 202c7bce09cSMark 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); 246*49691315SMark Cave-Ayland if (esp_select(s) < 0) { 247*49691315SMark Cave-Ayland return -1; 248*49691315SMark Cave-Ayland } 24974d71ea1SLaurent Vivier esp_raise_drq(s); 25074d71ea1SLaurent Vivier return 0; 25174d71ea1SLaurent Vivier } 25274d71ea1SLaurent Vivier } else { 253fc4d65daSblueswir1 dmalen = s->ti_size; 254d3cdc491SPrasad J Pandit if (dmalen > TI_BUFSZ) { 255d3cdc491SPrasad J Pandit return 0; 256d3cdc491SPrasad J Pandit } 257fc4d65daSblueswir1 memcpy(buf, s->ti_buf, dmalen); 25875ef8496SHervé Poussineau buf[0] = buf[2] >> 5; 2594f6200f0Sbellard } 260bf4b9889SBlue Swirl trace_esp_get_cmd(dmalen, target); 2612e5d83bbSpbrook 262c7bce09cSMark Cave-Ayland if (esp_select(s) < 0) { 263*49691315SMark Cave-Ayland return -1; 2642f275b8fSbellard } 2659f149aa9Spbrook return dmalen; 2669f149aa9Spbrook } 2679f149aa9Spbrook 268f2818f22SArtyom Tarasenko static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) 2699f149aa9Spbrook { 2709f149aa9Spbrook int32_t datalen; 2719f149aa9Spbrook int lun; 272f48a7a6eSPaolo Bonzini SCSIDevice *current_lun; 2739f149aa9Spbrook 274bf4b9889SBlue Swirl trace_esp_do_busid_cmd(busid); 275f2818f22SArtyom Tarasenko lun = busid & 7; 2760d3545e7SPaolo Bonzini current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun); 277e6810db8SHervé Poussineau s->current_req = scsi_req_new(current_lun, 0, lun, buf, s); 278c39ce112SPaolo Bonzini datalen = scsi_req_enqueue(s->current_req); 27967e999beSbellard s->ti_size = datalen; 28067e999beSbellard if (datalen != 0) { 281c73f96fdSblueswir1 s->rregs[ESP_RSTAT] = STAT_TC; 2826cc88d6bSMark Cave-Ayland esp_set_tc(s, 0); 2832e5d83bbSpbrook if (datalen > 0) { 2845ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] |= STAT_DI; 2854f6200f0Sbellard } else { 2865ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] |= STAT_DO; 2874f6200f0Sbellard } 288ad3376ccSPaolo Bonzini scsi_req_continue(s->current_req); 2894e9aec74Spbrook } 2905ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 2915ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = SEQ_CD; 292c73f96fdSblueswir1 esp_raise_irq(s); 2932f275b8fSbellard } 2942f275b8fSbellard 295c959f218SMark Cave-Ayland static void do_cmd(ESPState *s) 296f2818f22SArtyom Tarasenko { 297c959f218SMark Cave-Ayland uint8_t *buf = s->cmdbuf; 298f2818f22SArtyom Tarasenko uint8_t busid = buf[0]; 299f2818f22SArtyom Tarasenko 300f2818f22SArtyom Tarasenko do_busid_cmd(s, &buf[1], busid); 301f2818f22SArtyom Tarasenko } 302f2818f22SArtyom Tarasenko 30374d71ea1SLaurent Vivier static void satn_pdma_cb(ESPState *s) 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 { 313*49691315SMark Cave-Ayland int32_t cmdlen; 314*49691315SMark Cave-Ayland 3151b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 31673d74342SBlue Swirl s->dma_cb = handle_satn; 31773d74342SBlue Swirl return; 31873d74342SBlue Swirl } 31974d71ea1SLaurent Vivier s->pdma_cb = satn_pdma_cb; 320*49691315SMark Cave-Ayland cmdlen = get_cmd(s); 321*49691315SMark Cave-Ayland if (cmdlen > 0) { 322*49691315SMark Cave-Ayland s->cmdlen = cmdlen; 323c959f218SMark Cave-Ayland do_cmd(s); 324*49691315SMark Cave-Ayland } else if (cmdlen == 0) { 325*49691315SMark Cave-Ayland s->cmdlen = 0; 326bb0bc7bbSMark Cave-Ayland s->do_cmd = 1; 327*49691315SMark Cave-Ayland /* Target present, but no cmd yet - switch to command phase */ 328*49691315SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 329*49691315SMark Cave-Ayland s->rregs[ESP_RSTAT] = STAT_CD; 3309f149aa9Spbrook } 33194d5c79dSMark Cave-Ayland } 3329f149aa9Spbrook 33374d71ea1SLaurent Vivier static void s_without_satn_pdma_cb(ESPState *s) 33474d71ea1SLaurent Vivier { 335bb0bc7bbSMark Cave-Ayland s->do_cmd = 0; 336bb0bc7bbSMark Cave-Ayland if (s->cmdlen) { 3372c573cfeSMark Cave-Ayland do_busid_cmd(s, s->cmdbuf, 0); 33874d71ea1SLaurent Vivier } 33974d71ea1SLaurent Vivier } 34074d71ea1SLaurent Vivier 341f2818f22SArtyom Tarasenko static void handle_s_without_atn(ESPState *s) 342f2818f22SArtyom Tarasenko { 343*49691315SMark Cave-Ayland int32_t cmdlen; 344*49691315SMark Cave-Ayland 3451b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 34673d74342SBlue Swirl s->dma_cb = handle_s_without_atn; 34773d74342SBlue Swirl return; 34873d74342SBlue Swirl } 34974d71ea1SLaurent Vivier s->pdma_cb = s_without_satn_pdma_cb; 350*49691315SMark Cave-Ayland cmdlen = get_cmd(s); 351*49691315SMark Cave-Ayland if (cmdlen > 0) { 352*49691315SMark Cave-Ayland s->cmdlen = cmdlen; 353bb0bc7bbSMark Cave-Ayland do_busid_cmd(s, s->cmdbuf, 0); 354*49691315SMark Cave-Ayland } else if (cmdlen == 0) { 355*49691315SMark Cave-Ayland s->cmdlen = 0; 356bb0bc7bbSMark Cave-Ayland s->do_cmd = 1; 357*49691315SMark Cave-Ayland /* Target present, but no cmd yet - switch to command phase */ 358*49691315SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 359*49691315SMark Cave-Ayland s->rregs[ESP_RSTAT] = STAT_CD; 360f2818f22SArtyom Tarasenko } 361f2818f22SArtyom Tarasenko } 362f2818f22SArtyom Tarasenko 36374d71ea1SLaurent Vivier static void satn_stop_pdma_cb(ESPState *s) 36474d71ea1SLaurent Vivier { 365bb0bc7bbSMark Cave-Ayland s->do_cmd = 0; 36674d71ea1SLaurent Vivier if (s->cmdlen) { 36774d71ea1SLaurent Vivier trace_esp_handle_satn_stop(s->cmdlen); 36874d71ea1SLaurent Vivier s->do_cmd = 1; 36974d71ea1SLaurent Vivier s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; 37074d71ea1SLaurent Vivier s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 37174d71ea1SLaurent Vivier s->rregs[ESP_RSEQ] = SEQ_CD; 37274d71ea1SLaurent Vivier esp_raise_irq(s); 37374d71ea1SLaurent Vivier } 37474d71ea1SLaurent Vivier } 37574d71ea1SLaurent Vivier 3769f149aa9Spbrook static void handle_satn_stop(ESPState *s) 3779f149aa9Spbrook { 378*49691315SMark Cave-Ayland int32_t cmdlen; 379*49691315SMark Cave-Ayland 3801b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 38173d74342SBlue Swirl s->dma_cb = handle_satn_stop; 38273d74342SBlue Swirl return; 38373d74342SBlue Swirl } 384c62c1fa0SPhilippe Mathieu-Daudé s->pdma_cb = satn_stop_pdma_cb; 385*49691315SMark Cave-Ayland cmdlen = get_cmd(s); 386*49691315SMark Cave-Ayland if (cmdlen > 0) { 387bf4b9889SBlue Swirl trace_esp_handle_satn_stop(s->cmdlen); 388*49691315SMark Cave-Ayland s->cmdlen = cmdlen; 3899f149aa9Spbrook s->do_cmd = 1; 390c73f96fdSblueswir1 s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; 3915ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 3925ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = SEQ_CD; 393c73f96fdSblueswir1 esp_raise_irq(s); 394*49691315SMark Cave-Ayland } else if (cmdlen == 0) { 395*49691315SMark Cave-Ayland s->cmdlen = 0; 396bb0bc7bbSMark Cave-Ayland s->do_cmd = 1; 397*49691315SMark Cave-Ayland /* Target present, but no cmd yet - switch to command phase */ 398*49691315SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 399*49691315SMark Cave-Ayland s->rregs[ESP_RSTAT] = STAT_CD; 4009f149aa9Spbrook } 4019f149aa9Spbrook } 4029f149aa9Spbrook 40374d71ea1SLaurent Vivier static void write_response_pdma_cb(ESPState *s) 40474d71ea1SLaurent Vivier { 40574d71ea1SLaurent Vivier s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; 40674d71ea1SLaurent Vivier s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 40774d71ea1SLaurent Vivier s->rregs[ESP_RSEQ] = SEQ_CD; 40874d71ea1SLaurent Vivier esp_raise_irq(s); 40974d71ea1SLaurent Vivier } 41074d71ea1SLaurent Vivier 4110fc5c15aSpbrook static void write_response(ESPState *s) 4122f275b8fSbellard { 413bf4b9889SBlue Swirl trace_esp_write_response(s->status); 4143944966dSPaolo Bonzini s->ti_buf[0] = s->status; 4150fc5c15aSpbrook s->ti_buf[1] = 0; 4164f6200f0Sbellard if (s->dma) { 41774d71ea1SLaurent Vivier if (s->dma_memory_write) { 4188b17de88Sblueswir1 s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); 419c73f96fdSblueswir1 s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; 4205ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; 4215ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = SEQ_CD; 4224f6200f0Sbellard } else { 4233c421400SMark Cave-Ayland set_pdma(s, TI); 42474d71ea1SLaurent Vivier s->pdma_cb = write_response_pdma_cb; 42574d71ea1SLaurent Vivier esp_raise_drq(s); 42674d71ea1SLaurent Vivier return; 42774d71ea1SLaurent Vivier } 42874d71ea1SLaurent Vivier } else { 4290fc5c15aSpbrook s->ti_size = 2; 4304f6200f0Sbellard s->ti_rptr = 0; 431d020aa50SPaolo Bonzini s->ti_wptr = 2; 4325ad6bb97Sblueswir1 s->rregs[ESP_RFLAGS] = 2; 4334f6200f0Sbellard } 434c73f96fdSblueswir1 esp_raise_irq(s); 4352f275b8fSbellard } 4364f6200f0Sbellard 437a917d384Spbrook static void esp_dma_done(ESPState *s) 4384d611c9aSpbrook { 439c73f96fdSblueswir1 s->rregs[ESP_RSTAT] |= STAT_TC; 4405ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_BS; 4415ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = 0; 4425ad6bb97Sblueswir1 s->rregs[ESP_RFLAGS] = 0; 443c47b5835SMark Cave-Ayland esp_set_tc(s, 0); 444c73f96fdSblueswir1 esp_raise_irq(s); 4454d611c9aSpbrook } 446a917d384Spbrook 44774d71ea1SLaurent Vivier static void do_dma_pdma_cb(ESPState *s) 44874d71ea1SLaurent Vivier { 4494ca2ba6fSMark Cave-Ayland int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO); 4506cc88d6bSMark Cave-Ayland 45174d71ea1SLaurent Vivier if (s->do_cmd) { 45274d71ea1SLaurent Vivier s->ti_size = 0; 45374d71ea1SLaurent Vivier s->cmdlen = 0; 45474d71ea1SLaurent Vivier s->do_cmd = 0; 455c959f218SMark Cave-Ayland do_cmd(s); 45674d71ea1SLaurent Vivier return; 45774d71ea1SLaurent Vivier } 45874d71ea1SLaurent Vivier if (s->async_len == 0) { 45974d71ea1SLaurent Vivier scsi_req_continue(s->current_req); 46074d71ea1SLaurent Vivier /* 46174d71ea1SLaurent Vivier * If there is still data to be read from the device then 46274d71ea1SLaurent Vivier * complete the DMA operation immediately. Otherwise defer 46374d71ea1SLaurent Vivier * until the scsi layer has completed. 46474d71ea1SLaurent Vivier */ 4656cc88d6bSMark Cave-Ayland if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) { 46674d71ea1SLaurent Vivier return; 46774d71ea1SLaurent Vivier } 46874d71ea1SLaurent Vivier } 46974d71ea1SLaurent Vivier 47074d71ea1SLaurent Vivier /* Partially filled a scsi buffer. Complete immediately. */ 47174d71ea1SLaurent Vivier esp_dma_done(s); 47274d71ea1SLaurent Vivier } 47374d71ea1SLaurent Vivier 474a917d384Spbrook static void esp_do_dma(ESPState *s) 475a917d384Spbrook { 47667e999beSbellard uint32_t len; 4774ca2ba6fSMark Cave-Ayland int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO); 478a917d384Spbrook 4796cc88d6bSMark Cave-Ayland len = esp_get_tc(s); 480a917d384Spbrook if (s->do_cmd) { 48115407433SLaurent Vivier /* 48215407433SLaurent Vivier * handle_ti_cmd() case: esp_do_dma() is called only from 48315407433SLaurent Vivier * handle_ti_cmd() with do_cmd != NULL (see the assert()) 48415407433SLaurent Vivier */ 485bf4b9889SBlue Swirl trace_esp_do_dma(s->cmdlen, len); 486926cde5fSPrasad J Pandit assert(s->cmdlen <= sizeof(s->cmdbuf) && 487926cde5fSPrasad J Pandit len <= sizeof(s->cmdbuf) - s->cmdlen); 48874d71ea1SLaurent Vivier if (s->dma_memory_read) { 4898b17de88Sblueswir1 s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); 49074d71ea1SLaurent Vivier } else { 49102abe246SMark Cave-Ayland set_pdma(s, TI); 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 { 5143c421400SMark Cave-Ayland set_pdma(s, ASYNC); 51574d71ea1SLaurent Vivier s->pdma_cb = do_dma_pdma_cb; 51674d71ea1SLaurent Vivier esp_raise_drq(s); 51774d71ea1SLaurent Vivier return; 51874d71ea1SLaurent Vivier } 51974d71ea1SLaurent Vivier } else { 52074d71ea1SLaurent Vivier if (s->dma_memory_write) { 5218b17de88Sblueswir1 s->dma_memory_write(s->dma_opaque, s->async_buf, len); 52274d71ea1SLaurent Vivier } else { 5233c421400SMark Cave-Ayland set_pdma(s, ASYNC); 52474d71ea1SLaurent Vivier s->pdma_cb = do_dma_pdma_cb; 52574d71ea1SLaurent Vivier esp_raise_drq(s); 52674d71ea1SLaurent Vivier return; 52774d71ea1SLaurent Vivier } 528a917d384Spbrook } 5296cc88d6bSMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 530a917d384Spbrook s->async_buf += len; 531a917d384Spbrook s->async_len -= len; 53294d5c79dSMark Cave-Ayland if (to_device) { 5336787f5faSpbrook s->ti_size += len; 53494d5c79dSMark Cave-Ayland } else { 5356787f5faSpbrook s->ti_size -= len; 53694d5c79dSMark Cave-Ayland } 537a917d384Spbrook if (s->async_len == 0) { 538ad3376ccSPaolo Bonzini scsi_req_continue(s->current_req); 53994d5c79dSMark Cave-Ayland /* 54094d5c79dSMark Cave-Ayland * If there is still data to be read from the device then 54194d5c79dSMark Cave-Ayland * complete the DMA operation immediately. Otherwise defer 54294d5c79dSMark Cave-Ayland * until the scsi layer has completed. 54394d5c79dSMark Cave-Ayland */ 5446cc88d6bSMark Cave-Ayland if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) { 545ad3376ccSPaolo Bonzini return; 546a917d384Spbrook } 547a917d384Spbrook } 548ad3376ccSPaolo Bonzini 5496787f5faSpbrook /* Partially filled a scsi buffer. Complete immediately. */ 550a917d384Spbrook esp_dma_done(s); 551a917d384Spbrook } 552a917d384Spbrook 553ea84a442SGuenter Roeck static void esp_report_command_complete(ESPState *s, uint32_t status) 554a917d384Spbrook { 555bf4b9889SBlue Swirl trace_esp_command_complete(); 556c6df7102SPaolo Bonzini if (s->ti_size != 0) { 557bf4b9889SBlue Swirl trace_esp_command_complete_unexpected(); 558c6df7102SPaolo Bonzini } 559a917d384Spbrook s->ti_size = 0; 560a917d384Spbrook s->async_len = 0; 561aba1f023SPaolo Bonzini if (status) { 562bf4b9889SBlue Swirl trace_esp_command_complete_fail(); 563c6df7102SPaolo Bonzini } 564aba1f023SPaolo Bonzini s->status = status; 5655ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] = STAT_ST; 566a917d384Spbrook esp_dma_done(s); 5675c6c0e51SHannes Reinecke if (s->current_req) { 5685c6c0e51SHannes Reinecke scsi_req_unref(s->current_req); 5695c6c0e51SHannes Reinecke s->current_req = NULL; 570a917d384Spbrook s->current_dev = NULL; 5715c6c0e51SHannes Reinecke } 572c6df7102SPaolo Bonzini } 573c6df7102SPaolo Bonzini 57417ea26c2SHannes Reinecke void esp_command_complete(SCSIRequest *req, size_t resid) 575ea84a442SGuenter Roeck { 576ea84a442SGuenter Roeck ESPState *s = req->hba_private; 577ea84a442SGuenter Roeck 578ea84a442SGuenter Roeck if (s->rregs[ESP_RSTAT] & STAT_INT) { 57994d5c79dSMark Cave-Ayland /* 58094d5c79dSMark Cave-Ayland * Defer handling command complete until the previous 581ea84a442SGuenter Roeck * interrupt has been handled. 582ea84a442SGuenter Roeck */ 583ea84a442SGuenter Roeck trace_esp_command_complete_deferred(); 58417ea26c2SHannes Reinecke s->deferred_status = req->status; 585ea84a442SGuenter Roeck s->deferred_complete = true; 586ea84a442SGuenter Roeck return; 587ea84a442SGuenter Roeck } 58817ea26c2SHannes Reinecke esp_report_command_complete(s, req->status); 589ea84a442SGuenter Roeck } 590ea84a442SGuenter Roeck 5919c7e23fcSHervé Poussineau void esp_transfer_data(SCSIRequest *req, uint32_t len) 592c6df7102SPaolo Bonzini { 593e6810db8SHervé Poussineau ESPState *s = req->hba_private; 5946cc88d6bSMark Cave-Ayland uint32_t dmalen = esp_get_tc(s); 595c6df7102SPaolo Bonzini 5967f0b6e11SPaolo Bonzini assert(!s->do_cmd); 5976cc88d6bSMark Cave-Ayland trace_esp_transfer_data(dmalen, s->ti_size); 598aba1f023SPaolo Bonzini s->async_len = len; 5990c34459bSPaolo Bonzini s->async_buf = scsi_req_get_buf(req); 6006cc88d6bSMark Cave-Ayland if (dmalen) { 601a917d384Spbrook esp_do_dma(s); 6025eb7a23fSMark Cave-Ayland } else if (s->ti_size <= 0) { 60394d5c79dSMark Cave-Ayland /* 60494d5c79dSMark Cave-Ayland * If this was the last part of a DMA transfer then the 60594d5c79dSMark Cave-Ayland * completion interrupt is deferred to here. 60694d5c79dSMark Cave-Ayland */ 6076787f5faSpbrook esp_dma_done(s); 6086787f5faSpbrook } 609a917d384Spbrook } 6102e5d83bbSpbrook 6112f275b8fSbellard static void handle_ti(ESPState *s) 6122f275b8fSbellard { 613b76624deSMark Cave-Ayland uint32_t dmalen; 6142f275b8fSbellard 6157246e160SHervé Poussineau if (s->dma && !s->dma_enabled) { 6167246e160SHervé Poussineau s->dma_cb = handle_ti; 6177246e160SHervé Poussineau return; 6187246e160SHervé Poussineau } 6197246e160SHervé Poussineau 620c47b5835SMark Cave-Ayland dmalen = esp_get_tc(s); 6214f6200f0Sbellard if (s->dma) { 622b76624deSMark Cave-Ayland trace_esp_handle_ti(dmalen); 6235ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] &= ~STAT_TC; 6244d611c9aSpbrook esp_do_dma(s); 62515407433SLaurent Vivier } else if (s->do_cmd) { 626bf4b9889SBlue Swirl trace_esp_handle_ti_cmd(s->cmdlen); 6279f149aa9Spbrook s->ti_size = 0; 6289f149aa9Spbrook s->cmdlen = 0; 6299f149aa9Spbrook s->do_cmd = 0; 630c959f218SMark Cave-Ayland do_cmd(s); 6314f6200f0Sbellard } 6322f275b8fSbellard } 6332f275b8fSbellard 6349c7e23fcSHervé Poussineau void esp_hard_reset(ESPState *s) 6356f7e9aecSbellard { 6365aca8c3bSblueswir1 memset(s->rregs, 0, ESP_REGS); 6375aca8c3bSblueswir1 memset(s->wregs, 0, ESP_REGS); 638c9cf45c1SHannes Reinecke s->tchi_written = 0; 6394e9aec74Spbrook s->ti_size = 0; 6404e9aec74Spbrook s->ti_rptr = 0; 6414e9aec74Spbrook s->ti_wptr = 0; 6424e9aec74Spbrook s->dma = 0; 6439f149aa9Spbrook s->do_cmd = 0; 64473d74342SBlue Swirl s->dma_cb = NULL; 6458dea1dd4Sblueswir1 6468dea1dd4Sblueswir1 s->rregs[ESP_CFG1] = 7; 6476f7e9aecSbellard } 6486f7e9aecSbellard 649a391fdbcSHervé Poussineau static void esp_soft_reset(ESPState *s) 65085948643SBlue Swirl { 65185948643SBlue Swirl qemu_irq_lower(s->irq); 65274d71ea1SLaurent Vivier qemu_irq_lower(s->irq_data); 653a391fdbcSHervé Poussineau esp_hard_reset(s); 65485948643SBlue Swirl } 65585948643SBlue Swirl 656a391fdbcSHervé Poussineau static void parent_esp_reset(ESPState *s, int irq, int level) 6572d069babSblueswir1 { 65885948643SBlue Swirl if (level) { 659a391fdbcSHervé Poussineau esp_soft_reset(s); 66085948643SBlue Swirl } 6612d069babSblueswir1 } 6622d069babSblueswir1 6639c7e23fcSHervé Poussineau uint64_t esp_reg_read(ESPState *s, uint32_t saddr) 66473d74342SBlue Swirl { 665b630c075SMark Cave-Ayland uint32_t val; 66673d74342SBlue Swirl 6676f7e9aecSbellard switch (saddr) { 6685ad6bb97Sblueswir1 case ESP_FIFO: 6695ad6bb97Sblueswir1 if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) { 6708dea1dd4Sblueswir1 /* Data out. */ 671ff589551SPrasad J Pandit qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n"); 6725ad6bb97Sblueswir1 s->rregs[ESP_FIFO] = 0; 673ff589551SPrasad J Pandit } else if (s->ti_rptr < s->ti_wptr) { 674ff589551SPrasad J Pandit s->ti_size--; 6755ad6bb97Sblueswir1 s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; 6764f6200f0Sbellard } 677ff589551SPrasad J Pandit if (s->ti_rptr == s->ti_wptr) { 6784f6200f0Sbellard s->ti_rptr = 0; 6794f6200f0Sbellard s->ti_wptr = 0; 6804f6200f0Sbellard } 681b630c075SMark Cave-Ayland val = s->rregs[ESP_FIFO]; 6824f6200f0Sbellard break; 6835ad6bb97Sblueswir1 case ESP_RINTR: 68494d5c79dSMark Cave-Ayland /* 68594d5c79dSMark Cave-Ayland * Clear sequence step, interrupt register and all status bits 68694d5c79dSMark Cave-Ayland * except TC 68794d5c79dSMark Cave-Ayland */ 688b630c075SMark Cave-Ayland val = s->rregs[ESP_RINTR]; 6892814df28SBlue Swirl s->rregs[ESP_RINTR] = 0; 6902814df28SBlue Swirl s->rregs[ESP_RSTAT] &= ~STAT_TC; 6912814df28SBlue Swirl s->rregs[ESP_RSEQ] = SEQ_CD; 692c73f96fdSblueswir1 esp_lower_irq(s); 693ea84a442SGuenter Roeck if (s->deferred_complete) { 694ea84a442SGuenter Roeck esp_report_command_complete(s, s->deferred_status); 695ea84a442SGuenter Roeck s->deferred_complete = false; 696ea84a442SGuenter Roeck } 697b630c075SMark Cave-Ayland break; 698c9cf45c1SHannes Reinecke case ESP_TCHI: 699c9cf45c1SHannes Reinecke /* Return the unique id if the value has never been written */ 700c9cf45c1SHannes Reinecke if (!s->tchi_written) { 701b630c075SMark Cave-Ayland val = s->chip_id; 702b630c075SMark Cave-Ayland } else { 703b630c075SMark Cave-Ayland val = s->rregs[saddr]; 704c9cf45c1SHannes Reinecke } 705b630c075SMark Cave-Ayland break; 7066f7e9aecSbellard default: 707b630c075SMark Cave-Ayland val = s->rregs[saddr]; 7086f7e9aecSbellard break; 7096f7e9aecSbellard } 710b630c075SMark Cave-Ayland 711b630c075SMark Cave-Ayland trace_esp_mem_readb(saddr, val); 712b630c075SMark Cave-Ayland return val; 7136f7e9aecSbellard } 7146f7e9aecSbellard 7159c7e23fcSHervé Poussineau void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) 7166f7e9aecSbellard { 717bf4b9889SBlue Swirl trace_esp_mem_writeb(saddr, s->wregs[saddr], val); 7186f7e9aecSbellard switch (saddr) { 719c9cf45c1SHannes Reinecke case ESP_TCHI: 720c9cf45c1SHannes Reinecke s->tchi_written = true; 721c9cf45c1SHannes Reinecke /* fall through */ 7225ad6bb97Sblueswir1 case ESP_TCLO: 7235ad6bb97Sblueswir1 case ESP_TCMID: 7245ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] &= ~STAT_TC; 7254f6200f0Sbellard break; 7265ad6bb97Sblueswir1 case ESP_FIFO: 7279f149aa9Spbrook if (s->do_cmd) { 728926cde5fSPrasad J Pandit if (s->cmdlen < ESP_CMDBUF_SZ) { 7299f149aa9Spbrook s->cmdbuf[s->cmdlen++] = val & 0xff; 730c98c6c10SPrasad J Pandit } else { 731c98c6c10SPrasad J Pandit trace_esp_error_fifo_overrun(); 732c98c6c10SPrasad J Pandit } 733ff589551SPrasad J Pandit } else if (s->ti_wptr == TI_BUFSZ - 1) { 7343af4e9aaSHervé Poussineau trace_esp_error_fifo_overrun(); 7352e5d83bbSpbrook } else { 7364f6200f0Sbellard s->ti_size++; 7374f6200f0Sbellard s->ti_buf[s->ti_wptr++] = val & 0xff; 7382e5d83bbSpbrook } 7394f6200f0Sbellard break; 7405ad6bb97Sblueswir1 case ESP_CMD: 7414f6200f0Sbellard s->rregs[saddr] = val; 7425ad6bb97Sblueswir1 if (val & CMD_DMA) { 7434f6200f0Sbellard s->dma = 1; 7446787f5faSpbrook /* Reload DMA counter. */ 74596676c2fSMark Cave-Ayland if (esp_get_stc(s) == 0) { 74696676c2fSMark Cave-Ayland esp_set_tc(s, 0x10000); 74796676c2fSMark Cave-Ayland } else { 748c04ed569SMark Cave-Ayland esp_set_tc(s, esp_get_stc(s)); 74996676c2fSMark Cave-Ayland } 7504f6200f0Sbellard } else { 7514f6200f0Sbellard s->dma = 0; 7524f6200f0Sbellard } 7535ad6bb97Sblueswir1 switch (val & CMD_CMD) { 7545ad6bb97Sblueswir1 case CMD_NOP: 755bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_nop(val); 7562f275b8fSbellard break; 7575ad6bb97Sblueswir1 case CMD_FLUSH: 758bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_flush(val); 75994d5c79dSMark Cave-Ayland /*s->ti_size = 0;*/ 7605ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_FC; 7615ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = 0; 762a214c598Sblueswir1 s->rregs[ESP_RFLAGS] = 0; 7636f7e9aecSbellard break; 7645ad6bb97Sblueswir1 case CMD_RESET: 765bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_reset(val); 766a391fdbcSHervé Poussineau esp_soft_reset(s); 7676f7e9aecSbellard break; 7685ad6bb97Sblueswir1 case CMD_BUSRESET: 769bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_bus_reset(val); 7705ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_RST; 7715ad6bb97Sblueswir1 if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) { 772c73f96fdSblueswir1 esp_raise_irq(s); 7739e61bde5Sbellard } 7742f275b8fSbellard break; 7755ad6bb97Sblueswir1 case CMD_TI: 7760097d3ecSMark Cave-Ayland trace_esp_mem_writeb_cmd_ti(val); 7772f275b8fSbellard handle_ti(s); 7782f275b8fSbellard break; 7795ad6bb97Sblueswir1 case CMD_ICCS: 780bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_iccs(val); 7810fc5c15aSpbrook write_response(s); 7824bf5801dSblueswir1 s->rregs[ESP_RINTR] = INTR_FC; 7834bf5801dSblueswir1 s->rregs[ESP_RSTAT] |= STAT_MI; 7842f275b8fSbellard break; 7855ad6bb97Sblueswir1 case CMD_MSGACC: 786bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_msgacc(val); 7875ad6bb97Sblueswir1 s->rregs[ESP_RINTR] = INTR_DC; 7885ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = 0; 7894e2a68c1SArtyom Tarasenko s->rregs[ESP_RFLAGS] = 0; 7904e2a68c1SArtyom Tarasenko esp_raise_irq(s); 7916f7e9aecSbellard break; 7920fd0eb21SBlue Swirl case CMD_PAD: 793bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_pad(val); 7940fd0eb21SBlue Swirl s->rregs[ESP_RSTAT] = STAT_TC; 7950fd0eb21SBlue Swirl s->rregs[ESP_RINTR] = INTR_FC; 7960fd0eb21SBlue Swirl s->rregs[ESP_RSEQ] = 0; 7970fd0eb21SBlue Swirl break; 7985ad6bb97Sblueswir1 case CMD_SATN: 799bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_satn(val); 8006f7e9aecSbellard break; 8016915bff1SHervé Poussineau case CMD_RSTATN: 8026915bff1SHervé Poussineau trace_esp_mem_writeb_cmd_rstatn(val); 8036915bff1SHervé Poussineau break; 8045e1e0a3bSBlue Swirl case CMD_SEL: 805bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_sel(val); 806f2818f22SArtyom Tarasenko handle_s_without_atn(s); 8075e1e0a3bSBlue Swirl break; 8085ad6bb97Sblueswir1 case CMD_SELATN: 809bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_selatn(val); 8102f275b8fSbellard handle_satn(s); 8112f275b8fSbellard break; 8125ad6bb97Sblueswir1 case CMD_SELATNS: 813bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_selatns(val); 8149f149aa9Spbrook handle_satn_stop(s); 8152f275b8fSbellard break; 8165ad6bb97Sblueswir1 case CMD_ENSEL: 817bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_ensel(val); 818e3926838Sblueswir1 s->rregs[ESP_RINTR] = 0; 81974ec6048Sblueswir1 break; 8206fe84c18SHervé Poussineau case CMD_DISSEL: 8216fe84c18SHervé Poussineau trace_esp_mem_writeb_cmd_dissel(val); 8226fe84c18SHervé Poussineau s->rregs[ESP_RINTR] = 0; 8236fe84c18SHervé Poussineau esp_raise_irq(s); 8246fe84c18SHervé Poussineau break; 8252f275b8fSbellard default: 8263af4e9aaSHervé Poussineau trace_esp_error_unhandled_command(val); 8276f7e9aecSbellard break; 8286f7e9aecSbellard } 8296f7e9aecSbellard break; 8305ad6bb97Sblueswir1 case ESP_WBUSID ... ESP_WSYNO: 8314f6200f0Sbellard break; 8325ad6bb97Sblueswir1 case ESP_CFG1: 8339ea73f8bSPaolo Bonzini case ESP_CFG2: case ESP_CFG3: 8349ea73f8bSPaolo Bonzini case ESP_RES3: case ESP_RES4: 8354f6200f0Sbellard s->rregs[saddr] = val; 8364f6200f0Sbellard break; 8375ad6bb97Sblueswir1 case ESP_WCCF ... ESP_WTEST: 8384f6200f0Sbellard break; 8396f7e9aecSbellard default: 8403af4e9aaSHervé Poussineau trace_esp_error_invalid_write(val, saddr); 8418dea1dd4Sblueswir1 return; 8426f7e9aecSbellard } 8432f275b8fSbellard s->wregs[saddr] = val; 8446f7e9aecSbellard } 8456f7e9aecSbellard 846a8170e5eSAvi Kivity static bool esp_mem_accepts(void *opaque, hwaddr addr, 8478372d383SPeter Maydell unsigned size, bool is_write, 8488372d383SPeter Maydell MemTxAttrs attrs) 84967bb5314SAvi Kivity { 85067bb5314SAvi Kivity return (size == 1) || (is_write && size == 4); 85167bb5314SAvi Kivity } 8526f7e9aecSbellard 85374d71ea1SLaurent Vivier static bool esp_pdma_needed(void *opaque) 85474d71ea1SLaurent Vivier { 85574d71ea1SLaurent Vivier ESPState *s = opaque; 85674d71ea1SLaurent Vivier return s->dma_memory_read == NULL && s->dma_memory_write == NULL && 85774d71ea1SLaurent Vivier s->dma_enabled; 85874d71ea1SLaurent Vivier } 85974d71ea1SLaurent Vivier 86074d71ea1SLaurent Vivier static const VMStateDescription vmstate_esp_pdma = { 86174d71ea1SLaurent Vivier .name = "esp/pdma", 862bb0bc7bbSMark Cave-Ayland .version_id = 2, 863bb0bc7bbSMark Cave-Ayland .minimum_version_id = 2, 86474d71ea1SLaurent Vivier .needed = esp_pdma_needed, 86574d71ea1SLaurent Vivier .fields = (VMStateField[]) { 86674d71ea1SLaurent Vivier VMSTATE_INT32(pdma_origin, ESPState), 86774d71ea1SLaurent Vivier VMSTATE_END_OF_LIST() 86874d71ea1SLaurent Vivier } 86974d71ea1SLaurent Vivier }; 87074d71ea1SLaurent Vivier 8716cc88d6bSMark Cave-Ayland static bool esp_is_before_version_5(void *opaque, int version_id) 8726cc88d6bSMark Cave-Ayland { 8736cc88d6bSMark Cave-Ayland ESPState *s = ESP(opaque); 8746cc88d6bSMark Cave-Ayland 8756cc88d6bSMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 8766cc88d6bSMark Cave-Ayland return version_id < 5; 8776cc88d6bSMark Cave-Ayland } 8786cc88d6bSMark Cave-Ayland 8790bd005beSMark Cave-Ayland static int esp_pre_save(void *opaque) 8800bd005beSMark Cave-Ayland { 8810bd005beSMark Cave-Ayland ESPState *s = ESP(opaque); 8820bd005beSMark Cave-Ayland 8830bd005beSMark Cave-Ayland s->mig_version_id = vmstate_esp.version_id; 8840bd005beSMark Cave-Ayland return 0; 8850bd005beSMark Cave-Ayland } 8860bd005beSMark Cave-Ayland 8870bd005beSMark Cave-Ayland static int esp_post_load(void *opaque, int version_id) 8880bd005beSMark Cave-Ayland { 8890bd005beSMark Cave-Ayland ESPState *s = ESP(opaque); 8900bd005beSMark Cave-Ayland 8916cc88d6bSMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 8926cc88d6bSMark Cave-Ayland 8936cc88d6bSMark Cave-Ayland if (version_id < 5) { 8946cc88d6bSMark Cave-Ayland esp_set_tc(s, s->mig_dma_left); 8956cc88d6bSMark Cave-Ayland } 8966cc88d6bSMark Cave-Ayland 8970bd005beSMark Cave-Ayland s->mig_version_id = vmstate_esp.version_id; 8980bd005beSMark Cave-Ayland return 0; 8990bd005beSMark Cave-Ayland } 9000bd005beSMark Cave-Ayland 9019c7e23fcSHervé Poussineau const VMStateDescription vmstate_esp = { 902cc9952f3SBlue Swirl .name = "esp", 9030bd005beSMark Cave-Ayland .version_id = 5, 904cc9952f3SBlue Swirl .minimum_version_id = 3, 9050bd005beSMark Cave-Ayland .pre_save = esp_pre_save, 9060bd005beSMark Cave-Ayland .post_load = esp_post_load, 907cc9952f3SBlue Swirl .fields = (VMStateField[]) { 908cc9952f3SBlue Swirl VMSTATE_BUFFER(rregs, ESPState), 909cc9952f3SBlue Swirl VMSTATE_BUFFER(wregs, ESPState), 910cc9952f3SBlue Swirl VMSTATE_INT32(ti_size, ESPState), 911cc9952f3SBlue Swirl VMSTATE_UINT32(ti_rptr, ESPState), 912cc9952f3SBlue Swirl VMSTATE_UINT32(ti_wptr, ESPState), 913cc9952f3SBlue Swirl VMSTATE_BUFFER(ti_buf, ESPState), 9143944966dSPaolo Bonzini VMSTATE_UINT32(status, ESPState), 915ea84a442SGuenter Roeck VMSTATE_UINT32(deferred_status, ESPState), 916ea84a442SGuenter Roeck VMSTATE_BOOL(deferred_complete, ESPState), 917cc9952f3SBlue Swirl VMSTATE_UINT32(dma, ESPState), 918cc966774SPaolo Bonzini VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16), 919cc966774SPaolo Bonzini VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4), 920cc9952f3SBlue Swirl VMSTATE_UINT32(cmdlen, ESPState), 921cc9952f3SBlue Swirl VMSTATE_UINT32(do_cmd, ESPState), 9226cc88d6bSMark Cave-Ayland VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5), 923cc9952f3SBlue Swirl VMSTATE_END_OF_LIST() 92474d71ea1SLaurent Vivier }, 92574d71ea1SLaurent Vivier .subsections = (const VMStateDescription * []) { 92674d71ea1SLaurent Vivier &vmstate_esp_pdma, 92774d71ea1SLaurent Vivier NULL 9286f7e9aecSbellard } 929cc9952f3SBlue Swirl }; 9306f7e9aecSbellard 931a8170e5eSAvi Kivity static void sysbus_esp_mem_write(void *opaque, hwaddr addr, 932a391fdbcSHervé Poussineau uint64_t val, 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 esp_reg_write(s, saddr, val); 940a391fdbcSHervé Poussineau } 941a391fdbcSHervé Poussineau 942a8170e5eSAvi Kivity static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr, 943a391fdbcSHervé Poussineau unsigned int size) 944a391fdbcSHervé Poussineau { 945a391fdbcSHervé Poussineau SysBusESPState *sysbus = opaque; 946eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 947a391fdbcSHervé Poussineau uint32_t saddr; 948a391fdbcSHervé Poussineau 949a391fdbcSHervé Poussineau saddr = addr >> sysbus->it_shift; 950eb169c76SMark Cave-Ayland return esp_reg_read(s, saddr); 951a391fdbcSHervé Poussineau } 952a391fdbcSHervé Poussineau 953a391fdbcSHervé Poussineau static const MemoryRegionOps sysbus_esp_mem_ops = { 954a391fdbcSHervé Poussineau .read = sysbus_esp_mem_read, 955a391fdbcSHervé Poussineau .write = sysbus_esp_mem_write, 956a391fdbcSHervé Poussineau .endianness = DEVICE_NATIVE_ENDIAN, 957a391fdbcSHervé Poussineau .valid.accepts = esp_mem_accepts, 958a391fdbcSHervé Poussineau }; 959a391fdbcSHervé Poussineau 96074d71ea1SLaurent Vivier static void sysbus_esp_pdma_write(void *opaque, hwaddr addr, 96174d71ea1SLaurent Vivier uint64_t val, unsigned int size) 96274d71ea1SLaurent Vivier { 96374d71ea1SLaurent Vivier SysBusESPState *sysbus = opaque; 964eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 9653c421400SMark Cave-Ayland uint32_t dmalen; 96674d71ea1SLaurent Vivier 967960ebfd9SMark Cave-Ayland trace_esp_pdma_write(size); 968960ebfd9SMark Cave-Ayland 96974d71ea1SLaurent Vivier switch (size) { 97074d71ea1SLaurent Vivier case 1: 971761bef75SMark Cave-Ayland esp_pdma_write(s, val); 97274d71ea1SLaurent Vivier break; 97374d71ea1SLaurent Vivier case 2: 974761bef75SMark Cave-Ayland esp_pdma_write(s, val >> 8); 975761bef75SMark Cave-Ayland esp_pdma_write(s, val); 97674d71ea1SLaurent Vivier break; 97774d71ea1SLaurent Vivier } 9783c421400SMark Cave-Ayland dmalen = esp_get_tc(s); 9793c421400SMark Cave-Ayland if (dmalen == 0 && s->pdma_cb) { 98074d71ea1SLaurent Vivier esp_lower_drq(s); 98174d71ea1SLaurent Vivier s->pdma_cb(s); 98274d71ea1SLaurent Vivier s->pdma_cb = NULL; 98374d71ea1SLaurent Vivier } 98474d71ea1SLaurent Vivier } 98574d71ea1SLaurent Vivier 98674d71ea1SLaurent Vivier static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr, 98774d71ea1SLaurent Vivier unsigned int size) 98874d71ea1SLaurent Vivier { 98974d71ea1SLaurent Vivier SysBusESPState *sysbus = opaque; 990eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 9916cc88d6bSMark Cave-Ayland uint32_t dmalen = esp_get_tc(s); 99274d71ea1SLaurent Vivier uint64_t val = 0; 99374d71ea1SLaurent Vivier 994960ebfd9SMark Cave-Ayland trace_esp_pdma_read(size); 995960ebfd9SMark Cave-Ayland 9963c421400SMark Cave-Ayland if (dmalen == 0) { 99774d71ea1SLaurent Vivier return 0; 99874d71ea1SLaurent Vivier } 99974d71ea1SLaurent Vivier switch (size) { 100074d71ea1SLaurent Vivier case 1: 1001761bef75SMark Cave-Ayland val = esp_pdma_read(s); 100274d71ea1SLaurent Vivier break; 100374d71ea1SLaurent Vivier case 2: 1004761bef75SMark Cave-Ayland val = esp_pdma_read(s); 1005761bef75SMark Cave-Ayland val = (val << 8) | esp_pdma_read(s); 100674d71ea1SLaurent Vivier break; 100774d71ea1SLaurent Vivier } 10088da90e81SMark Cave-Ayland dmalen = esp_get_tc(s); 10093c421400SMark Cave-Ayland if (dmalen == 0 && s->pdma_cb) { 101074d71ea1SLaurent Vivier esp_lower_drq(s); 101174d71ea1SLaurent Vivier s->pdma_cb(s); 101274d71ea1SLaurent Vivier s->pdma_cb = NULL; 101374d71ea1SLaurent Vivier } 101474d71ea1SLaurent Vivier return val; 101574d71ea1SLaurent Vivier } 101674d71ea1SLaurent Vivier 101774d71ea1SLaurent Vivier static const MemoryRegionOps sysbus_esp_pdma_ops = { 101874d71ea1SLaurent Vivier .read = sysbus_esp_pdma_read, 101974d71ea1SLaurent Vivier .write = sysbus_esp_pdma_write, 102074d71ea1SLaurent Vivier .endianness = DEVICE_NATIVE_ENDIAN, 102174d71ea1SLaurent Vivier .valid.min_access_size = 1, 102274d71ea1SLaurent Vivier .valid.max_access_size = 2, 102374d71ea1SLaurent Vivier }; 102474d71ea1SLaurent Vivier 1025afd4030cSPaolo Bonzini static const struct SCSIBusInfo esp_scsi_info = { 1026afd4030cSPaolo Bonzini .tcq = false, 10277e0380b9SPaolo Bonzini .max_target = ESP_MAX_DEVS, 10287e0380b9SPaolo Bonzini .max_lun = 7, 1029afd4030cSPaolo Bonzini 1030c6df7102SPaolo Bonzini .transfer_data = esp_transfer_data, 103194d3f98aSPaolo Bonzini .complete = esp_command_complete, 103294d3f98aSPaolo Bonzini .cancel = esp_request_cancelled 1033cfdc1bb0SPaolo Bonzini }; 1034cfdc1bb0SPaolo Bonzini 1035a391fdbcSHervé Poussineau static void sysbus_esp_gpio_demux(void *opaque, int irq, int level) 1036cfb9de9cSPaul Brook { 103784fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(opaque); 1038eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1039a391fdbcSHervé Poussineau 1040a391fdbcSHervé Poussineau switch (irq) { 1041a391fdbcSHervé Poussineau case 0: 1042a391fdbcSHervé Poussineau parent_esp_reset(s, irq, level); 1043a391fdbcSHervé Poussineau break; 1044a391fdbcSHervé Poussineau case 1: 1045a391fdbcSHervé Poussineau esp_dma_enable(opaque, irq, level); 1046a391fdbcSHervé Poussineau break; 1047a391fdbcSHervé Poussineau } 1048a391fdbcSHervé Poussineau } 1049a391fdbcSHervé Poussineau 1050b09318caSHu Tao static void sysbus_esp_realize(DeviceState *dev, Error **errp) 1051a391fdbcSHervé Poussineau { 1052b09318caSHu Tao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 105384fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(dev); 1054eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1055eb169c76SMark Cave-Ayland 1056eb169c76SMark Cave-Ayland if (!qdev_realize(DEVICE(s), NULL, errp)) { 1057eb169c76SMark Cave-Ayland return; 1058eb169c76SMark Cave-Ayland } 10596f7e9aecSbellard 1060b09318caSHu Tao sysbus_init_irq(sbd, &s->irq); 106174d71ea1SLaurent Vivier sysbus_init_irq(sbd, &s->irq_data); 1062a391fdbcSHervé Poussineau assert(sysbus->it_shift != -1); 10636f7e9aecSbellard 1064d32e4b3dSHervé Poussineau s->chip_id = TCHI_FAS100A; 106529776739SPaolo Bonzini memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_ops, 106674d71ea1SLaurent Vivier sysbus, "esp-regs", ESP_REGS << sysbus->it_shift); 1067b09318caSHu Tao sysbus_init_mmio(sbd, &sysbus->iomem); 106874d71ea1SLaurent Vivier memory_region_init_io(&sysbus->pdma, OBJECT(sysbus), &sysbus_esp_pdma_ops, 106974d71ea1SLaurent Vivier sysbus, "esp-pdma", 2); 107074d71ea1SLaurent Vivier sysbus_init_mmio(sbd, &sysbus->pdma); 10716f7e9aecSbellard 1072b09318caSHu Tao qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2); 10732d069babSblueswir1 1074b1187b51SAndreas Färber scsi_bus_new(&s->bus, sizeof(s->bus), dev, &esp_scsi_info, NULL); 107567e999beSbellard } 1076cfb9de9cSPaul Brook 1077a391fdbcSHervé Poussineau static void sysbus_esp_hard_reset(DeviceState *dev) 1078a391fdbcSHervé Poussineau { 107984fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(dev); 1080eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1081eb169c76SMark Cave-Ayland 1082eb169c76SMark Cave-Ayland esp_hard_reset(s); 1083eb169c76SMark Cave-Ayland } 1084eb169c76SMark Cave-Ayland 1085eb169c76SMark Cave-Ayland static void sysbus_esp_init(Object *obj) 1086eb169c76SMark Cave-Ayland { 1087eb169c76SMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(obj); 1088eb169c76SMark Cave-Ayland 1089eb169c76SMark Cave-Ayland object_initialize_child(obj, "esp", &sysbus->esp, TYPE_ESP); 1090a391fdbcSHervé Poussineau } 1091a391fdbcSHervé Poussineau 1092a391fdbcSHervé Poussineau static const VMStateDescription vmstate_sysbus_esp_scsi = { 1093a391fdbcSHervé Poussineau .name = "sysbusespscsi", 10940bd005beSMark Cave-Ayland .version_id = 2, 1095ea84a442SGuenter Roeck .minimum_version_id = 1, 1096a391fdbcSHervé Poussineau .fields = (VMStateField[]) { 10970bd005beSMark Cave-Ayland VMSTATE_UINT8_V(esp.mig_version_id, SysBusESPState, 2), 1098a391fdbcSHervé Poussineau VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState), 1099a391fdbcSHervé Poussineau VMSTATE_END_OF_LIST() 1100a391fdbcSHervé Poussineau } 1101999e12bbSAnthony Liguori }; 1102999e12bbSAnthony Liguori 1103a391fdbcSHervé Poussineau static void sysbus_esp_class_init(ObjectClass *klass, void *data) 1104999e12bbSAnthony Liguori { 110539bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 1106999e12bbSAnthony Liguori 1107b09318caSHu Tao dc->realize = sysbus_esp_realize; 1108a391fdbcSHervé Poussineau dc->reset = sysbus_esp_hard_reset; 1109a391fdbcSHervé Poussineau dc->vmsd = &vmstate_sysbus_esp_scsi; 1110125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 111163235df8SBlue Swirl } 1112999e12bbSAnthony Liguori 11131f077308SHervé Poussineau static const TypeInfo sysbus_esp_info = { 111484fbefedSMark Cave-Ayland .name = TYPE_SYSBUS_ESP, 111539bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 1116eb169c76SMark Cave-Ayland .instance_init = sysbus_esp_init, 1117a391fdbcSHervé Poussineau .instance_size = sizeof(SysBusESPState), 1118a391fdbcSHervé Poussineau .class_init = sysbus_esp_class_init, 111963235df8SBlue Swirl }; 112063235df8SBlue Swirl 1121eb169c76SMark Cave-Ayland static void esp_class_init(ObjectClass *klass, void *data) 1122eb169c76SMark Cave-Ayland { 1123eb169c76SMark Cave-Ayland DeviceClass *dc = DEVICE_CLASS(klass); 1124eb169c76SMark Cave-Ayland 1125eb169c76SMark Cave-Ayland /* internal device for sysbusesp/pciespscsi, not user-creatable */ 1126eb169c76SMark Cave-Ayland dc->user_creatable = false; 1127eb169c76SMark Cave-Ayland set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 1128eb169c76SMark Cave-Ayland } 1129eb169c76SMark Cave-Ayland 1130eb169c76SMark Cave-Ayland static const TypeInfo esp_info = { 1131eb169c76SMark Cave-Ayland .name = TYPE_ESP, 1132eb169c76SMark Cave-Ayland .parent = TYPE_DEVICE, 1133eb169c76SMark Cave-Ayland .instance_size = sizeof(ESPState), 1134eb169c76SMark Cave-Ayland .class_init = esp_class_init, 1135eb169c76SMark Cave-Ayland }; 1136eb169c76SMark Cave-Ayland 113783f7d43aSAndreas Färber static void esp_register_types(void) 1138cfb9de9cSPaul Brook { 1139a391fdbcSHervé Poussineau type_register_static(&sysbus_esp_info); 1140eb169c76SMark Cave-Ayland type_register_static(&esp_info); 1141cfb9de9cSPaul Brook } 1142cfb9de9cSPaul Brook 114383f7d43aSAndreas Färber type_init(esp_register_types) 1144