X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/0c34459b6af1b7ed2f000995b9bcb1c722646fbb..430ee2f26f01f146f3757467b3f0b802ad309ff8:/hw/spapr_vscsi.c diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 762a22ec4a..e8426d7c5e 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -80,7 +80,6 @@ typedef struct vscsi_req { int active; long data_len; int writing; - int sensing; int senselen; uint8_t sense[SCSI_SENSE_BUF_SIZE]; @@ -121,7 +120,7 @@ static struct vscsi_req *vscsi_get_req(VSCSIState *s) return NULL; } -static void vscsi_put_req(VSCSIState *s, vscsi_req *req) +static void vscsi_put_req(vscsi_req *req) { if (req->sreq != NULL) { scsi_req_unref(req->sreq); @@ -130,15 +129,6 @@ static void vscsi_put_req(VSCSIState *s, vscsi_req *req) req->active = 0; } -static vscsi_req *vscsi_find_req(VSCSIState *s, SCSIRequest *req) -{ - uint32_t tag = req->tag; - if (tag >= VSCSI_REQ_LIMIT || !s->reqs[tag].active) { - return NULL; - } - return &s->reqs[tag]; -} - static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun) { /* XXX Figure that one out properly ! This is crackpot */ @@ -445,99 +435,24 @@ static int vscsi_preprocess_desc(vscsi_req *req) return 0; } -static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) -{ - uint8_t *cdb = req->iu.srp.cmd.cdb; - int n; - - cdb[0] = 3; - cdb[1] = 0; - cdb[2] = 0; - cdb[3] = 0; - cdb[4] = 96; - cdb[5] = 0; - req->sensing = 1; - n = scsi_req_enqueue(req->sreq, cdb); - dprintf("VSCSI: Queued request sense tag 0x%x\n", req->qtag); - if (n < 0) { - fprintf(stderr, "VSCSI: REQUEST_SENSE wants write data !?!?!?\n"); - vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); - scsi_req_abort(req->sreq, CHECK_CONDITION); - return; - } else if (n == 0) { - return; - } - scsi_req_continue(req->sreq); -} - /* Callback to indicate that the SCSI layer has completed a transfer. */ -static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg) +static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) { VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); - vscsi_req *req = vscsi_find_req(s, sreq); + vscsi_req *req = sreq->hba_private; uint8_t *buf; - int32_t res_in = 0, res_out = 0; - int len, rc = 0; + int rc = 0; - dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x arg=0x%x, req=%p\n", - reason, sreq->tag, arg, req); + dprintf("VSCSI: SCSI xfer complete tag=0x%x len=0x%x, req=%p\n", + sreq->tag, len, req); if (req == NULL) { fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); return; } - if (req->sensing) { - if (reason == SCSI_REASON_DONE) { - dprintf("VSCSI: Sense done !\n"); - vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); - vscsi_put_req(s, req); - } else { - uint8_t *buf = scsi_req_get_buf(sreq); - - len = MIN(arg, SCSI_SENSE_BUF_SIZE); - dprintf("VSCSI: Sense data, %d bytes:\n", len); - dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", - buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7]); - dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", - buf[8], buf[9], buf[10], buf[11], - buf[12], buf[13], buf[14], buf[15]); - memcpy(req->sense, buf, len); - req->senselen = len; - scsi_req_continue(req->sreq); - } - return; - } - - if (reason == SCSI_REASON_DONE) { - dprintf("VSCSI: Command complete err=%d\n", arg); - if (arg == 0) { - /* We handle overflows, not underflows for normal commands, - * but hopefully nobody cares - */ - if (req->writing) { - res_out = req->data_len; - } else { - res_in = req->data_len; - } - vscsi_send_rsp(s, req, 0, res_in, res_out); - } else if (arg == CHECK_CONDITION) { - dprintf("VSCSI: Got CHECK_CONDITION, requesting sense...\n"); - vscsi_send_request_sense(s, req); - return; - } else { - vscsi_send_rsp(s, req, arg, 0, 0); - } - vscsi_put_req(s, req); - return; - } - - /* "arg" is how much we have read for reads and how much we want - * to write for writes (ie, how much is to be DMA'd) - */ - if (arg) { + if (len) { buf = scsi_req_get_buf(sreq); - rc = vscsi_srp_transfer_data(s, req, req->writing, buf, arg); + rc = vscsi_srp_transfer_data(s, req, req->writing, buf, len); } if (rc < 0) { fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc); @@ -551,12 +466,52 @@ static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg) scsi_req_continue(sreq); } -static void vscsi_request_cancelled(SCSIRequest *sreq) +/* Callback to indicate that the SCSI layer has completed a transfer. */ +static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status) { VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); - vscsi_req *req = vscsi_find_req(s, sreq); + vscsi_req *req = sreq->hba_private; + int32_t res_in = 0, res_out = 0; + + dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n", + reason, sreq->tag, status, req); + if (req == NULL) { + fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); + return; + } - vscsi_put_req(s, req); + if (status == CHECK_CONDITION) { + req->senselen = scsi_req_get_sense(req->sreq, req->sense, + sizeof(req->sense)); + dprintf("VSCSI: Sense data, %d bytes:\n", len); + dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", + req->sense[0], req->sense[1], req->sense[2], req->sense[3], + req->sense[4], req->sense[5], req->sense[6], req->sense[7]); + dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", + req->sense[8], req->sense[9], req->sense[10], req->sense[11], + req->sense[12], req->sense[13], req->sense[14], req->sense[15]); + } + + dprintf("VSCSI: Command complete err=%d\n", status); + if (status == 0) { + /* We handle overflows, not underflows for normal commands, + * but hopefully nobody cares + */ + if (req->writing) { + res_out = req->data_len; + } else { + res_in = req->data_len; + } + } + vscsi_send_rsp(s, req, status, res_in, res_out); + vscsi_put_req(req); +} + +static void vscsi_request_cancelled(SCSIRequest *sreq) +{ + vscsi_req *req = sreq->hba_private; + + vscsi_put_req(req); } static void vscsi_process_login(VSCSIState *s, vscsi_req *req) @@ -644,8 +599,8 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) } req->lun = lun; - req->sreq = scsi_req_new(sdev, req->qtag, lun); - n = scsi_req_enqueue(req->sreq, srp->cmd.cdb); + req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req); + n = scsi_req_enqueue(req->sreq); dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n", req->qtag, srp->cmd.cdb[0], id, lun, n); @@ -832,7 +787,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq) if (spapr_tce_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu, crq->s.IU_length)) { fprintf(stderr, "vscsi_got_payload: DMA read failure !\n"); - qemu_free(req); + g_free(req); } memcpy(&req->crq, crq, sizeof(vscsi_crq)); @@ -843,7 +798,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq) } if (done) { - vscsi_put_req(s, req); + vscsi_put_req(req); } } @@ -908,6 +863,7 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data) } static const struct SCSIBusOps vscsi_scsi_ops = { + .transfer_data = vscsi_transfer_data, .complete = vscsi_command_complete, .cancel = vscsi_request_cancelled }; @@ -936,20 +892,14 @@ static int spapr_vscsi_init(VIOsPAPRDevice *dev) return 0; } -void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg, - qemu_irq qirq, uint32_t vio_irq_num) +void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg) { DeviceState *dev; - VIOsPAPRDevice *sdev; dev = qdev_create(&bus->bus, "spapr-vscsi"); qdev_prop_set_uint32(dev, "reg", reg); qdev_init_nofail(dev); - - sdev = (VIOsPAPRDevice *)dev; - sdev->qirq = qirq; - sdev->vio_irq_num = vio_irq_num; } static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off) @@ -979,9 +929,7 @@ static VIOsPAPRDeviceInfo spapr_vscsi = { .qdev.name = "spapr-vscsi", .qdev.size = sizeof(VSCSIState), .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x2000), - DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice, - rtce_window_size, 0x10000000), + DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev, 0x2000, 0x10000000), DEFINE_PROP_END_OF_LIST(), }, };