union viosrp_iu iu;
/* SCSI request tracking */
- SCSIDevice *sdev;
SCSIRequest *sreq;
uint32_t qtag; /* qemu tag != srp tag */
int lun;
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 */
static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
{
- SCSIDevice *sdev = req->sdev;
uint8_t *cdb = req->iu.srp.cmd.cdb;
int n;
+ n = scsi_req_get_sense(req->sreq, req->sense, sizeof(req->sense));
+ if (n) {
+ req->senselen = n;
+ vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+ vscsi_put_req(req);
+ return;
+ }
+
+ dprintf("VSCSI: Got CHECK_CONDITION, requesting sense...\n");
cdb[0] = 3;
cdb[1] = 0;
cdb[2] = 0;
cdb[4] = 96;
cdb[5] = 0;
req->sensing = 1;
- n = sdev->info->send_command(req->sreq, cdb);
+ 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");
} else if (n == 0) {
return;
}
- sdev->info->read_data(req->sreq);
+ 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);
- SCSIDevice *sdev;
+ 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;
}
- sdev = req->sdev;
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 = sdev->info->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;
- sdev->info->read_data(sreq);
- }
+ uint8_t *buf = scsi_req_get_buf(sreq);
+
+ len = MIN(len, 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) {
- buf = sdev->info->get_buf(sreq);
- rc = vscsi_srp_transfer_data(s, req, req->writing, buf, arg);
+ if (len) {
+ buf = scsi_req_get_buf(sreq);
+ rc = vscsi_srp_transfer_data(s, req, req->writing, buf, len);
}
if (rc < 0) {
fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc);
/* Start next chunk */
req->data_len -= rc;
- if (req->writing) {
- sdev->info->write_data(sreq);
+ scsi_req_continue(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 = 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;
+ }
+
+ if (!req->sensing && status == CHECK_CONDITION) {
+ vscsi_send_request_sense(s, req);
+ return;
+ }
+
+ if (req->sensing) {
+ dprintf("VSCSI: Sense done !\n");
+ status = CHECK_CONDITION;
} else {
- sdev->info->read_data(sreq);
+ 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, 0, 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)
} return 1;
}
- req->sdev = sdev;
req->lun = lun;
- req->sreq = sdev->info->alloc_req(sdev, req->qtag, lun);
- n = sdev->info->send_command(req->sreq, srp->cmd.cdb);
+ req->sreq = scsi_req_new(sdev, req->qtag, lun, req);
+ n = scsi_req_enqueue(req->sreq, srp->cmd.cdb);
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);
/* Preprocess RDMA descriptors */
vscsi_preprocess_desc(req);
- }
- /* Get transfer direction and initiate transfer */
- if (n > 0) {
- req->data_len = n;
- sdev->info->read_data(req->sreq);
- } else if (n < 0) {
- req->data_len = -n;
- sdev->info->write_data(req->sreq);
+ /* Get transfer direction and initiate transfer */
+ if (n > 0) {
+ req->data_len = n;
+ } else if (n < 0) {
+ req->data_len = -n;
+ }
+ scsi_req_continue(req->sreq);
}
/* Don't touch req here, it may have been recycled already */
}
if (done) {
- vscsi_put_req(s, req);
+ vscsi_put_req(req);
}
}
}
static const struct SCSIBusOps vscsi_scsi_ops = {
- .complete = vscsi_command_complete
+ .transfer_data = vscsi_transfer_data,
+ .complete = vscsi_command_complete,
+ .cancel = vscsi_request_cancelled
};
static int spapr_vscsi_init(VIOsPAPRDevice *dev)