// Low-level usb command transmit function. int usb_process_op(struct disk_op_s *op) { if (!CONFIG_USB_MSC) return 0; dprintf(16, "usb_cmd_data id=%p write=%d count=%d buf=%p\n" , op->drive_fl, 0, op->count, op->buf_fl); struct usbdrive_s *udrive_gf = container_of( op->drive_fl, struct usbdrive_s, drive); // Setup command block wrapper. struct cbw_s cbw; memset(&cbw, 0, sizeof(cbw)); int blocksize = scsi_fill_cmd(op, cbw.CBWCB, USB_CDB_SIZE); if (blocksize < 0) return default_process_op(op); u32 bytes = blocksize * op->count; cbw.dCBWSignature = CBW_SIGNATURE; cbw.dCBWTag = 999; // XXX cbw.dCBWDataTransferLength = bytes; cbw.bmCBWFlags = scsi_is_read(op) ? USB_DIR_IN : USB_DIR_OUT; cbw.bCBWLUN = GET_GLOBALFLAT(udrive_gf->lun); cbw.bCBWCBLength = USB_CDB_SIZE; // Transfer cbw to device. int ret = usb_msc_send(udrive_gf, USB_DIR_OUT , MAKE_FLATPTR(GET_SEG(SS), &cbw), sizeof(cbw)); if (ret) goto fail; // Transfer data to/from device. if (bytes) { ret = usb_msc_send(udrive_gf, cbw.bmCBWFlags, op->buf_fl, bytes); if (ret) goto fail; } // Transfer csw info. struct csw_s csw; ret = usb_msc_send(udrive_gf, USB_DIR_IN , MAKE_FLATPTR(GET_SEG(SS), &csw), sizeof(csw)); if (ret) goto fail; if (!csw.bCSWStatus) return DISK_RET_SUCCESS; if (csw.bCSWStatus == 2) goto fail; if (blocksize) op->count -= csw.dCSWDataResidue / blocksize; return DISK_RET_EBADTRACK; fail: // XXX - reset connection dprintf(1, "USB transmission failed\n"); return DISK_RET_EBADTRACK; }
int pvscsi_process_op(struct disk_op_s *op) { if (!CONFIG_PVSCSI) return DISK_RET_EBADTRACK; struct pvscsi_lun_s *plun = container_of(op->drive_gf, struct pvscsi_lun_s, drive); struct pvscsi_ring_dsc_s *ring_dsc = plun->ring_dsc; struct PVSCSIRingsState *s = ring_dsc->ring_state; u32 req_entries = s->reqNumEntriesLog2; u32 cmp_entries = s->cmpNumEntriesLog2; struct PVSCSIRingReqDesc *req; struct PVSCSIRingCmpDesc *rsp; u32 status; if (s->reqProdIdx - s->cmpConsIdx >= 1 << req_entries) { dprintf(1, "pvscsi: ring full: reqProdIdx=%d cmpConsIdx=%d\n", s->reqProdIdx, s->cmpConsIdx); return DISK_RET_EBADTRACK; } req = ring_dsc->ring_reqs + (s->reqProdIdx & MASK(req_entries)); int blocksize = scsi_fill_cmd(op, req->cdb, 16); if (blocksize < 0) return default_process_op(op); req->bus = 0; req->target = plun->target; memset(req->lun, 0, sizeof(req->lun)); req->lun[1] = plun->lun; req->senseLen = 0; req->senseAddr = 0; req->cdbLen = 16; req->vcpuHint = 0; req->tag = SIMPLE_QUEUE_TAG; req->flags = scsi_is_read(op) ? PVSCSI_FLAG_CMD_DIR_TOHOST : PVSCSI_FLAG_CMD_DIR_TODEVICE; req->dataLen = op->count * blocksize; req->dataAddr = (u32)op->buf_fl; s->reqProdIdx = s->reqProdIdx + 1; pvscsi_kick_rw_io(plun->iobase); pvscsi_wait_intr_cmpl(plun->iobase); rsp = ring_dsc->ring_cmps + (s->cmpConsIdx & MASK(cmp_entries)); status = pvscsi_get_rsp(s, rsp); return status == 0 ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK; }