int active;
long data_len;
int writing;
- int sensing;
int senselen;
uint8_t sense[SCSI_SENSE_BUF_SIZE];
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);
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 */
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);
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)
}
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);
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));
}
if (done) {
- vscsi_put_req(s, req);
+ vscsi_put_req(req);
}
}
}
static const struct SCSIBusOps vscsi_scsi_ops = {
+ .transfer_data = vscsi_transfer_data,
.complete = vscsi_command_complete,
.cancel = vscsi_request_cancelled
};
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)
.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(),
},
};