1*881d588aSDmitry Fleytman /* 2*881d588aSDmitry Fleytman * QEMU VMWARE PVSCSI paravirtual SCSI bus 3*881d588aSDmitry Fleytman * 4*881d588aSDmitry Fleytman * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) 5*881d588aSDmitry Fleytman * 6*881d588aSDmitry Fleytman * Developed by Daynix Computing LTD (http://www.daynix.com) 7*881d588aSDmitry Fleytman * 8*881d588aSDmitry Fleytman * Based on implementation by Paolo Bonzini 9*881d588aSDmitry Fleytman * http://lists.gnu.org/archive/html/qemu-devel/2011-08/msg00729.html 10*881d588aSDmitry Fleytman * 11*881d588aSDmitry Fleytman * Authors: 12*881d588aSDmitry Fleytman * Paolo Bonzini <pbonzini@redhat.com> 13*881d588aSDmitry Fleytman * Dmitry Fleytman <dmitry@daynix.com> 14*881d588aSDmitry Fleytman * Yan Vugenfirer <yan@daynix.com> 15*881d588aSDmitry Fleytman * 16*881d588aSDmitry Fleytman * This work is licensed under the terms of the GNU GPL, version 2. 17*881d588aSDmitry Fleytman * See the COPYING file in the top-level directory. 18*881d588aSDmitry Fleytman * 19*881d588aSDmitry Fleytman * NOTE about MSI-X: 20*881d588aSDmitry Fleytman * MSI-X support has been removed for the moment because it leads Windows OS 21*881d588aSDmitry Fleytman * to crash on startup. The crash happens because Windows driver requires 22*881d588aSDmitry Fleytman * MSI-X shared memory to be part of the same BAR used for rings state 23*881d588aSDmitry Fleytman * registers, etc. This is not supported by QEMU infrastructure so separate 24*881d588aSDmitry Fleytman * BAR created from MSI-X purposes. Windows driver fails to deal with 2 BARs. 25*881d588aSDmitry Fleytman * 26*881d588aSDmitry Fleytman */ 27*881d588aSDmitry Fleytman 28*881d588aSDmitry Fleytman #include "hw/scsi/scsi.h" 29*881d588aSDmitry Fleytman #include <block/scsi.h> 30*881d588aSDmitry Fleytman #include "hw/pci/msi.h" 31*881d588aSDmitry Fleytman #include "vmw_pvscsi.h" 32*881d588aSDmitry Fleytman #include "trace.h" 33*881d588aSDmitry Fleytman 34*881d588aSDmitry Fleytman 35*881d588aSDmitry Fleytman #define PVSCSI_MSI_OFFSET (0x50) 36*881d588aSDmitry Fleytman #define PVSCSI_USE_64BIT (true) 37*881d588aSDmitry Fleytman #define PVSCSI_PER_VECTOR_MASK (false) 38*881d588aSDmitry Fleytman 39*881d588aSDmitry Fleytman #define PVSCSI_MAX_DEVS (64) 40*881d588aSDmitry Fleytman #define PVSCSI_MSIX_NUM_VECTORS (1) 41*881d588aSDmitry Fleytman 42*881d588aSDmitry Fleytman #define PVSCSI_MAX_CMD_DATA_WORDS \ 43*881d588aSDmitry Fleytman (sizeof(PVSCSICmdDescSetupRings)/sizeof(uint32_t)) 44*881d588aSDmitry Fleytman 45*881d588aSDmitry Fleytman #define RS_GET_FIELD(rs_pa, field) \ 46*881d588aSDmitry Fleytman (ldl_le_phys(rs_pa + offsetof(struct PVSCSIRingsState, field))) 47*881d588aSDmitry Fleytman #define RS_SET_FIELD(rs_pa, field, val) \ 48*881d588aSDmitry Fleytman (stl_le_phys(rs_pa + offsetof(struct PVSCSIRingsState, field), val)) 49*881d588aSDmitry Fleytman 50*881d588aSDmitry Fleytman #define TYPE_PVSCSI "pvscsi" 51*881d588aSDmitry Fleytman #define PVSCSI(obj) OBJECT_CHECK(PVSCSIState, (obj), TYPE_PVSCSI) 52*881d588aSDmitry Fleytman 53*881d588aSDmitry Fleytman typedef struct PVSCSIRingInfo { 54*881d588aSDmitry Fleytman uint64_t rs_pa; 55*881d588aSDmitry Fleytman uint32_t txr_len_mask; 56*881d588aSDmitry Fleytman uint32_t rxr_len_mask; 57*881d588aSDmitry Fleytman uint32_t msg_len_mask; 58*881d588aSDmitry Fleytman uint64_t req_ring_pages_pa[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES]; 59*881d588aSDmitry Fleytman uint64_t cmp_ring_pages_pa[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES]; 60*881d588aSDmitry Fleytman uint64_t msg_ring_pages_pa[PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES]; 61*881d588aSDmitry Fleytman uint64_t consumed_ptr; 62*881d588aSDmitry Fleytman uint64_t filled_cmp_ptr; 63*881d588aSDmitry Fleytman uint64_t filled_msg_ptr; 64*881d588aSDmitry Fleytman } PVSCSIRingInfo; 65*881d588aSDmitry Fleytman 66*881d588aSDmitry Fleytman typedef struct PVSCSISGState { 67*881d588aSDmitry Fleytman hwaddr elemAddr; 68*881d588aSDmitry Fleytman hwaddr dataAddr; 69*881d588aSDmitry Fleytman uint32_t resid; 70*881d588aSDmitry Fleytman } PVSCSISGState; 71*881d588aSDmitry Fleytman 72*881d588aSDmitry Fleytman typedef QTAILQ_HEAD(, PVSCSIRequest) PVSCSIRequestList; 73*881d588aSDmitry Fleytman 74*881d588aSDmitry Fleytman typedef struct { 75*881d588aSDmitry Fleytman PCIDevice parent_obj; 76*881d588aSDmitry Fleytman MemoryRegion io_space; 77*881d588aSDmitry Fleytman SCSIBus bus; 78*881d588aSDmitry Fleytman QEMUBH *completion_worker; 79*881d588aSDmitry Fleytman PVSCSIRequestList pending_queue; 80*881d588aSDmitry Fleytman PVSCSIRequestList completion_queue; 81*881d588aSDmitry Fleytman 82*881d588aSDmitry Fleytman uint64_t reg_interrupt_status; /* Interrupt status register value */ 83*881d588aSDmitry Fleytman uint64_t reg_interrupt_enabled; /* Interrupt mask register value */ 84*881d588aSDmitry Fleytman uint64_t reg_command_status; /* Command status register value */ 85*881d588aSDmitry Fleytman 86*881d588aSDmitry Fleytman /* Command data adoption mechanism */ 87*881d588aSDmitry Fleytman uint64_t curr_cmd; /* Last command arrived */ 88*881d588aSDmitry Fleytman uint32_t curr_cmd_data_cntr; /* Amount of data for last command */ 89*881d588aSDmitry Fleytman 90*881d588aSDmitry Fleytman /* Collector for current command data */ 91*881d588aSDmitry Fleytman uint32_t curr_cmd_data[PVSCSI_MAX_CMD_DATA_WORDS]; 92*881d588aSDmitry Fleytman 93*881d588aSDmitry Fleytman uint8_t rings_info_valid; /* Whether data rings initialized */ 94*881d588aSDmitry Fleytman uint8_t msg_ring_info_valid; /* Whether message ring initialized */ 95*881d588aSDmitry Fleytman uint8_t use_msg; /* Whether to use message ring */ 96*881d588aSDmitry Fleytman 97*881d588aSDmitry Fleytman uint8_t msi_used; /* Whether MSI support was installed successfully */ 98*881d588aSDmitry Fleytman 99*881d588aSDmitry Fleytman PVSCSIRingInfo rings; /* Data transfer rings manager */ 100*881d588aSDmitry Fleytman uint32_t resetting; /* Reset in progress */ 101*881d588aSDmitry Fleytman } PVSCSIState; 102*881d588aSDmitry Fleytman 103*881d588aSDmitry Fleytman typedef struct PVSCSIRequest { 104*881d588aSDmitry Fleytman SCSIRequest *sreq; 105*881d588aSDmitry Fleytman PVSCSIState *dev; 106*881d588aSDmitry Fleytman uint8_t sense_key; 107*881d588aSDmitry Fleytman uint8_t completed; 108*881d588aSDmitry Fleytman int lun; 109*881d588aSDmitry Fleytman QEMUSGList sgl; 110*881d588aSDmitry Fleytman PVSCSISGState sg; 111*881d588aSDmitry Fleytman struct PVSCSIRingReqDesc req; 112*881d588aSDmitry Fleytman struct PVSCSIRingCmpDesc cmp; 113*881d588aSDmitry Fleytman QTAILQ_ENTRY(PVSCSIRequest) next; 114*881d588aSDmitry Fleytman } PVSCSIRequest; 115*881d588aSDmitry Fleytman 116*881d588aSDmitry Fleytman /* Integer binary logarithm */ 117*881d588aSDmitry Fleytman static int 118*881d588aSDmitry Fleytman pvscsi_log2(uint32_t input) 119*881d588aSDmitry Fleytman { 120*881d588aSDmitry Fleytman int log = 0; 121*881d588aSDmitry Fleytman assert(input > 0); 122*881d588aSDmitry Fleytman while (input >> ++log) { 123*881d588aSDmitry Fleytman } 124*881d588aSDmitry Fleytman return log; 125*881d588aSDmitry Fleytman } 126*881d588aSDmitry Fleytman 127*881d588aSDmitry Fleytman static void 128*881d588aSDmitry Fleytman pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri) 129*881d588aSDmitry Fleytman { 130*881d588aSDmitry Fleytman int i; 131*881d588aSDmitry Fleytman uint32_t txr_len_log2, rxr_len_log2; 132*881d588aSDmitry Fleytman uint32_t req_ring_size, cmp_ring_size; 133*881d588aSDmitry Fleytman m->rs_pa = ri->ringsStatePPN << VMW_PAGE_SHIFT; 134*881d588aSDmitry Fleytman 135*881d588aSDmitry Fleytman req_ring_size = ri->reqRingNumPages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; 136*881d588aSDmitry Fleytman cmp_ring_size = ri->cmpRingNumPages * PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE; 137*881d588aSDmitry Fleytman txr_len_log2 = pvscsi_log2(req_ring_size - 1); 138*881d588aSDmitry Fleytman rxr_len_log2 = pvscsi_log2(cmp_ring_size - 1); 139*881d588aSDmitry Fleytman 140*881d588aSDmitry Fleytman m->txr_len_mask = MASK(txr_len_log2); 141*881d588aSDmitry Fleytman m->rxr_len_mask = MASK(rxr_len_log2); 142*881d588aSDmitry Fleytman 143*881d588aSDmitry Fleytman m->consumed_ptr = 0; 144*881d588aSDmitry Fleytman m->filled_cmp_ptr = 0; 145*881d588aSDmitry Fleytman 146*881d588aSDmitry Fleytman for (i = 0; i < ri->reqRingNumPages; i++) { 147*881d588aSDmitry Fleytman m->req_ring_pages_pa[i] = ri->reqRingPPNs[i] << VMW_PAGE_SHIFT; 148*881d588aSDmitry Fleytman } 149*881d588aSDmitry Fleytman 150*881d588aSDmitry Fleytman for (i = 0; i < ri->cmpRingNumPages; i++) { 151*881d588aSDmitry Fleytman m->cmp_ring_pages_pa[i] = ri->cmpRingPPNs[i] << VMW_PAGE_SHIFT; 152*881d588aSDmitry Fleytman } 153*881d588aSDmitry Fleytman 154*881d588aSDmitry Fleytman RS_SET_FIELD(m->rs_pa, reqProdIdx, 0); 155*881d588aSDmitry Fleytman RS_SET_FIELD(m->rs_pa, reqConsIdx, 0); 156*881d588aSDmitry Fleytman RS_SET_FIELD(m->rs_pa, reqNumEntriesLog2, txr_len_log2); 157*881d588aSDmitry Fleytman 158*881d588aSDmitry Fleytman RS_SET_FIELD(m->rs_pa, cmpProdIdx, 0); 159*881d588aSDmitry Fleytman RS_SET_FIELD(m->rs_pa, cmpConsIdx, 0); 160*881d588aSDmitry Fleytman RS_SET_FIELD(m->rs_pa, cmpNumEntriesLog2, rxr_len_log2); 161*881d588aSDmitry Fleytman 162*881d588aSDmitry Fleytman trace_pvscsi_ring_init_data(txr_len_log2, rxr_len_log2); 163*881d588aSDmitry Fleytman 164*881d588aSDmitry Fleytman /* Flush ring state page changes */ 165*881d588aSDmitry Fleytman smp_wmb(); 166*881d588aSDmitry Fleytman } 167*881d588aSDmitry Fleytman 168*881d588aSDmitry Fleytman static void 169*881d588aSDmitry Fleytman pvscsi_ring_init_msg(PVSCSIRingInfo *m, PVSCSICmdDescSetupMsgRing *ri) 170*881d588aSDmitry Fleytman { 171*881d588aSDmitry Fleytman int i; 172*881d588aSDmitry Fleytman uint32_t len_log2; 173*881d588aSDmitry Fleytman uint32_t ring_size; 174*881d588aSDmitry Fleytman 175*881d588aSDmitry Fleytman ring_size = ri->numPages * PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE; 176*881d588aSDmitry Fleytman len_log2 = pvscsi_log2(ring_size - 1); 177*881d588aSDmitry Fleytman 178*881d588aSDmitry Fleytman m->msg_len_mask = MASK(len_log2); 179*881d588aSDmitry Fleytman 180*881d588aSDmitry Fleytman m->filled_msg_ptr = 0; 181*881d588aSDmitry Fleytman 182*881d588aSDmitry Fleytman for (i = 0; i < ri->numPages; i++) { 183*881d588aSDmitry Fleytman m->msg_ring_pages_pa[i] = ri->ringPPNs[i] << VMW_PAGE_SHIFT; 184*881d588aSDmitry Fleytman } 185*881d588aSDmitry Fleytman 186*881d588aSDmitry Fleytman RS_SET_FIELD(m->rs_pa, msgProdIdx, 0); 187*881d588aSDmitry Fleytman RS_SET_FIELD(m->rs_pa, msgConsIdx, 0); 188*881d588aSDmitry Fleytman RS_SET_FIELD(m->rs_pa, msgNumEntriesLog2, len_log2); 189*881d588aSDmitry Fleytman 190*881d588aSDmitry Fleytman trace_pvscsi_ring_init_msg(len_log2); 191*881d588aSDmitry Fleytman 192*881d588aSDmitry Fleytman /* Flush ring state page changes */ 193*881d588aSDmitry Fleytman smp_wmb(); 194*881d588aSDmitry Fleytman } 195*881d588aSDmitry Fleytman 196*881d588aSDmitry Fleytman static void 197*881d588aSDmitry Fleytman pvscsi_ring_cleanup(PVSCSIRingInfo *mgr) 198*881d588aSDmitry Fleytman { 199*881d588aSDmitry Fleytman mgr->rs_pa = 0; 200*881d588aSDmitry Fleytman mgr->txr_len_mask = 0; 201*881d588aSDmitry Fleytman mgr->rxr_len_mask = 0; 202*881d588aSDmitry Fleytman mgr->msg_len_mask = 0; 203*881d588aSDmitry Fleytman mgr->consumed_ptr = 0; 204*881d588aSDmitry Fleytman mgr->filled_cmp_ptr = 0; 205*881d588aSDmitry Fleytman mgr->filled_msg_ptr = 0; 206*881d588aSDmitry Fleytman memset(mgr->req_ring_pages_pa, 0, sizeof(mgr->req_ring_pages_pa)); 207*881d588aSDmitry Fleytman memset(mgr->cmp_ring_pages_pa, 0, sizeof(mgr->cmp_ring_pages_pa)); 208*881d588aSDmitry Fleytman memset(mgr->msg_ring_pages_pa, 0, sizeof(mgr->msg_ring_pages_pa)); 209*881d588aSDmitry Fleytman } 210*881d588aSDmitry Fleytman 211*881d588aSDmitry Fleytman static hwaddr 212*881d588aSDmitry Fleytman pvscsi_ring_pop_req_descr(PVSCSIRingInfo *mgr) 213*881d588aSDmitry Fleytman { 214*881d588aSDmitry Fleytman uint32_t ready_ptr = RS_GET_FIELD(mgr->rs_pa, reqProdIdx); 215*881d588aSDmitry Fleytman 216*881d588aSDmitry Fleytman if (ready_ptr != mgr->consumed_ptr) { 217*881d588aSDmitry Fleytman uint32_t next_ready_ptr = 218*881d588aSDmitry Fleytman mgr->consumed_ptr++ & mgr->txr_len_mask; 219*881d588aSDmitry Fleytman uint32_t next_ready_page = 220*881d588aSDmitry Fleytman next_ready_ptr / PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; 221*881d588aSDmitry Fleytman uint32_t inpage_idx = 222*881d588aSDmitry Fleytman next_ready_ptr % PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; 223*881d588aSDmitry Fleytman 224*881d588aSDmitry Fleytman return mgr->req_ring_pages_pa[next_ready_page] + 225*881d588aSDmitry Fleytman inpage_idx * sizeof(PVSCSIRingReqDesc); 226*881d588aSDmitry Fleytman } else { 227*881d588aSDmitry Fleytman return 0; 228*881d588aSDmitry Fleytman } 229*881d588aSDmitry Fleytman } 230*881d588aSDmitry Fleytman 231*881d588aSDmitry Fleytman static void 232*881d588aSDmitry Fleytman pvscsi_ring_flush_req(PVSCSIRingInfo *mgr) 233*881d588aSDmitry Fleytman { 234*881d588aSDmitry Fleytman RS_SET_FIELD(mgr->rs_pa, reqConsIdx, mgr->consumed_ptr); 235*881d588aSDmitry Fleytman } 236*881d588aSDmitry Fleytman 237*881d588aSDmitry Fleytman static hwaddr 238*881d588aSDmitry Fleytman pvscsi_ring_pop_cmp_descr(PVSCSIRingInfo *mgr) 239*881d588aSDmitry Fleytman { 240*881d588aSDmitry Fleytman /* 241*881d588aSDmitry Fleytman * According to Linux driver code it explicitly verifies that number 242*881d588aSDmitry Fleytman * of requests being processed by device is less then the size of 243*881d588aSDmitry Fleytman * completion queue, so device may omit completion queue overflow 244*881d588aSDmitry Fleytman * conditions check. We assume that this is true for other (Windows) 245*881d588aSDmitry Fleytman * drivers as well. 246*881d588aSDmitry Fleytman */ 247*881d588aSDmitry Fleytman 248*881d588aSDmitry Fleytman uint32_t free_cmp_ptr = 249*881d588aSDmitry Fleytman mgr->filled_cmp_ptr++ & mgr->rxr_len_mask; 250*881d588aSDmitry Fleytman uint32_t free_cmp_page = 251*881d588aSDmitry Fleytman free_cmp_ptr / PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE; 252*881d588aSDmitry Fleytman uint32_t inpage_idx = 253*881d588aSDmitry Fleytman free_cmp_ptr % PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE; 254*881d588aSDmitry Fleytman return mgr->cmp_ring_pages_pa[free_cmp_page] + 255*881d588aSDmitry Fleytman inpage_idx * sizeof(PVSCSIRingCmpDesc); 256*881d588aSDmitry Fleytman } 257*881d588aSDmitry Fleytman 258*881d588aSDmitry Fleytman static hwaddr 259*881d588aSDmitry Fleytman pvscsi_ring_pop_msg_descr(PVSCSIRingInfo *mgr) 260*881d588aSDmitry Fleytman { 261*881d588aSDmitry Fleytman uint32_t free_msg_ptr = 262*881d588aSDmitry Fleytman mgr->filled_msg_ptr++ & mgr->msg_len_mask; 263*881d588aSDmitry Fleytman uint32_t free_msg_page = 264*881d588aSDmitry Fleytman free_msg_ptr / PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE; 265*881d588aSDmitry Fleytman uint32_t inpage_idx = 266*881d588aSDmitry Fleytman free_msg_ptr % PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE; 267*881d588aSDmitry Fleytman return mgr->msg_ring_pages_pa[free_msg_page] + 268*881d588aSDmitry Fleytman inpage_idx * sizeof(PVSCSIRingMsgDesc); 269*881d588aSDmitry Fleytman } 270*881d588aSDmitry Fleytman 271*881d588aSDmitry Fleytman static void 272*881d588aSDmitry Fleytman pvscsi_ring_flush_cmp(PVSCSIRingInfo *mgr) 273*881d588aSDmitry Fleytman { 274*881d588aSDmitry Fleytman /* Flush descriptor changes */ 275*881d588aSDmitry Fleytman smp_wmb(); 276*881d588aSDmitry Fleytman 277*881d588aSDmitry Fleytman trace_pvscsi_ring_flush_cmp(mgr->filled_cmp_ptr); 278*881d588aSDmitry Fleytman 279*881d588aSDmitry Fleytman RS_SET_FIELD(mgr->rs_pa, cmpProdIdx, mgr->filled_cmp_ptr); 280*881d588aSDmitry Fleytman } 281*881d588aSDmitry Fleytman 282*881d588aSDmitry Fleytman static bool 283*881d588aSDmitry Fleytman pvscsi_ring_msg_has_room(PVSCSIRingInfo *mgr) 284*881d588aSDmitry Fleytman { 285*881d588aSDmitry Fleytman uint32_t prodIdx = RS_GET_FIELD(mgr->rs_pa, msgProdIdx); 286*881d588aSDmitry Fleytman uint32_t consIdx = RS_GET_FIELD(mgr->rs_pa, msgConsIdx); 287*881d588aSDmitry Fleytman 288*881d588aSDmitry Fleytman return (prodIdx - consIdx) < (mgr->msg_len_mask + 1); 289*881d588aSDmitry Fleytman } 290*881d588aSDmitry Fleytman 291*881d588aSDmitry Fleytman static void 292*881d588aSDmitry Fleytman pvscsi_ring_flush_msg(PVSCSIRingInfo *mgr) 293*881d588aSDmitry Fleytman { 294*881d588aSDmitry Fleytman /* Flush descriptor changes */ 295*881d588aSDmitry Fleytman smp_wmb(); 296*881d588aSDmitry Fleytman 297*881d588aSDmitry Fleytman trace_pvscsi_ring_flush_msg(mgr->filled_msg_ptr); 298*881d588aSDmitry Fleytman 299*881d588aSDmitry Fleytman RS_SET_FIELD(mgr->rs_pa, msgProdIdx, mgr->filled_msg_ptr); 300*881d588aSDmitry Fleytman } 301*881d588aSDmitry Fleytman 302*881d588aSDmitry Fleytman static void 303*881d588aSDmitry Fleytman pvscsi_reset_state(PVSCSIState *s) 304*881d588aSDmitry Fleytman { 305*881d588aSDmitry Fleytman s->curr_cmd = PVSCSI_CMD_FIRST; 306*881d588aSDmitry Fleytman s->curr_cmd_data_cntr = 0; 307*881d588aSDmitry Fleytman s->reg_command_status = PVSCSI_COMMAND_PROCESSING_SUCCEEDED; 308*881d588aSDmitry Fleytman s->reg_interrupt_status = 0; 309*881d588aSDmitry Fleytman pvscsi_ring_cleanup(&s->rings); 310*881d588aSDmitry Fleytman s->rings_info_valid = FALSE; 311*881d588aSDmitry Fleytman s->msg_ring_info_valid = FALSE; 312*881d588aSDmitry Fleytman QTAILQ_INIT(&s->pending_queue); 313*881d588aSDmitry Fleytman QTAILQ_INIT(&s->completion_queue); 314*881d588aSDmitry Fleytman } 315*881d588aSDmitry Fleytman 316*881d588aSDmitry Fleytman static void 317*881d588aSDmitry Fleytman pvscsi_update_irq_status(PVSCSIState *s) 318*881d588aSDmitry Fleytman { 319*881d588aSDmitry Fleytman PCIDevice *d = PCI_DEVICE(s); 320*881d588aSDmitry Fleytman bool should_raise = s->reg_interrupt_enabled & s->reg_interrupt_status; 321*881d588aSDmitry Fleytman 322*881d588aSDmitry Fleytman trace_pvscsi_update_irq_level(should_raise, s->reg_interrupt_enabled, 323*881d588aSDmitry Fleytman s->reg_interrupt_status); 324*881d588aSDmitry Fleytman 325*881d588aSDmitry Fleytman if (s->msi_used && msi_enabled(d)) { 326*881d588aSDmitry Fleytman if (should_raise) { 327*881d588aSDmitry Fleytman trace_pvscsi_update_irq_msi(); 328*881d588aSDmitry Fleytman msi_notify(d, PVSCSI_VECTOR_COMPLETION); 329*881d588aSDmitry Fleytman } 330*881d588aSDmitry Fleytman return; 331*881d588aSDmitry Fleytman } 332*881d588aSDmitry Fleytman 333*881d588aSDmitry Fleytman qemu_set_irq(d->irq[0], !!should_raise); 334*881d588aSDmitry Fleytman } 335*881d588aSDmitry Fleytman 336*881d588aSDmitry Fleytman static void 337*881d588aSDmitry Fleytman pvscsi_raise_completion_interrupt(PVSCSIState *s) 338*881d588aSDmitry Fleytman { 339*881d588aSDmitry Fleytman s->reg_interrupt_status |= PVSCSI_INTR_CMPL_0; 340*881d588aSDmitry Fleytman 341*881d588aSDmitry Fleytman /* Memory barrier to flush interrupt status register changes*/ 342*881d588aSDmitry Fleytman smp_wmb(); 343*881d588aSDmitry Fleytman 344*881d588aSDmitry Fleytman pvscsi_update_irq_status(s); 345*881d588aSDmitry Fleytman } 346*881d588aSDmitry Fleytman 347*881d588aSDmitry Fleytman static void 348*881d588aSDmitry Fleytman pvscsi_raise_message_interrupt(PVSCSIState *s) 349*881d588aSDmitry Fleytman { 350*881d588aSDmitry Fleytman s->reg_interrupt_status |= PVSCSI_INTR_MSG_0; 351*881d588aSDmitry Fleytman 352*881d588aSDmitry Fleytman /* Memory barrier to flush interrupt status register changes*/ 353*881d588aSDmitry Fleytman smp_wmb(); 354*881d588aSDmitry Fleytman 355*881d588aSDmitry Fleytman pvscsi_update_irq_status(s); 356*881d588aSDmitry Fleytman } 357*881d588aSDmitry Fleytman 358*881d588aSDmitry Fleytman static void 359*881d588aSDmitry Fleytman pvscsi_cmp_ring_put(PVSCSIState *s, struct PVSCSIRingCmpDesc *cmp_desc) 360*881d588aSDmitry Fleytman { 361*881d588aSDmitry Fleytman hwaddr cmp_descr_pa; 362*881d588aSDmitry Fleytman 363*881d588aSDmitry Fleytman cmp_descr_pa = pvscsi_ring_pop_cmp_descr(&s->rings); 364*881d588aSDmitry Fleytman trace_pvscsi_cmp_ring_put(cmp_descr_pa); 365*881d588aSDmitry Fleytman cpu_physical_memory_write(cmp_descr_pa, (void *)cmp_desc, 366*881d588aSDmitry Fleytman sizeof(*cmp_desc)); 367*881d588aSDmitry Fleytman } 368*881d588aSDmitry Fleytman 369*881d588aSDmitry Fleytman static void 370*881d588aSDmitry Fleytman pvscsi_msg_ring_put(PVSCSIState *s, struct PVSCSIRingMsgDesc *msg_desc) 371*881d588aSDmitry Fleytman { 372*881d588aSDmitry Fleytman hwaddr msg_descr_pa; 373*881d588aSDmitry Fleytman 374*881d588aSDmitry Fleytman msg_descr_pa = pvscsi_ring_pop_msg_descr(&s->rings); 375*881d588aSDmitry Fleytman trace_pvscsi_msg_ring_put(msg_descr_pa); 376*881d588aSDmitry Fleytman cpu_physical_memory_write(msg_descr_pa, (void *)msg_desc, 377*881d588aSDmitry Fleytman sizeof(*msg_desc)); 378*881d588aSDmitry Fleytman } 379*881d588aSDmitry Fleytman 380*881d588aSDmitry Fleytman static void 381*881d588aSDmitry Fleytman pvscsi_process_completion_queue(void *opaque) 382*881d588aSDmitry Fleytman { 383*881d588aSDmitry Fleytman PVSCSIState *s = opaque; 384*881d588aSDmitry Fleytman PVSCSIRequest *pvscsi_req; 385*881d588aSDmitry Fleytman bool has_completed = false; 386*881d588aSDmitry Fleytman 387*881d588aSDmitry Fleytman while (!QTAILQ_EMPTY(&s->completion_queue)) { 388*881d588aSDmitry Fleytman pvscsi_req = QTAILQ_FIRST(&s->completion_queue); 389*881d588aSDmitry Fleytman QTAILQ_REMOVE(&s->completion_queue, pvscsi_req, next); 390*881d588aSDmitry Fleytman pvscsi_cmp_ring_put(s, &pvscsi_req->cmp); 391*881d588aSDmitry Fleytman g_free(pvscsi_req); 392*881d588aSDmitry Fleytman has_completed++; 393*881d588aSDmitry Fleytman } 394*881d588aSDmitry Fleytman 395*881d588aSDmitry Fleytman if (has_completed) { 396*881d588aSDmitry Fleytman pvscsi_ring_flush_cmp(&s->rings); 397*881d588aSDmitry Fleytman pvscsi_raise_completion_interrupt(s); 398*881d588aSDmitry Fleytman } 399*881d588aSDmitry Fleytman } 400*881d588aSDmitry Fleytman 401*881d588aSDmitry Fleytman static void 402*881d588aSDmitry Fleytman pvscsi_reset_adapter(PVSCSIState *s) 403*881d588aSDmitry Fleytman { 404*881d588aSDmitry Fleytman s->resetting++; 405*881d588aSDmitry Fleytman qbus_reset_all_fn(&s->bus); 406*881d588aSDmitry Fleytman s->resetting--; 407*881d588aSDmitry Fleytman pvscsi_process_completion_queue(s); 408*881d588aSDmitry Fleytman assert(QTAILQ_EMPTY(&s->pending_queue)); 409*881d588aSDmitry Fleytman pvscsi_reset_state(s); 410*881d588aSDmitry Fleytman } 411*881d588aSDmitry Fleytman 412*881d588aSDmitry Fleytman static void 413*881d588aSDmitry Fleytman pvscsi_schedule_completion_processing(PVSCSIState *s) 414*881d588aSDmitry Fleytman { 415*881d588aSDmitry Fleytman /* Try putting more complete requests on the ring. */ 416*881d588aSDmitry Fleytman if (!QTAILQ_EMPTY(&s->completion_queue)) { 417*881d588aSDmitry Fleytman qemu_bh_schedule(s->completion_worker); 418*881d588aSDmitry Fleytman } 419*881d588aSDmitry Fleytman } 420*881d588aSDmitry Fleytman 421*881d588aSDmitry Fleytman static void 422*881d588aSDmitry Fleytman pvscsi_complete_request(PVSCSIState *s, PVSCSIRequest *r) 423*881d588aSDmitry Fleytman { 424*881d588aSDmitry Fleytman assert(!r->completed); 425*881d588aSDmitry Fleytman 426*881d588aSDmitry Fleytman trace_pvscsi_complete_request(r->cmp.context, r->cmp.dataLen, 427*881d588aSDmitry Fleytman r->sense_key); 428*881d588aSDmitry Fleytman if (r->sreq != NULL) { 429*881d588aSDmitry Fleytman scsi_req_unref(r->sreq); 430*881d588aSDmitry Fleytman r->sreq = NULL; 431*881d588aSDmitry Fleytman } 432*881d588aSDmitry Fleytman r->completed = 1; 433*881d588aSDmitry Fleytman QTAILQ_REMOVE(&s->pending_queue, r, next); 434*881d588aSDmitry Fleytman QTAILQ_INSERT_TAIL(&s->completion_queue, r, next); 435*881d588aSDmitry Fleytman pvscsi_schedule_completion_processing(s); 436*881d588aSDmitry Fleytman } 437*881d588aSDmitry Fleytman 438*881d588aSDmitry Fleytman static QEMUSGList *pvscsi_get_sg_list(SCSIRequest *r) 439*881d588aSDmitry Fleytman { 440*881d588aSDmitry Fleytman PVSCSIRequest *req = r->hba_private; 441*881d588aSDmitry Fleytman 442*881d588aSDmitry Fleytman trace_pvscsi_get_sg_list(req->sgl.nsg, req->sgl.size); 443*881d588aSDmitry Fleytman 444*881d588aSDmitry Fleytman return &req->sgl; 445*881d588aSDmitry Fleytman } 446*881d588aSDmitry Fleytman 447*881d588aSDmitry Fleytman static void 448*881d588aSDmitry Fleytman pvscsi_get_next_sg_elem(PVSCSISGState *sg) 449*881d588aSDmitry Fleytman { 450*881d588aSDmitry Fleytman struct PVSCSISGElement elem; 451*881d588aSDmitry Fleytman 452*881d588aSDmitry Fleytman cpu_physical_memory_read(sg->elemAddr, (void *)&elem, sizeof(elem)); 453*881d588aSDmitry Fleytman if ((elem.flags & ~PVSCSI_KNOWN_FLAGS) != 0) { 454*881d588aSDmitry Fleytman /* 455*881d588aSDmitry Fleytman * There is PVSCSI_SGE_FLAG_CHAIN_ELEMENT flag described in 456*881d588aSDmitry Fleytman * header file but its value is unknown. This flag requires 457*881d588aSDmitry Fleytman * additional processing, so we put warning here to catch it 458*881d588aSDmitry Fleytman * some day and make proper implementation 459*881d588aSDmitry Fleytman */ 460*881d588aSDmitry Fleytman trace_pvscsi_get_next_sg_elem(elem.flags); 461*881d588aSDmitry Fleytman } 462*881d588aSDmitry Fleytman 463*881d588aSDmitry Fleytman sg->elemAddr += sizeof(elem); 464*881d588aSDmitry Fleytman sg->dataAddr = elem.addr; 465*881d588aSDmitry Fleytman sg->resid = elem.length; 466*881d588aSDmitry Fleytman } 467*881d588aSDmitry Fleytman 468*881d588aSDmitry Fleytman static void 469*881d588aSDmitry Fleytman pvscsi_write_sense(PVSCSIRequest *r, uint8_t *sense, int len) 470*881d588aSDmitry Fleytman { 471*881d588aSDmitry Fleytman r->cmp.senseLen = MIN(r->req.senseLen, len); 472*881d588aSDmitry Fleytman r->sense_key = sense[(sense[0] & 2) ? 1 : 2]; 473*881d588aSDmitry Fleytman cpu_physical_memory_write(r->req.senseAddr, sense, r->cmp.senseLen); 474*881d588aSDmitry Fleytman } 475*881d588aSDmitry Fleytman 476*881d588aSDmitry Fleytman static void 477*881d588aSDmitry Fleytman pvscsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid) 478*881d588aSDmitry Fleytman { 479*881d588aSDmitry Fleytman PVSCSIRequest *pvscsi_req = req->hba_private; 480*881d588aSDmitry Fleytman PVSCSIState *s = pvscsi_req->dev; 481*881d588aSDmitry Fleytman 482*881d588aSDmitry Fleytman if (!pvscsi_req) { 483*881d588aSDmitry Fleytman trace_pvscsi_command_complete_not_found(req->tag); 484*881d588aSDmitry Fleytman return; 485*881d588aSDmitry Fleytman } 486*881d588aSDmitry Fleytman 487*881d588aSDmitry Fleytman if (resid) { 488*881d588aSDmitry Fleytman /* Short transfer. */ 489*881d588aSDmitry Fleytman trace_pvscsi_command_complete_data_run(); 490*881d588aSDmitry Fleytman pvscsi_req->cmp.hostStatus = BTSTAT_DATARUN; 491*881d588aSDmitry Fleytman } 492*881d588aSDmitry Fleytman 493*881d588aSDmitry Fleytman pvscsi_req->cmp.scsiStatus = status; 494*881d588aSDmitry Fleytman if (pvscsi_req->cmp.scsiStatus == CHECK_CONDITION) { 495*881d588aSDmitry Fleytman uint8_t sense[SCSI_SENSE_BUF_SIZE]; 496*881d588aSDmitry Fleytman int sense_len = 497*881d588aSDmitry Fleytman scsi_req_get_sense(pvscsi_req->sreq, sense, sizeof(sense)); 498*881d588aSDmitry Fleytman 499*881d588aSDmitry Fleytman trace_pvscsi_command_complete_sense_len(sense_len); 500*881d588aSDmitry Fleytman pvscsi_write_sense(pvscsi_req, sense, sense_len); 501*881d588aSDmitry Fleytman } 502*881d588aSDmitry Fleytman qemu_sglist_destroy(&pvscsi_req->sgl); 503*881d588aSDmitry Fleytman pvscsi_complete_request(s, pvscsi_req); 504*881d588aSDmitry Fleytman } 505*881d588aSDmitry Fleytman 506*881d588aSDmitry Fleytman static void 507*881d588aSDmitry Fleytman pvscsi_send_msg(PVSCSIState *s, SCSIDevice *dev, uint32_t msg_type) 508*881d588aSDmitry Fleytman { 509*881d588aSDmitry Fleytman if (s->msg_ring_info_valid && pvscsi_ring_msg_has_room(&s->rings)) { 510*881d588aSDmitry Fleytman PVSCSIMsgDescDevStatusChanged msg = {0}; 511*881d588aSDmitry Fleytman 512*881d588aSDmitry Fleytman msg.type = msg_type; 513*881d588aSDmitry Fleytman msg.bus = dev->channel; 514*881d588aSDmitry Fleytman msg.target = dev->id; 515*881d588aSDmitry Fleytman msg.lun[1] = dev->lun; 516*881d588aSDmitry Fleytman 517*881d588aSDmitry Fleytman pvscsi_msg_ring_put(s, (PVSCSIRingMsgDesc *)&msg); 518*881d588aSDmitry Fleytman pvscsi_ring_flush_msg(&s->rings); 519*881d588aSDmitry Fleytman pvscsi_raise_message_interrupt(s); 520*881d588aSDmitry Fleytman } 521*881d588aSDmitry Fleytman } 522*881d588aSDmitry Fleytman 523*881d588aSDmitry Fleytman static void 524*881d588aSDmitry Fleytman pvscsi_hotplug(SCSIBus *bus, SCSIDevice *dev) 525*881d588aSDmitry Fleytman { 526*881d588aSDmitry Fleytman PVSCSIState *s = container_of(bus, PVSCSIState, bus); 527*881d588aSDmitry Fleytman pvscsi_send_msg(s, dev, PVSCSI_MSG_DEV_ADDED); 528*881d588aSDmitry Fleytman } 529*881d588aSDmitry Fleytman 530*881d588aSDmitry Fleytman static void 531*881d588aSDmitry Fleytman pvscsi_hot_unplug(SCSIBus *bus, SCSIDevice *dev) 532*881d588aSDmitry Fleytman { 533*881d588aSDmitry Fleytman PVSCSIState *s = container_of(bus, PVSCSIState, bus); 534*881d588aSDmitry Fleytman pvscsi_send_msg(s, dev, PVSCSI_MSG_DEV_REMOVED); 535*881d588aSDmitry Fleytman } 536*881d588aSDmitry Fleytman 537*881d588aSDmitry Fleytman static void 538*881d588aSDmitry Fleytman pvscsi_request_cancelled(SCSIRequest *req) 539*881d588aSDmitry Fleytman { 540*881d588aSDmitry Fleytman PVSCSIRequest *pvscsi_req = req->hba_private; 541*881d588aSDmitry Fleytman PVSCSIState *s = pvscsi_req->dev; 542*881d588aSDmitry Fleytman 543*881d588aSDmitry Fleytman if (pvscsi_req->completed) { 544*881d588aSDmitry Fleytman return; 545*881d588aSDmitry Fleytman } 546*881d588aSDmitry Fleytman 547*881d588aSDmitry Fleytman if (pvscsi_req->dev->resetting) { 548*881d588aSDmitry Fleytman pvscsi_req->cmp.hostStatus = BTSTAT_BUSRESET; 549*881d588aSDmitry Fleytman } else { 550*881d588aSDmitry Fleytman pvscsi_req->cmp.hostStatus = BTSTAT_ABORTQUEUE; 551*881d588aSDmitry Fleytman } 552*881d588aSDmitry Fleytman 553*881d588aSDmitry Fleytman pvscsi_complete_request(s, pvscsi_req); 554*881d588aSDmitry Fleytman } 555*881d588aSDmitry Fleytman 556*881d588aSDmitry Fleytman static SCSIDevice* 557*881d588aSDmitry Fleytman pvscsi_device_find(PVSCSIState *s, int channel, int target, 558*881d588aSDmitry Fleytman uint8_t *requested_lun, uint8_t *target_lun) 559*881d588aSDmitry Fleytman { 560*881d588aSDmitry Fleytman if (requested_lun[0] || requested_lun[2] || requested_lun[3] || 561*881d588aSDmitry Fleytman requested_lun[4] || requested_lun[5] || requested_lun[6] || 562*881d588aSDmitry Fleytman requested_lun[7] || (target > PVSCSI_MAX_DEVS)) { 563*881d588aSDmitry Fleytman return NULL; 564*881d588aSDmitry Fleytman } else { 565*881d588aSDmitry Fleytman *target_lun = requested_lun[1]; 566*881d588aSDmitry Fleytman return scsi_device_find(&s->bus, channel, target, *target_lun); 567*881d588aSDmitry Fleytman } 568*881d588aSDmitry Fleytman } 569*881d588aSDmitry Fleytman 570*881d588aSDmitry Fleytman static PVSCSIRequest * 571*881d588aSDmitry Fleytman pvscsi_queue_pending_descriptor(PVSCSIState *s, SCSIDevice **d, 572*881d588aSDmitry Fleytman struct PVSCSIRingReqDesc *descr) 573*881d588aSDmitry Fleytman { 574*881d588aSDmitry Fleytman PVSCSIRequest *pvscsi_req; 575*881d588aSDmitry Fleytman uint8_t lun; 576*881d588aSDmitry Fleytman 577*881d588aSDmitry Fleytman pvscsi_req = g_malloc0(sizeof(*pvscsi_req)); 578*881d588aSDmitry Fleytman pvscsi_req->dev = s; 579*881d588aSDmitry Fleytman pvscsi_req->req = *descr; 580*881d588aSDmitry Fleytman pvscsi_req->cmp.context = pvscsi_req->req.context; 581*881d588aSDmitry Fleytman QTAILQ_INSERT_TAIL(&s->pending_queue, pvscsi_req, next); 582*881d588aSDmitry Fleytman 583*881d588aSDmitry Fleytman *d = pvscsi_device_find(s, descr->bus, descr->target, descr->lun, &lun); 584*881d588aSDmitry Fleytman if (*d) { 585*881d588aSDmitry Fleytman pvscsi_req->lun = lun; 586*881d588aSDmitry Fleytman } 587*881d588aSDmitry Fleytman 588*881d588aSDmitry Fleytman return pvscsi_req; 589*881d588aSDmitry Fleytman } 590*881d588aSDmitry Fleytman 591*881d588aSDmitry Fleytman static void 592*881d588aSDmitry Fleytman pvscsi_convert_sglist(PVSCSIRequest *r) 593*881d588aSDmitry Fleytman { 594*881d588aSDmitry Fleytman int chunk_size; 595*881d588aSDmitry Fleytman uint64_t data_length = r->req.dataLen; 596*881d588aSDmitry Fleytman PVSCSISGState sg = r->sg; 597*881d588aSDmitry Fleytman while (data_length) { 598*881d588aSDmitry Fleytman while (!sg.resid) { 599*881d588aSDmitry Fleytman pvscsi_get_next_sg_elem(&sg); 600*881d588aSDmitry Fleytman trace_pvscsi_convert_sglist(r->req.context, r->sg.dataAddr, 601*881d588aSDmitry Fleytman r->sg.resid); 602*881d588aSDmitry Fleytman } 603*881d588aSDmitry Fleytman assert(data_length > 0); 604*881d588aSDmitry Fleytman chunk_size = MIN((unsigned) data_length, sg.resid); 605*881d588aSDmitry Fleytman if (chunk_size) { 606*881d588aSDmitry Fleytman qemu_sglist_add(&r->sgl, sg.dataAddr, chunk_size); 607*881d588aSDmitry Fleytman } 608*881d588aSDmitry Fleytman 609*881d588aSDmitry Fleytman sg.dataAddr += chunk_size; 610*881d588aSDmitry Fleytman data_length -= chunk_size; 611*881d588aSDmitry Fleytman sg.resid -= chunk_size; 612*881d588aSDmitry Fleytman } 613*881d588aSDmitry Fleytman } 614*881d588aSDmitry Fleytman 615*881d588aSDmitry Fleytman static void 616*881d588aSDmitry Fleytman pvscsi_build_sglist(PVSCSIState *s, PVSCSIRequest *r) 617*881d588aSDmitry Fleytman { 618*881d588aSDmitry Fleytman PCIDevice *d = PCI_DEVICE(s); 619*881d588aSDmitry Fleytman 620*881d588aSDmitry Fleytman qemu_sglist_init(&r->sgl, 1, pci_dma_context(d)); 621*881d588aSDmitry Fleytman if (r->req.flags & PVSCSI_FLAG_CMD_WITH_SG_LIST) { 622*881d588aSDmitry Fleytman pvscsi_convert_sglist(r); 623*881d588aSDmitry Fleytman } else { 624*881d588aSDmitry Fleytman qemu_sglist_add(&r->sgl, r->req.dataAddr, r->req.dataLen); 625*881d588aSDmitry Fleytman } 626*881d588aSDmitry Fleytman } 627*881d588aSDmitry Fleytman 628*881d588aSDmitry Fleytman static void 629*881d588aSDmitry Fleytman pvscsi_process_request_descriptor(PVSCSIState *s, 630*881d588aSDmitry Fleytman struct PVSCSIRingReqDesc *descr) 631*881d588aSDmitry Fleytman { 632*881d588aSDmitry Fleytman SCSIDevice *d; 633*881d588aSDmitry Fleytman PVSCSIRequest *r = pvscsi_queue_pending_descriptor(s, &d, descr); 634*881d588aSDmitry Fleytman int64_t n; 635*881d588aSDmitry Fleytman 636*881d588aSDmitry Fleytman trace_pvscsi_process_req_descr(descr->cdb[0], descr->context); 637*881d588aSDmitry Fleytman 638*881d588aSDmitry Fleytman if (!d) { 639*881d588aSDmitry Fleytman r->cmp.hostStatus = BTSTAT_SELTIMEO; 640*881d588aSDmitry Fleytman trace_pvscsi_process_req_descr_unknown_device(); 641*881d588aSDmitry Fleytman pvscsi_complete_request(s, r); 642*881d588aSDmitry Fleytman return; 643*881d588aSDmitry Fleytman } 644*881d588aSDmitry Fleytman 645*881d588aSDmitry Fleytman if (descr->flags & PVSCSI_FLAG_CMD_WITH_SG_LIST) { 646*881d588aSDmitry Fleytman r->sg.elemAddr = descr->dataAddr; 647*881d588aSDmitry Fleytman } 648*881d588aSDmitry Fleytman 649*881d588aSDmitry Fleytman r->sreq = scsi_req_new(d, descr->context, r->lun, descr->cdb, r); 650*881d588aSDmitry Fleytman if (r->sreq->cmd.mode == SCSI_XFER_FROM_DEV && 651*881d588aSDmitry Fleytman (descr->flags & PVSCSI_FLAG_CMD_DIR_TODEVICE)) { 652*881d588aSDmitry Fleytman r->cmp.hostStatus = BTSTAT_BADMSG; 653*881d588aSDmitry Fleytman trace_pvscsi_process_req_descr_invalid_dir(); 654*881d588aSDmitry Fleytman scsi_req_cancel(r->sreq); 655*881d588aSDmitry Fleytman return; 656*881d588aSDmitry Fleytman } 657*881d588aSDmitry Fleytman if (r->sreq->cmd.mode == SCSI_XFER_TO_DEV && 658*881d588aSDmitry Fleytman (descr->flags & PVSCSI_FLAG_CMD_DIR_TOHOST)) { 659*881d588aSDmitry Fleytman r->cmp.hostStatus = BTSTAT_BADMSG; 660*881d588aSDmitry Fleytman trace_pvscsi_process_req_descr_invalid_dir(); 661*881d588aSDmitry Fleytman scsi_req_cancel(r->sreq); 662*881d588aSDmitry Fleytman return; 663*881d588aSDmitry Fleytman } 664*881d588aSDmitry Fleytman 665*881d588aSDmitry Fleytman pvscsi_build_sglist(s, r); 666*881d588aSDmitry Fleytman n = scsi_req_enqueue(r->sreq); 667*881d588aSDmitry Fleytman 668*881d588aSDmitry Fleytman if (n) { 669*881d588aSDmitry Fleytman scsi_req_continue(r->sreq); 670*881d588aSDmitry Fleytman } 671*881d588aSDmitry Fleytman } 672*881d588aSDmitry Fleytman 673*881d588aSDmitry Fleytman static void 674*881d588aSDmitry Fleytman pvscsi_process_io(PVSCSIState *s) 675*881d588aSDmitry Fleytman { 676*881d588aSDmitry Fleytman PVSCSIRingReqDesc descr; 677*881d588aSDmitry Fleytman hwaddr next_descr_pa; 678*881d588aSDmitry Fleytman 679*881d588aSDmitry Fleytman assert(s->rings_info_valid); 680*881d588aSDmitry Fleytman while ((next_descr_pa = pvscsi_ring_pop_req_descr(&s->rings)) != 0) { 681*881d588aSDmitry Fleytman 682*881d588aSDmitry Fleytman /* Only read after production index verification */ 683*881d588aSDmitry Fleytman smp_rmb(); 684*881d588aSDmitry Fleytman 685*881d588aSDmitry Fleytman trace_pvscsi_process_io(next_descr_pa); 686*881d588aSDmitry Fleytman cpu_physical_memory_read(next_descr_pa, &descr, sizeof(descr)); 687*881d588aSDmitry Fleytman pvscsi_process_request_descriptor(s, &descr); 688*881d588aSDmitry Fleytman } 689*881d588aSDmitry Fleytman 690*881d588aSDmitry Fleytman pvscsi_ring_flush_req(&s->rings); 691*881d588aSDmitry Fleytman } 692*881d588aSDmitry Fleytman 693*881d588aSDmitry Fleytman static void 694*881d588aSDmitry Fleytman pvscsi_dbg_dump_tx_rings_config(PVSCSICmdDescSetupRings *rc) 695*881d588aSDmitry Fleytman { 696*881d588aSDmitry Fleytman int i; 697*881d588aSDmitry Fleytman trace_pvscsi_tx_rings_ppn("Rings State", rc->ringsStatePPN); 698*881d588aSDmitry Fleytman 699*881d588aSDmitry Fleytman trace_pvscsi_tx_rings_num_pages("Request Ring", rc->reqRingNumPages); 700*881d588aSDmitry Fleytman for (i = 0; i < rc->reqRingNumPages; i++) { 701*881d588aSDmitry Fleytman trace_pvscsi_tx_rings_ppn("Request Ring", rc->reqRingPPNs[i]); 702*881d588aSDmitry Fleytman } 703*881d588aSDmitry Fleytman 704*881d588aSDmitry Fleytman trace_pvscsi_tx_rings_num_pages("Confirm Ring", rc->cmpRingNumPages); 705*881d588aSDmitry Fleytman for (i = 0; i < rc->cmpRingNumPages; i++) { 706*881d588aSDmitry Fleytman trace_pvscsi_tx_rings_ppn("Confirm Ring", rc->reqRingPPNs[i]); 707*881d588aSDmitry Fleytman } 708*881d588aSDmitry Fleytman } 709*881d588aSDmitry Fleytman 710*881d588aSDmitry Fleytman static uint64_t 711*881d588aSDmitry Fleytman pvscsi_on_cmd_config(PVSCSIState *s) 712*881d588aSDmitry Fleytman { 713*881d588aSDmitry Fleytman trace_pvscsi_on_cmd_noimpl("PVSCSI_CMD_CONFIG"); 714*881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_FAILED; 715*881d588aSDmitry Fleytman } 716*881d588aSDmitry Fleytman 717*881d588aSDmitry Fleytman static uint64_t 718*881d588aSDmitry Fleytman pvscsi_on_cmd_unplug(PVSCSIState *s) 719*881d588aSDmitry Fleytman { 720*881d588aSDmitry Fleytman trace_pvscsi_on_cmd_noimpl("PVSCSI_CMD_DEVICE_UNPLUG"); 721*881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_FAILED; 722*881d588aSDmitry Fleytman } 723*881d588aSDmitry Fleytman 724*881d588aSDmitry Fleytman static uint64_t 725*881d588aSDmitry Fleytman pvscsi_on_issue_scsi(PVSCSIState *s) 726*881d588aSDmitry Fleytman { 727*881d588aSDmitry Fleytman trace_pvscsi_on_cmd_noimpl("PVSCSI_CMD_ISSUE_SCSI"); 728*881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_FAILED; 729*881d588aSDmitry Fleytman } 730*881d588aSDmitry Fleytman 731*881d588aSDmitry Fleytman static uint64_t 732*881d588aSDmitry Fleytman pvscsi_on_cmd_setup_rings(PVSCSIState *s) 733*881d588aSDmitry Fleytman { 734*881d588aSDmitry Fleytman PVSCSICmdDescSetupRings *rc = 735*881d588aSDmitry Fleytman (PVSCSICmdDescSetupRings *) s->curr_cmd_data; 736*881d588aSDmitry Fleytman 737*881d588aSDmitry Fleytman trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_SETUP_RINGS"); 738*881d588aSDmitry Fleytman 739*881d588aSDmitry Fleytman pvscsi_dbg_dump_tx_rings_config(rc); 740*881d588aSDmitry Fleytman pvscsi_ring_init_data(&s->rings, rc); 741*881d588aSDmitry Fleytman s->rings_info_valid = TRUE; 742*881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; 743*881d588aSDmitry Fleytman } 744*881d588aSDmitry Fleytman 745*881d588aSDmitry Fleytman static uint64_t 746*881d588aSDmitry Fleytman pvscsi_on_cmd_abort(PVSCSIState *s) 747*881d588aSDmitry Fleytman { 748*881d588aSDmitry Fleytman PVSCSICmdDescAbortCmd *cmd = (PVSCSICmdDescAbortCmd *) s->curr_cmd_data; 749*881d588aSDmitry Fleytman PVSCSIRequest *r, *next; 750*881d588aSDmitry Fleytman 751*881d588aSDmitry Fleytman trace_pvscsi_on_cmd_abort(cmd->context, cmd->target); 752*881d588aSDmitry Fleytman 753*881d588aSDmitry Fleytman QTAILQ_FOREACH_SAFE(r, &s->pending_queue, next, next) { 754*881d588aSDmitry Fleytman if (r->req.context == cmd->context) { 755*881d588aSDmitry Fleytman break; 756*881d588aSDmitry Fleytman } 757*881d588aSDmitry Fleytman } 758*881d588aSDmitry Fleytman if (r) { 759*881d588aSDmitry Fleytman assert(!r->completed); 760*881d588aSDmitry Fleytman r->cmp.hostStatus = BTSTAT_ABORTQUEUE; 761*881d588aSDmitry Fleytman scsi_req_cancel(r->sreq); 762*881d588aSDmitry Fleytman } 763*881d588aSDmitry Fleytman 764*881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; 765*881d588aSDmitry Fleytman } 766*881d588aSDmitry Fleytman 767*881d588aSDmitry Fleytman static uint64_t 768*881d588aSDmitry Fleytman pvscsi_on_cmd_unknown(PVSCSIState *s) 769*881d588aSDmitry Fleytman { 770*881d588aSDmitry Fleytman trace_pvscsi_on_cmd_unknown_data(s->curr_cmd_data[0]); 771*881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_FAILED; 772*881d588aSDmitry Fleytman } 773*881d588aSDmitry Fleytman 774*881d588aSDmitry Fleytman static uint64_t 775*881d588aSDmitry Fleytman pvscsi_on_cmd_reset_device(PVSCSIState *s) 776*881d588aSDmitry Fleytman { 777*881d588aSDmitry Fleytman uint8_t target_lun = 0; 778*881d588aSDmitry Fleytman struct PVSCSICmdDescResetDevice *cmd = 779*881d588aSDmitry Fleytman (struct PVSCSICmdDescResetDevice *) s->curr_cmd_data; 780*881d588aSDmitry Fleytman SCSIDevice *sdev; 781*881d588aSDmitry Fleytman 782*881d588aSDmitry Fleytman sdev = pvscsi_device_find(s, 0, cmd->target, cmd->lun, &target_lun); 783*881d588aSDmitry Fleytman 784*881d588aSDmitry Fleytman trace_pvscsi_on_cmd_reset_dev(cmd->target, (int) target_lun, sdev); 785*881d588aSDmitry Fleytman 786*881d588aSDmitry Fleytman if (sdev != NULL) { 787*881d588aSDmitry Fleytman s->resetting++; 788*881d588aSDmitry Fleytman device_reset(&sdev->qdev); 789*881d588aSDmitry Fleytman s->resetting--; 790*881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; 791*881d588aSDmitry Fleytman } 792*881d588aSDmitry Fleytman 793*881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_FAILED; 794*881d588aSDmitry Fleytman } 795*881d588aSDmitry Fleytman 796*881d588aSDmitry Fleytman static uint64_t 797*881d588aSDmitry Fleytman pvscsi_on_cmd_reset_bus(PVSCSIState *s) 798*881d588aSDmitry Fleytman { 799*881d588aSDmitry Fleytman trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_RESET_BUS"); 800*881d588aSDmitry Fleytman 801*881d588aSDmitry Fleytman s->resetting++; 802*881d588aSDmitry Fleytman qbus_reset_all_fn(&s->bus); 803*881d588aSDmitry Fleytman s->resetting--; 804*881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; 805*881d588aSDmitry Fleytman } 806*881d588aSDmitry Fleytman 807*881d588aSDmitry Fleytman static uint64_t 808*881d588aSDmitry Fleytman pvscsi_on_cmd_setup_msg_ring(PVSCSIState *s) 809*881d588aSDmitry Fleytman { 810*881d588aSDmitry Fleytman PVSCSICmdDescSetupMsgRing *rc = 811*881d588aSDmitry Fleytman (PVSCSICmdDescSetupMsgRing *) s->curr_cmd_data; 812*881d588aSDmitry Fleytman 813*881d588aSDmitry Fleytman trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_SETUP_MSG_RING"); 814*881d588aSDmitry Fleytman 815*881d588aSDmitry Fleytman if (!s->use_msg) { 816*881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_FAILED; 817*881d588aSDmitry Fleytman } 818*881d588aSDmitry Fleytman 819*881d588aSDmitry Fleytman if (s->rings_info_valid) { 820*881d588aSDmitry Fleytman pvscsi_ring_init_msg(&s->rings, rc); 821*881d588aSDmitry Fleytman s->msg_ring_info_valid = TRUE; 822*881d588aSDmitry Fleytman } 823*881d588aSDmitry Fleytman return sizeof(PVSCSICmdDescSetupMsgRing) / sizeof(uint32_t); 824*881d588aSDmitry Fleytman } 825*881d588aSDmitry Fleytman 826*881d588aSDmitry Fleytman static uint64_t 827*881d588aSDmitry Fleytman pvscsi_on_cmd_adapter_reset(PVSCSIState *s) 828*881d588aSDmitry Fleytman { 829*881d588aSDmitry Fleytman trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_ADAPTER_RESET"); 830*881d588aSDmitry Fleytman 831*881d588aSDmitry Fleytman pvscsi_reset_adapter(s); 832*881d588aSDmitry Fleytman return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; 833*881d588aSDmitry Fleytman } 834*881d588aSDmitry Fleytman 835*881d588aSDmitry Fleytman static const struct { 836*881d588aSDmitry Fleytman int data_size; 837*881d588aSDmitry Fleytman uint64_t (*handler_fn)(PVSCSIState *s); 838*881d588aSDmitry Fleytman } pvscsi_commands[] = { 839*881d588aSDmitry Fleytman [PVSCSI_CMD_FIRST] = { 840*881d588aSDmitry Fleytman .data_size = 0, 841*881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_unknown, 842*881d588aSDmitry Fleytman }, 843*881d588aSDmitry Fleytman 844*881d588aSDmitry Fleytman /* Not implemented, data size defined based on what arrives on windows */ 845*881d588aSDmitry Fleytman [PVSCSI_CMD_CONFIG] = { 846*881d588aSDmitry Fleytman .data_size = 6 * sizeof(uint32_t), 847*881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_config, 848*881d588aSDmitry Fleytman }, 849*881d588aSDmitry Fleytman 850*881d588aSDmitry Fleytman /* Command not implemented, data size is unknown */ 851*881d588aSDmitry Fleytman [PVSCSI_CMD_ISSUE_SCSI] = { 852*881d588aSDmitry Fleytman .data_size = 0, 853*881d588aSDmitry Fleytman .handler_fn = pvscsi_on_issue_scsi, 854*881d588aSDmitry Fleytman }, 855*881d588aSDmitry Fleytman 856*881d588aSDmitry Fleytman /* Command not implemented, data size is unknown */ 857*881d588aSDmitry Fleytman [PVSCSI_CMD_DEVICE_UNPLUG] = { 858*881d588aSDmitry Fleytman .data_size = 0, 859*881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_unplug, 860*881d588aSDmitry Fleytman }, 861*881d588aSDmitry Fleytman 862*881d588aSDmitry Fleytman [PVSCSI_CMD_SETUP_RINGS] = { 863*881d588aSDmitry Fleytman .data_size = sizeof(PVSCSICmdDescSetupRings), 864*881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_setup_rings, 865*881d588aSDmitry Fleytman }, 866*881d588aSDmitry Fleytman 867*881d588aSDmitry Fleytman [PVSCSI_CMD_RESET_DEVICE] = { 868*881d588aSDmitry Fleytman .data_size = sizeof(struct PVSCSICmdDescResetDevice), 869*881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_reset_device, 870*881d588aSDmitry Fleytman }, 871*881d588aSDmitry Fleytman 872*881d588aSDmitry Fleytman [PVSCSI_CMD_RESET_BUS] = { 873*881d588aSDmitry Fleytman .data_size = 0, 874*881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_reset_bus, 875*881d588aSDmitry Fleytman }, 876*881d588aSDmitry Fleytman 877*881d588aSDmitry Fleytman [PVSCSI_CMD_SETUP_MSG_RING] = { 878*881d588aSDmitry Fleytman .data_size = sizeof(PVSCSICmdDescSetupMsgRing), 879*881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_setup_msg_ring, 880*881d588aSDmitry Fleytman }, 881*881d588aSDmitry Fleytman 882*881d588aSDmitry Fleytman [PVSCSI_CMD_ADAPTER_RESET] = { 883*881d588aSDmitry Fleytman .data_size = 0, 884*881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_adapter_reset, 885*881d588aSDmitry Fleytman }, 886*881d588aSDmitry Fleytman 887*881d588aSDmitry Fleytman [PVSCSI_CMD_ABORT_CMD] = { 888*881d588aSDmitry Fleytman .data_size = sizeof(struct PVSCSICmdDescAbortCmd), 889*881d588aSDmitry Fleytman .handler_fn = pvscsi_on_cmd_abort, 890*881d588aSDmitry Fleytman }, 891*881d588aSDmitry Fleytman }; 892*881d588aSDmitry Fleytman 893*881d588aSDmitry Fleytman static void 894*881d588aSDmitry Fleytman pvscsi_do_command_processing(PVSCSIState *s) 895*881d588aSDmitry Fleytman { 896*881d588aSDmitry Fleytman size_t bytes_arrived = s->curr_cmd_data_cntr * sizeof(uint32_t); 897*881d588aSDmitry Fleytman 898*881d588aSDmitry Fleytman assert(s->curr_cmd < PVSCSI_CMD_LAST); 899*881d588aSDmitry Fleytman if (bytes_arrived >= pvscsi_commands[s->curr_cmd].data_size) { 900*881d588aSDmitry Fleytman s->reg_command_status = pvscsi_commands[s->curr_cmd].handler_fn(s); 901*881d588aSDmitry Fleytman s->curr_cmd = PVSCSI_CMD_FIRST; 902*881d588aSDmitry Fleytman s->curr_cmd_data_cntr = 0; 903*881d588aSDmitry Fleytman } 904*881d588aSDmitry Fleytman } 905*881d588aSDmitry Fleytman 906*881d588aSDmitry Fleytman static void 907*881d588aSDmitry Fleytman pvscsi_on_command_data(PVSCSIState *s, uint32_t value) 908*881d588aSDmitry Fleytman { 909*881d588aSDmitry Fleytman size_t bytes_arrived = s->curr_cmd_data_cntr * sizeof(uint32_t); 910*881d588aSDmitry Fleytman 911*881d588aSDmitry Fleytman assert(bytes_arrived < sizeof(s->curr_cmd_data)); 912*881d588aSDmitry Fleytman s->curr_cmd_data[s->curr_cmd_data_cntr++] = value; 913*881d588aSDmitry Fleytman 914*881d588aSDmitry Fleytman pvscsi_do_command_processing(s); 915*881d588aSDmitry Fleytman } 916*881d588aSDmitry Fleytman 917*881d588aSDmitry Fleytman static void 918*881d588aSDmitry Fleytman pvscsi_on_command(PVSCSIState *s, uint64_t cmd_id) 919*881d588aSDmitry Fleytman { 920*881d588aSDmitry Fleytman if ((cmd_id > PVSCSI_CMD_FIRST) && (cmd_id < PVSCSI_CMD_LAST)) { 921*881d588aSDmitry Fleytman s->curr_cmd = cmd_id; 922*881d588aSDmitry Fleytman } else { 923*881d588aSDmitry Fleytman s->curr_cmd = PVSCSI_CMD_FIRST; 924*881d588aSDmitry Fleytman trace_pvscsi_on_cmd_unknown(cmd_id); 925*881d588aSDmitry Fleytman } 926*881d588aSDmitry Fleytman 927*881d588aSDmitry Fleytman s->curr_cmd_data_cntr = 0; 928*881d588aSDmitry Fleytman s->reg_command_status = PVSCSI_COMMAND_NOT_ENOUGH_DATA; 929*881d588aSDmitry Fleytman 930*881d588aSDmitry Fleytman pvscsi_do_command_processing(s); 931*881d588aSDmitry Fleytman } 932*881d588aSDmitry Fleytman 933*881d588aSDmitry Fleytman static void 934*881d588aSDmitry Fleytman pvscsi_io_write(void *opaque, hwaddr addr, 935*881d588aSDmitry Fleytman uint64_t val, unsigned size) 936*881d588aSDmitry Fleytman { 937*881d588aSDmitry Fleytman PVSCSIState *s = opaque; 938*881d588aSDmitry Fleytman 939*881d588aSDmitry Fleytman switch (addr) { 940*881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_COMMAND: 941*881d588aSDmitry Fleytman pvscsi_on_command(s, val); 942*881d588aSDmitry Fleytman break; 943*881d588aSDmitry Fleytman 944*881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_COMMAND_DATA: 945*881d588aSDmitry Fleytman pvscsi_on_command_data(s, (uint32_t) val); 946*881d588aSDmitry Fleytman break; 947*881d588aSDmitry Fleytman 948*881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_INTR_STATUS: 949*881d588aSDmitry Fleytman trace_pvscsi_io_write("PVSCSI_REG_OFFSET_INTR_STATUS", val); 950*881d588aSDmitry Fleytman s->reg_interrupt_status &= ~val; 951*881d588aSDmitry Fleytman pvscsi_update_irq_status(s); 952*881d588aSDmitry Fleytman pvscsi_schedule_completion_processing(s); 953*881d588aSDmitry Fleytman break; 954*881d588aSDmitry Fleytman 955*881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_INTR_MASK: 956*881d588aSDmitry Fleytman trace_pvscsi_io_write("PVSCSI_REG_OFFSET_INTR_MASK", val); 957*881d588aSDmitry Fleytman s->reg_interrupt_enabled = val; 958*881d588aSDmitry Fleytman pvscsi_update_irq_status(s); 959*881d588aSDmitry Fleytman break; 960*881d588aSDmitry Fleytman 961*881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_KICK_NON_RW_IO: 962*881d588aSDmitry Fleytman trace_pvscsi_io_write("PVSCSI_REG_OFFSET_KICK_NON_RW_IO", val); 963*881d588aSDmitry Fleytman pvscsi_process_io(s); 964*881d588aSDmitry Fleytman break; 965*881d588aSDmitry Fleytman 966*881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_KICK_RW_IO: 967*881d588aSDmitry Fleytman trace_pvscsi_io_write("PVSCSI_REG_OFFSET_KICK_RW_IO", val); 968*881d588aSDmitry Fleytman pvscsi_process_io(s); 969*881d588aSDmitry Fleytman break; 970*881d588aSDmitry Fleytman 971*881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_DEBUG: 972*881d588aSDmitry Fleytman trace_pvscsi_io_write("PVSCSI_REG_OFFSET_DEBUG", val); 973*881d588aSDmitry Fleytman break; 974*881d588aSDmitry Fleytman 975*881d588aSDmitry Fleytman default: 976*881d588aSDmitry Fleytman trace_pvscsi_io_write_unknown(addr, size, val); 977*881d588aSDmitry Fleytman break; 978*881d588aSDmitry Fleytman } 979*881d588aSDmitry Fleytman 980*881d588aSDmitry Fleytman } 981*881d588aSDmitry Fleytman 982*881d588aSDmitry Fleytman static uint64_t 983*881d588aSDmitry Fleytman pvscsi_io_read(void *opaque, hwaddr addr, unsigned size) 984*881d588aSDmitry Fleytman { 985*881d588aSDmitry Fleytman PVSCSIState *s = opaque; 986*881d588aSDmitry Fleytman 987*881d588aSDmitry Fleytman switch (addr) { 988*881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_INTR_STATUS: 989*881d588aSDmitry Fleytman trace_pvscsi_io_read("PVSCSI_REG_OFFSET_INTR_STATUS", 990*881d588aSDmitry Fleytman s->reg_interrupt_status); 991*881d588aSDmitry Fleytman return s->reg_interrupt_status; 992*881d588aSDmitry Fleytman 993*881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_INTR_MASK: 994*881d588aSDmitry Fleytman trace_pvscsi_io_read("PVSCSI_REG_OFFSET_INTR_MASK", 995*881d588aSDmitry Fleytman s->reg_interrupt_status); 996*881d588aSDmitry Fleytman return s->reg_interrupt_enabled; 997*881d588aSDmitry Fleytman 998*881d588aSDmitry Fleytman case PVSCSI_REG_OFFSET_COMMAND_STATUS: 999*881d588aSDmitry Fleytman trace_pvscsi_io_read("PVSCSI_REG_OFFSET_COMMAND_STATUS", 1000*881d588aSDmitry Fleytman s->reg_interrupt_status); 1001*881d588aSDmitry Fleytman return s->reg_command_status; 1002*881d588aSDmitry Fleytman 1003*881d588aSDmitry Fleytman default: 1004*881d588aSDmitry Fleytman trace_pvscsi_io_read_unknown(addr, size); 1005*881d588aSDmitry Fleytman return 0; 1006*881d588aSDmitry Fleytman } 1007*881d588aSDmitry Fleytman } 1008*881d588aSDmitry Fleytman 1009*881d588aSDmitry Fleytman 1010*881d588aSDmitry Fleytman static bool 1011*881d588aSDmitry Fleytman pvscsi_init_msi(PVSCSIState *s) 1012*881d588aSDmitry Fleytman { 1013*881d588aSDmitry Fleytman int res; 1014*881d588aSDmitry Fleytman PCIDevice *d = PCI_DEVICE(s); 1015*881d588aSDmitry Fleytman 1016*881d588aSDmitry Fleytman res = msi_init(d, PVSCSI_MSI_OFFSET, PVSCSI_MSIX_NUM_VECTORS, 1017*881d588aSDmitry Fleytman PVSCSI_USE_64BIT, PVSCSI_PER_VECTOR_MASK); 1018*881d588aSDmitry Fleytman if (res < 0) { 1019*881d588aSDmitry Fleytman trace_pvscsi_init_msi_fail(res); 1020*881d588aSDmitry Fleytman s->msi_used = false; 1021*881d588aSDmitry Fleytman } else { 1022*881d588aSDmitry Fleytman s->msi_used = true; 1023*881d588aSDmitry Fleytman } 1024*881d588aSDmitry Fleytman 1025*881d588aSDmitry Fleytman return s->msi_used; 1026*881d588aSDmitry Fleytman } 1027*881d588aSDmitry Fleytman 1028*881d588aSDmitry Fleytman static void 1029*881d588aSDmitry Fleytman pvscsi_cleanup_msi(PVSCSIState *s) 1030*881d588aSDmitry Fleytman { 1031*881d588aSDmitry Fleytman PCIDevice *d = PCI_DEVICE(s); 1032*881d588aSDmitry Fleytman 1033*881d588aSDmitry Fleytman if (s->msi_used) { 1034*881d588aSDmitry Fleytman msi_uninit(d); 1035*881d588aSDmitry Fleytman } 1036*881d588aSDmitry Fleytman } 1037*881d588aSDmitry Fleytman 1038*881d588aSDmitry Fleytman static const MemoryRegionOps pvscsi_ops = { 1039*881d588aSDmitry Fleytman .read = pvscsi_io_read, 1040*881d588aSDmitry Fleytman .write = pvscsi_io_write, 1041*881d588aSDmitry Fleytman .endianness = DEVICE_LITTLE_ENDIAN, 1042*881d588aSDmitry Fleytman .impl = { 1043*881d588aSDmitry Fleytman .min_access_size = 4, 1044*881d588aSDmitry Fleytman .max_access_size = 4, 1045*881d588aSDmitry Fleytman }, 1046*881d588aSDmitry Fleytman }; 1047*881d588aSDmitry Fleytman 1048*881d588aSDmitry Fleytman static const struct SCSIBusInfo pvscsi_scsi_info = { 1049*881d588aSDmitry Fleytman .tcq = true, 1050*881d588aSDmitry Fleytman .max_target = PVSCSI_MAX_DEVS, 1051*881d588aSDmitry Fleytman .max_channel = 0, 1052*881d588aSDmitry Fleytman .max_lun = 0, 1053*881d588aSDmitry Fleytman 1054*881d588aSDmitry Fleytman .get_sg_list = pvscsi_get_sg_list, 1055*881d588aSDmitry Fleytman .complete = pvscsi_command_complete, 1056*881d588aSDmitry Fleytman .cancel = pvscsi_request_cancelled, 1057*881d588aSDmitry Fleytman .hotplug = pvscsi_hotplug, 1058*881d588aSDmitry Fleytman .hot_unplug = pvscsi_hot_unplug, 1059*881d588aSDmitry Fleytman }; 1060*881d588aSDmitry Fleytman 1061*881d588aSDmitry Fleytman static int 1062*881d588aSDmitry Fleytman pvscsi_init(PCIDevice *pci_dev) 1063*881d588aSDmitry Fleytman { 1064*881d588aSDmitry Fleytman PVSCSIState *s = PVSCSI(pci_dev); 1065*881d588aSDmitry Fleytman 1066*881d588aSDmitry Fleytman trace_pvscsi_state("init"); 1067*881d588aSDmitry Fleytman 1068*881d588aSDmitry Fleytman /* PCI subsystem ID */ 1069*881d588aSDmitry Fleytman pci_dev->config[PCI_SUBSYSTEM_ID] = 0x00; 1070*881d588aSDmitry Fleytman pci_dev->config[PCI_SUBSYSTEM_ID + 1] = 0x10; 1071*881d588aSDmitry Fleytman 1072*881d588aSDmitry Fleytman /* PCI latency timer = 255 */ 1073*881d588aSDmitry Fleytman pci_dev->config[PCI_LATENCY_TIMER] = 0xff; 1074*881d588aSDmitry Fleytman 1075*881d588aSDmitry Fleytman /* Interrupt pin A */ 1076*881d588aSDmitry Fleytman pci_config_set_interrupt_pin(pci_dev->config, 1); 1077*881d588aSDmitry Fleytman 1078*881d588aSDmitry Fleytman memory_region_init_io(&s->io_space, &pvscsi_ops, s, 1079*881d588aSDmitry Fleytman "pvscsi-io", PVSCSI_MEM_SPACE_SIZE); 1080*881d588aSDmitry Fleytman pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io_space); 1081*881d588aSDmitry Fleytman 1082*881d588aSDmitry Fleytman pvscsi_init_msi(s); 1083*881d588aSDmitry Fleytman 1084*881d588aSDmitry Fleytman s->completion_worker = qemu_bh_new(pvscsi_process_completion_queue, s); 1085*881d588aSDmitry Fleytman if (!s->completion_worker) { 1086*881d588aSDmitry Fleytman pvscsi_cleanup_msi(s); 1087*881d588aSDmitry Fleytman memory_region_destroy(&s->io_space); 1088*881d588aSDmitry Fleytman return -ENOMEM; 1089*881d588aSDmitry Fleytman } 1090*881d588aSDmitry Fleytman 1091*881d588aSDmitry Fleytman scsi_bus_new(&s->bus, &pci_dev->qdev, &pvscsi_scsi_info); 1092*881d588aSDmitry Fleytman pvscsi_reset_state(s); 1093*881d588aSDmitry Fleytman 1094*881d588aSDmitry Fleytman return 0; 1095*881d588aSDmitry Fleytman } 1096*881d588aSDmitry Fleytman 1097*881d588aSDmitry Fleytman static void 1098*881d588aSDmitry Fleytman pvscsi_uninit(PCIDevice *pci_dev) 1099*881d588aSDmitry Fleytman { 1100*881d588aSDmitry Fleytman PVSCSIState *s = PVSCSI(pci_dev); 1101*881d588aSDmitry Fleytman 1102*881d588aSDmitry Fleytman trace_pvscsi_state("uninit"); 1103*881d588aSDmitry Fleytman qemu_bh_delete(s->completion_worker); 1104*881d588aSDmitry Fleytman 1105*881d588aSDmitry Fleytman pvscsi_cleanup_msi(s); 1106*881d588aSDmitry Fleytman 1107*881d588aSDmitry Fleytman memory_region_destroy(&s->io_space); 1108*881d588aSDmitry Fleytman } 1109*881d588aSDmitry Fleytman 1110*881d588aSDmitry Fleytman static void 1111*881d588aSDmitry Fleytman pvscsi_reset(DeviceState *dev) 1112*881d588aSDmitry Fleytman { 1113*881d588aSDmitry Fleytman PCIDevice *d = PCI_DEVICE(dev); 1114*881d588aSDmitry Fleytman PVSCSIState *s = PVSCSI(d); 1115*881d588aSDmitry Fleytman 1116*881d588aSDmitry Fleytman trace_pvscsi_state("reset"); 1117*881d588aSDmitry Fleytman pvscsi_reset_adapter(s); 1118*881d588aSDmitry Fleytman } 1119*881d588aSDmitry Fleytman 1120*881d588aSDmitry Fleytman static void 1121*881d588aSDmitry Fleytman pvscsi_pre_save(void *opaque) 1122*881d588aSDmitry Fleytman { 1123*881d588aSDmitry Fleytman PVSCSIState *s = (PVSCSIState *) opaque; 1124*881d588aSDmitry Fleytman 1125*881d588aSDmitry Fleytman trace_pvscsi_state("presave"); 1126*881d588aSDmitry Fleytman 1127*881d588aSDmitry Fleytman assert(QTAILQ_EMPTY(&s->pending_queue)); 1128*881d588aSDmitry Fleytman assert(QTAILQ_EMPTY(&s->completion_queue)); 1129*881d588aSDmitry Fleytman } 1130*881d588aSDmitry Fleytman 1131*881d588aSDmitry Fleytman static int 1132*881d588aSDmitry Fleytman pvscsi_post_load(void *opaque, int version_id) 1133*881d588aSDmitry Fleytman { 1134*881d588aSDmitry Fleytman trace_pvscsi_state("postload"); 1135*881d588aSDmitry Fleytman return 0; 1136*881d588aSDmitry Fleytman } 1137*881d588aSDmitry Fleytman 1138*881d588aSDmitry Fleytman static const VMStateDescription vmstate_pvscsi = { 1139*881d588aSDmitry Fleytman .name = TYPE_PVSCSI, 1140*881d588aSDmitry Fleytman .version_id = 0, 1141*881d588aSDmitry Fleytman .minimum_version_id = 0, 1142*881d588aSDmitry Fleytman .minimum_version_id_old = 0, 1143*881d588aSDmitry Fleytman .pre_save = pvscsi_pre_save, 1144*881d588aSDmitry Fleytman .post_load = pvscsi_post_load, 1145*881d588aSDmitry Fleytman .fields = (VMStateField[]) { 1146*881d588aSDmitry Fleytman VMSTATE_PCI_DEVICE(parent_obj, PVSCSIState), 1147*881d588aSDmitry Fleytman VMSTATE_UINT8(msi_used, PVSCSIState), 1148*881d588aSDmitry Fleytman VMSTATE_UINT32(resetting, PVSCSIState), 1149*881d588aSDmitry Fleytman VMSTATE_UINT64(reg_interrupt_status, PVSCSIState), 1150*881d588aSDmitry Fleytman VMSTATE_UINT64(reg_interrupt_enabled, PVSCSIState), 1151*881d588aSDmitry Fleytman VMSTATE_UINT64(reg_command_status, PVSCSIState), 1152*881d588aSDmitry Fleytman VMSTATE_UINT64(curr_cmd, PVSCSIState), 1153*881d588aSDmitry Fleytman VMSTATE_UINT32(curr_cmd_data_cntr, PVSCSIState), 1154*881d588aSDmitry Fleytman VMSTATE_UINT32_ARRAY(curr_cmd_data, PVSCSIState, 1155*881d588aSDmitry Fleytman ARRAY_SIZE(((PVSCSIState *)NULL)->curr_cmd_data)), 1156*881d588aSDmitry Fleytman VMSTATE_UINT8(rings_info_valid, PVSCSIState), 1157*881d588aSDmitry Fleytman VMSTATE_UINT8(msg_ring_info_valid, PVSCSIState), 1158*881d588aSDmitry Fleytman VMSTATE_UINT8(use_msg, PVSCSIState), 1159*881d588aSDmitry Fleytman 1160*881d588aSDmitry Fleytman VMSTATE_UINT64(rings.rs_pa, PVSCSIState), 1161*881d588aSDmitry Fleytman VMSTATE_UINT32(rings.txr_len_mask, PVSCSIState), 1162*881d588aSDmitry Fleytman VMSTATE_UINT32(rings.rxr_len_mask, PVSCSIState), 1163*881d588aSDmitry Fleytman VMSTATE_UINT64_ARRAY(rings.req_ring_pages_pa, PVSCSIState, 1164*881d588aSDmitry Fleytman PVSCSI_SETUP_RINGS_MAX_NUM_PAGES), 1165*881d588aSDmitry Fleytman VMSTATE_UINT64_ARRAY(rings.cmp_ring_pages_pa, PVSCSIState, 1166*881d588aSDmitry Fleytman PVSCSI_SETUP_RINGS_MAX_NUM_PAGES), 1167*881d588aSDmitry Fleytman VMSTATE_UINT64(rings.consumed_ptr, PVSCSIState), 1168*881d588aSDmitry Fleytman VMSTATE_UINT64(rings.filled_cmp_ptr, PVSCSIState), 1169*881d588aSDmitry Fleytman 1170*881d588aSDmitry Fleytman VMSTATE_END_OF_LIST() 1171*881d588aSDmitry Fleytman } 1172*881d588aSDmitry Fleytman }; 1173*881d588aSDmitry Fleytman 1174*881d588aSDmitry Fleytman static void 1175*881d588aSDmitry Fleytman pvscsi_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len) 1176*881d588aSDmitry Fleytman { 1177*881d588aSDmitry Fleytman pci_default_write_config(pci, addr, val, len); 1178*881d588aSDmitry Fleytman msi_write_config(pci, addr, val, len); 1179*881d588aSDmitry Fleytman } 1180*881d588aSDmitry Fleytman 1181*881d588aSDmitry Fleytman static Property pvscsi_properties[] = { 1182*881d588aSDmitry Fleytman DEFINE_PROP_UINT8("use_msg", PVSCSIState, use_msg, 1), 1183*881d588aSDmitry Fleytman DEFINE_PROP_END_OF_LIST(), 1184*881d588aSDmitry Fleytman }; 1185*881d588aSDmitry Fleytman 1186*881d588aSDmitry Fleytman static void pvscsi_class_init(ObjectClass *klass, void *data) 1187*881d588aSDmitry Fleytman { 1188*881d588aSDmitry Fleytman DeviceClass *dc = DEVICE_CLASS(klass); 1189*881d588aSDmitry Fleytman PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 1190*881d588aSDmitry Fleytman 1191*881d588aSDmitry Fleytman k->init = pvscsi_init; 1192*881d588aSDmitry Fleytman k->exit = pvscsi_uninit; 1193*881d588aSDmitry Fleytman k->vendor_id = PCI_VENDOR_ID_VMWARE; 1194*881d588aSDmitry Fleytman k->device_id = PCI_DEVICE_ID_VMWARE_PVSCSI; 1195*881d588aSDmitry Fleytman k->class_id = PCI_CLASS_STORAGE_SCSI; 1196*881d588aSDmitry Fleytman k->subsystem_id = 0x1000; 1197*881d588aSDmitry Fleytman dc->reset = pvscsi_reset; 1198*881d588aSDmitry Fleytman dc->vmsd = &vmstate_pvscsi; 1199*881d588aSDmitry Fleytman dc->props = pvscsi_properties; 1200*881d588aSDmitry Fleytman k->config_write = pvscsi_write_config; 1201*881d588aSDmitry Fleytman } 1202*881d588aSDmitry Fleytman 1203*881d588aSDmitry Fleytman static const TypeInfo pvscsi_info = { 1204*881d588aSDmitry Fleytman .name = "pvscsi", 1205*881d588aSDmitry Fleytman .parent = TYPE_PCI_DEVICE, 1206*881d588aSDmitry Fleytman .instance_size = sizeof(PVSCSIState), 1207*881d588aSDmitry Fleytman .class_init = pvscsi_class_init, 1208*881d588aSDmitry Fleytman }; 1209*881d588aSDmitry Fleytman 1210*881d588aSDmitry Fleytman static void 1211*881d588aSDmitry Fleytman pvscsi_register_types(void) 1212*881d588aSDmitry Fleytman { 1213*881d588aSDmitry Fleytman type_register_static(&pvscsi_info); 1214*881d588aSDmitry Fleytman } 1215*881d588aSDmitry Fleytman 1216*881d588aSDmitry Fleytman type_init(pvscsi_register_types); 1217