qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

spapr-vscsi: add task management

At the moment the guest kernel issues two types of task management
requests to the hypervisor - task about and lun reset. This adds
handling for these tasks. As spapr-vscsi starts calling scsi_req_cancel(),
free_request callback was implemented.

As virtio-vscsi, spapr-vscsi does not handle CLEAR_ACA either as CDB
control byte does not seem to be used at all so NACA bit is not
set to the guest so the guest has no good reason to call CLEAR_ACA task.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
[Fix choice of UCSOLCNT vs. SCSOLCNT. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Alexey Kardashevskiy and committed by
Paolo Bonzini
eb37f146 5accc840

+99 -27
+92 -27
hw/scsi/spapr_vscsi.c
··· 117 117 return NULL; 118 118 } 119 119 120 + static struct vscsi_req *vscsi_find_req(VSCSIState *s, uint64_t srp_tag) 121 + { 122 + vscsi_req *req; 123 + int i; 124 + 125 + for (i = 0; i < VSCSI_REQ_LIMIT; i++) { 126 + req = &s->reqs[i]; 127 + if (req->iu.srp.cmd.tag == srp_tag) { 128 + return req; 129 + } 130 + } 131 + return NULL; 132 + } 133 + 120 134 static void vscsi_put_req(vscsi_req *req) 121 135 { 122 136 if (req->sreq != NULL) { ··· 755 769 static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req) 756 770 { 757 771 union viosrp_iu *iu = &req->iu; 758 - int fn; 772 + vscsi_req *tmpreq; 773 + int i, lun = 0, resp = SRP_TSK_MGMT_COMPLETE; 774 + SCSIDevice *d; 775 + uint64_t tag = iu->srp.rsp.tag; 776 + uint8_t sol_not = iu->srp.cmd.sol_not; 759 777 760 778 fprintf(stderr, "vscsi_process_tsk_mgmt %02x\n", 761 779 iu->srp.tsk_mgmt.tsk_mgmt_func); 762 780 763 - switch (iu->srp.tsk_mgmt.tsk_mgmt_func) { 764 - #if 0 /* We really don't deal with these for now */ 765 - case SRP_TSK_ABORT_TASK: 766 - fn = ABORT_TASK; 767 - break; 768 - case SRP_TSK_ABORT_TASK_SET: 769 - fn = ABORT_TASK_SET; 770 - break; 771 - case SRP_TSK_CLEAR_TASK_SET: 772 - fn = CLEAR_TASK_SET; 773 - break; 774 - case SRP_TSK_LUN_RESET: 775 - fn = LOGICAL_UNIT_RESET; 776 - break; 777 - case SRP_TSK_CLEAR_ACA: 778 - fn = CLEAR_ACA; 779 - break; 780 - #endif 781 - default: 782 - fn = 0; 781 + d = vscsi_device_find(&s->bus, be64_to_cpu(req->iu.srp.tsk_mgmt.lun), &lun); 782 + if (!d) { 783 + resp = SRP_TSK_MGMT_FIELDS_INVALID; 784 + } else { 785 + switch (iu->srp.tsk_mgmt.tsk_mgmt_func) { 786 + case SRP_TSK_ABORT_TASK: 787 + if (d->lun != lun) { 788 + resp = SRP_TSK_MGMT_FIELDS_INVALID; 789 + break; 790 + } 791 + 792 + tmpreq = vscsi_find_req(s, req->iu.srp.tsk_mgmt.task_tag); 793 + if (tmpreq && tmpreq->sreq) { 794 + assert(tmpreq->sreq->hba_private); 795 + scsi_req_cancel(tmpreq->sreq); 796 + } 797 + break; 798 + 799 + case SRP_TSK_LUN_RESET: 800 + if (d->lun != lun) { 801 + resp = SRP_TSK_MGMT_FIELDS_INVALID; 802 + break; 803 + } 804 + 805 + qdev_reset_all(&d->qdev); 806 + break; 807 + 808 + case SRP_TSK_ABORT_TASK_SET: 809 + case SRP_TSK_CLEAR_TASK_SET: 810 + if (d->lun != lun) { 811 + resp = SRP_TSK_MGMT_FIELDS_INVALID; 812 + break; 813 + } 814 + 815 + for (i = 0; i < VSCSI_REQ_LIMIT; i++) { 816 + tmpreq = &s->reqs[i]; 817 + if (tmpreq->iu.srp.cmd.lun != req->iu.srp.tsk_mgmt.lun) { 818 + continue; 819 + } 820 + if (!tmpreq->active || !tmpreq->sreq) { 821 + continue; 822 + } 823 + assert(tmpreq->sreq->hba_private); 824 + scsi_req_cancel(tmpreq->sreq); 825 + } 826 + break; 827 + 828 + case SRP_TSK_CLEAR_ACA: 829 + resp = SRP_TSK_MGMT_NOT_SUPPORTED; 830 + break; 831 + 832 + default: 833 + resp = SRP_TSK_MGMT_FIELDS_INVALID; 834 + break; 835 + } 783 836 } 784 - if (fn) { 785 - /* XXX Send/Handle target task management */ 786 - ; 837 + 838 + /* Compose the response here as */ 839 + memset(iu, 0, sizeof(struct srp_rsp) + 4); 840 + iu->srp.rsp.opcode = SRP_RSP; 841 + iu->srp.rsp.req_lim_delta = cpu_to_be32(1); 842 + iu->srp.rsp.tag = tag; 843 + iu->srp.rsp.flags |= SRP_RSP_FLAG_RSPVALID; 844 + iu->srp.rsp.resp_data_len = cpu_to_be32(4); 845 + if (resp) { 846 + iu->srp.rsp.sol_not = (sol_not & 0x04) >> 2; 787 847 } else { 788 - vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x20, 0); 789 - vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); 848 + iu->srp.rsp.sol_not = (sol_not & 0x02) >> 1; 790 849 } 791 - return !fn; 850 + 851 + iu->srp.rsp.status = GOOD; 852 + iu->srp.rsp.data[3] = resp; 853 + 854 + vscsi_send_iu(s, req, sizeof(iu->srp.rsp) + 4, VIOSRP_SRP_FORMAT); 855 + 856 + return 1; 792 857 } 793 858 794 859 static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req)
+7
hw/scsi/srp.h
··· 90 90 SRP_REV16A_IB_IO_CLASS = 0x0100 91 91 }; 92 92 93 + enum { 94 + SRP_TSK_MGMT_COMPLETE = 0x00, 95 + SRP_TSK_MGMT_FIELDS_INVALID = 0x02, 96 + SRP_TSK_MGMT_NOT_SUPPORTED = 0x04, 97 + SRP_TSK_MGMT_FAILED = 0x05 98 + }; 99 + 93 100 struct srp_direct_buf { 94 101 uint64_t va; 95 102 uint32_t key;