xref: /openbmc/qemu/hw/scsi/spapr_vscsi.c (revision d328fef93ae757a0dd65ed786a4086e27952eef3)
153a55002SPaolo Bonzini /*
253a55002SPaolo Bonzini  * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
353a55002SPaolo Bonzini  *
453a55002SPaolo Bonzini  * PAPR Virtual SCSI, aka ibmvscsi
553a55002SPaolo Bonzini  *
653a55002SPaolo Bonzini  * Copyright (c) 2010,2011 Benjamin Herrenschmidt, IBM Corporation.
753a55002SPaolo Bonzini  *
853a55002SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
953a55002SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
1053a55002SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
1153a55002SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1253a55002SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1353a55002SPaolo Bonzini  * furnished to do so, subject to the following conditions:
1453a55002SPaolo Bonzini  *
1553a55002SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1653a55002SPaolo Bonzini  * all copies or substantial portions of the Software.
1753a55002SPaolo Bonzini  *
1853a55002SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1953a55002SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2053a55002SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2153a55002SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2253a55002SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2353a55002SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2453a55002SPaolo Bonzini  * THE SOFTWARE.
2553a55002SPaolo Bonzini  *
2653a55002SPaolo Bonzini  * TODO:
2753a55002SPaolo Bonzini  *
2853a55002SPaolo Bonzini  *  - Cleanups :-)
2953a55002SPaolo Bonzini  *  - Sort out better how to assign devices to VSCSI instances
3053a55002SPaolo Bonzini  *  - Fix residual counts
3153a55002SPaolo Bonzini  *  - Add indirect descriptors support
3253a55002SPaolo Bonzini  *  - Maybe do autosense (PAPR seems to mandate it, linux doesn't care)
3353a55002SPaolo Bonzini  */
340b8fa32fSMarkus Armbruster 
350d75590dSPeter Maydell #include "qemu/osdep.h"
360b8fa32fSMarkus Armbruster #include "qemu/module.h"
3753a55002SPaolo Bonzini #include "hw/scsi/scsi.h"
38d6454270SMarkus Armbruster #include "migration/vmstate.h"
3908e2c9f1SPaolo Bonzini #include "scsi/constants.h"
4047b43a1fSPaolo Bonzini #include "srp.h"
4153a55002SPaolo Bonzini #include "hw/ppc/spapr.h"
4253a55002SPaolo Bonzini #include "hw/ppc/spapr_vio.h"
43a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
4447b43a1fSPaolo Bonzini #include "viosrp.h"
45f19661c8SLaurent Vivier #include "trace.h"
4653a55002SPaolo Bonzini 
4753a55002SPaolo Bonzini #include <libfdt.h>
48db1015e9SEduardo Habkost #include "qom/object.h"
4953a55002SPaolo Bonzini 
5053a55002SPaolo Bonzini /*
5153a55002SPaolo Bonzini  * Virtual SCSI device
5253a55002SPaolo Bonzini  */
5353a55002SPaolo Bonzini 
5453a55002SPaolo Bonzini /* Random numbers */
5553a55002SPaolo Bonzini #define VSCSI_MAX_SECTORS       4096
5653a55002SPaolo Bonzini #define VSCSI_REQ_LIMIT         24
5753a55002SPaolo Bonzini 
5813a54905SPhilippe Mathieu-Daudé /* Maximum size of a IU payload */
5913a54905SPhilippe Mathieu-Daudé #define SRP_MAX_IU_DATA_LEN     (SRP_MAX_IU_LEN - sizeof(union srp_iu))
6053a55002SPaolo Bonzini #define SRP_RSP_SENSE_DATA_LEN  18
6153a55002SPaolo Bonzini 
623052f0d5SNathan Whitehorn #define SRP_REPORT_LUNS_WLUN    0xc10100000000000ULL
633052f0d5SNathan Whitehorn 
6453a55002SPaolo Bonzini typedef union vscsi_crq {
6553a55002SPaolo Bonzini     struct viosrp_crq s;
6653a55002SPaolo Bonzini     uint8_t raw[16];
6753a55002SPaolo Bonzini } vscsi_crq;
6853a55002SPaolo Bonzini 
6953a55002SPaolo Bonzini typedef struct vscsi_req {
7053a55002SPaolo Bonzini     vscsi_crq               crq;
71ff78b728SPhilippe Mathieu-Daudé     uint8_t                 viosrp_iu_buf[SRP_MAX_IU_LEN];
7253a55002SPaolo Bonzini 
7353a55002SPaolo Bonzini     /* SCSI request tracking */
7453a55002SPaolo Bonzini     SCSIRequest             *sreq;
7553a55002SPaolo Bonzini     uint32_t                qtag; /* qemu tag != srp tag */
768ca8a17cSAlexey Kardashevskiy     bool                    active;
778ca8a17cSAlexey Kardashevskiy     bool                    writing;
78eda470e4SFam Zheng     bool                    dma_error;
79eda470e4SFam Zheng     uint32_t                data_len;
808ca8a17cSAlexey Kardashevskiy     uint32_t                senselen;
8153a55002SPaolo Bonzini     uint8_t                 sense[SCSI_SENSE_BUF_SIZE];
8253a55002SPaolo Bonzini 
8353a55002SPaolo Bonzini     /* RDMA related bits */
8453a55002SPaolo Bonzini     uint8_t                 dma_fmt;
858ca8a17cSAlexey Kardashevskiy     uint16_t                local_desc;
868ca8a17cSAlexey Kardashevskiy     uint16_t                total_desc;
878ca8a17cSAlexey Kardashevskiy     uint16_t                cdb_offset;
888ca8a17cSAlexey Kardashevskiy     uint16_t                cur_desc_num;
898ca8a17cSAlexey Kardashevskiy     uint16_t                cur_desc_offset;
9053a55002SPaolo Bonzini } vscsi_req;
9153a55002SPaolo Bonzini 
92fd506b4fSDavid Gibson #define TYPE_VIO_SPAPR_VSCSI_DEVICE "spapr-vscsi"
938063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(VSCSIState, VIO_SPAPR_VSCSI_DEVICE)
9453a55002SPaolo Bonzini 
95db1015e9SEduardo Habkost struct VSCSIState {
96ce2918cbSDavid Gibson     SpaprVioDevice vdev;
9753a55002SPaolo Bonzini     SCSIBus bus;
9853a55002SPaolo Bonzini     vscsi_req reqs[VSCSI_REQ_LIMIT];
99db1015e9SEduardo Habkost };
10053a55002SPaolo Bonzini 
req_iu(vscsi_req * req)10181e70549SPhilippe Mathieu-Daudé static union viosrp_iu *req_iu(vscsi_req *req)
10281e70549SPhilippe Mathieu-Daudé {
103ff78b728SPhilippe Mathieu-Daudé     return (union viosrp_iu *)req->viosrp_iu_buf;
10481e70549SPhilippe Mathieu-Daudé }
10581e70549SPhilippe Mathieu-Daudé 
vscsi_get_req(VSCSIState * s)10653a55002SPaolo Bonzini static struct vscsi_req *vscsi_get_req(VSCSIState *s)
10753a55002SPaolo Bonzini {
10853a55002SPaolo Bonzini     vscsi_req *req;
10953a55002SPaolo Bonzini     int i;
11053a55002SPaolo Bonzini 
11153a55002SPaolo Bonzini     for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
11253a55002SPaolo Bonzini         req = &s->reqs[i];
11353a55002SPaolo Bonzini         if (!req->active) {
11453a55002SPaolo Bonzini             memset(req, 0, sizeof(*req));
11553a55002SPaolo Bonzini             req->qtag = i;
11653a55002SPaolo Bonzini             req->active = 1;
11753a55002SPaolo Bonzini             return req;
11853a55002SPaolo Bonzini         }
11953a55002SPaolo Bonzini     }
12053a55002SPaolo Bonzini     return NULL;
12153a55002SPaolo Bonzini }
12253a55002SPaolo Bonzini 
vscsi_find_req(VSCSIState * s,uint64_t srp_tag)123eb37f146SAlexey Kardashevskiy static struct vscsi_req *vscsi_find_req(VSCSIState *s, uint64_t srp_tag)
124eb37f146SAlexey Kardashevskiy {
125eb37f146SAlexey Kardashevskiy     vscsi_req *req;
126eb37f146SAlexey Kardashevskiy     int i;
127eb37f146SAlexey Kardashevskiy 
128eb37f146SAlexey Kardashevskiy     for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
129eb37f146SAlexey Kardashevskiy         req = &s->reqs[i];
13081e70549SPhilippe Mathieu-Daudé         if (req_iu(req)->srp.cmd.tag == srp_tag) {
131eb37f146SAlexey Kardashevskiy             return req;
132eb37f146SAlexey Kardashevskiy         }
133eb37f146SAlexey Kardashevskiy     }
134eb37f146SAlexey Kardashevskiy     return NULL;
135eb37f146SAlexey Kardashevskiy }
136eb37f146SAlexey Kardashevskiy 
vscsi_put_req(vscsi_req * req)13753a55002SPaolo Bonzini static void vscsi_put_req(vscsi_req *req)
13853a55002SPaolo Bonzini {
13953a55002SPaolo Bonzini     if (req->sreq != NULL) {
14053a55002SPaolo Bonzini         scsi_req_unref(req->sreq);
14153a55002SPaolo Bonzini     }
14253a55002SPaolo Bonzini     req->sreq = NULL;
14353a55002SPaolo Bonzini     req->active = 0;
14453a55002SPaolo Bonzini }
14553a55002SPaolo Bonzini 
vscsi_device_find(SCSIBus * bus,uint64_t srp_lun,int * lun)14653a55002SPaolo Bonzini static SCSIDevice *vscsi_device_find(SCSIBus *bus, uint64_t srp_lun, int *lun)
14753a55002SPaolo Bonzini {
14853a55002SPaolo Bonzini     int channel = 0, id = 0;
14953a55002SPaolo Bonzini 
15053a55002SPaolo Bonzini retry:
15153a55002SPaolo Bonzini     switch (srp_lun >> 62) {
15253a55002SPaolo Bonzini     case 0:
15353a55002SPaolo Bonzini         if ((srp_lun >> 56) != 0) {
15453a55002SPaolo Bonzini             channel = (srp_lun >> 56) & 0x3f;
15553a55002SPaolo Bonzini             id = (srp_lun >> 48) & 0xff;
15653a55002SPaolo Bonzini             srp_lun <<= 16;
15753a55002SPaolo Bonzini             goto retry;
15853a55002SPaolo Bonzini         }
15953a55002SPaolo Bonzini         *lun = (srp_lun >> 48) & 0xff;
16053a55002SPaolo Bonzini         break;
16153a55002SPaolo Bonzini 
16253a55002SPaolo Bonzini     case 1:
16353a55002SPaolo Bonzini         *lun = (srp_lun >> 48) & 0x3fff;
16453a55002SPaolo Bonzini         break;
16553a55002SPaolo Bonzini     case 2:
16653a55002SPaolo Bonzini         channel = (srp_lun >> 53) & 0x7;
16753a55002SPaolo Bonzini         id = (srp_lun >> 56) & 0x3f;
16853a55002SPaolo Bonzini         *lun = (srp_lun >> 48) & 0x1f;
16953a55002SPaolo Bonzini         break;
17053a55002SPaolo Bonzini     case 3:
17153a55002SPaolo Bonzini         *lun = -1;
17253a55002SPaolo Bonzini         return NULL;
17353a55002SPaolo Bonzini     default:
17453a55002SPaolo Bonzini         abort();
17553a55002SPaolo Bonzini     }
17653a55002SPaolo Bonzini 
17753a55002SPaolo Bonzini     return scsi_device_find(bus, channel, id, *lun);
17853a55002SPaolo Bonzini }
17953a55002SPaolo Bonzini 
vscsi_send_iu(VSCSIState * s,vscsi_req * req,uint64_t length,uint8_t format)18053a55002SPaolo Bonzini static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
18153a55002SPaolo Bonzini                          uint64_t length, uint8_t format)
18253a55002SPaolo Bonzini {
18353a55002SPaolo Bonzini     long rc, rc1;
18453a55002SPaolo Bonzini 
18513a54905SPhilippe Mathieu-Daudé     assert(length <= SRP_MAX_IU_LEN);
18613a54905SPhilippe Mathieu-Daudé 
18753a55002SPaolo Bonzini     /* First copy the SRP */
18853a55002SPaolo Bonzini     rc = spapr_vio_dma_write(&s->vdev, req->crq.s.IU_data_ptr,
189ff78b728SPhilippe Mathieu-Daudé                              &req->viosrp_iu_buf, length);
19053a55002SPaolo Bonzini     if (rc) {
19153a55002SPaolo Bonzini         fprintf(stderr, "vscsi_send_iu: DMA write failure !\n");
19253a55002SPaolo Bonzini     }
19353a55002SPaolo Bonzini 
19453a55002SPaolo Bonzini     req->crq.s.valid = 0x80;
19553a55002SPaolo Bonzini     req->crq.s.format = format;
19653a55002SPaolo Bonzini     req->crq.s.reserved = 0x00;
19753a55002SPaolo Bonzini     req->crq.s.timeout = cpu_to_be16(0x0000);
19853a55002SPaolo Bonzini     req->crq.s.IU_length = cpu_to_be16(length);
19981e70549SPhilippe Mathieu-Daudé     req->crq.s.IU_data_ptr = req_iu(req)->srp.rsp.tag; /* right byte order */
20053a55002SPaolo Bonzini 
20153a55002SPaolo Bonzini     if (rc == 0) {
20222956a37SAlexey Kardashevskiy         req->crq.s.status = VIOSRP_OK;
20353a55002SPaolo Bonzini     } else {
20422956a37SAlexey Kardashevskiy         req->crq.s.status = VIOSRP_ADAPTER_FAIL;
20553a55002SPaolo Bonzini     }
20653a55002SPaolo Bonzini 
20753a55002SPaolo Bonzini     rc1 = spapr_vio_send_crq(&s->vdev, req->crq.raw);
20853a55002SPaolo Bonzini     if (rc1) {
20953a55002SPaolo Bonzini         fprintf(stderr, "vscsi_send_iu: Error sending response\n");
21053a55002SPaolo Bonzini         return rc1;
21153a55002SPaolo Bonzini     }
21253a55002SPaolo Bonzini 
21353a55002SPaolo Bonzini     return rc;
21453a55002SPaolo Bonzini }
21553a55002SPaolo Bonzini 
vscsi_makeup_sense(VSCSIState * s,vscsi_req * req,uint8_t key,uint8_t asc,uint8_t ascq)21653a55002SPaolo Bonzini static void vscsi_makeup_sense(VSCSIState *s, vscsi_req *req,
21753a55002SPaolo Bonzini                                uint8_t key, uint8_t asc, uint8_t ascq)
21853a55002SPaolo Bonzini {
21953a55002SPaolo Bonzini     req->senselen = SRP_RSP_SENSE_DATA_LEN;
22053a55002SPaolo Bonzini 
22153a55002SPaolo Bonzini     /* Valid bit and 'current errors' */
22253a55002SPaolo Bonzini     req->sense[0] = (0x1 << 7 | 0x70);
22353a55002SPaolo Bonzini     /* Sense key */
22453a55002SPaolo Bonzini     req->sense[2] = key;
22553a55002SPaolo Bonzini     /* Additional sense length */
22653a55002SPaolo Bonzini     req->sense[7] = 0xa; /* 10 bytes */
22753a55002SPaolo Bonzini     /* Additional sense code */
22853a55002SPaolo Bonzini     req->sense[12] = asc;
22953a55002SPaolo Bonzini     req->sense[13] = ascq;
23053a55002SPaolo Bonzini }
23153a55002SPaolo Bonzini 
vscsi_send_rsp(VSCSIState * s,vscsi_req * req,uint8_t status,int32_t res_in,int32_t res_out)23253a55002SPaolo Bonzini static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req,
23353a55002SPaolo Bonzini                           uint8_t status, int32_t res_in, int32_t res_out)
23453a55002SPaolo Bonzini {
23581e70549SPhilippe Mathieu-Daudé     union viosrp_iu *iu = req_iu(req);
23653a55002SPaolo Bonzini     uint64_t tag = iu->srp.rsp.tag;
23753a55002SPaolo Bonzini     int total_len = sizeof(iu->srp.rsp);
238dbd94f8eSAlexey Kardashevskiy     uint8_t sol_not = iu->srp.cmd.sol_not;
23953a55002SPaolo Bonzini 
240f19661c8SLaurent Vivier     trace_spapr_vscsi_send_rsp(status, res_in, res_out);
24153a55002SPaolo Bonzini 
24253a55002SPaolo Bonzini     memset(iu, 0, sizeof(struct srp_rsp));
24353a55002SPaolo Bonzini     iu->srp.rsp.opcode = SRP_RSP;
24453a55002SPaolo Bonzini     iu->srp.rsp.req_lim_delta = cpu_to_be32(1);
24553a55002SPaolo Bonzini     iu->srp.rsp.tag = tag;
24653a55002SPaolo Bonzini 
24753a55002SPaolo Bonzini     /* Handle residuals */
24853a55002SPaolo Bonzini     if (res_in < 0) {
24953a55002SPaolo Bonzini         iu->srp.rsp.flags |= SRP_RSP_FLAG_DIUNDER;
25053a55002SPaolo Bonzini         res_in = -res_in;
25153a55002SPaolo Bonzini     } else if (res_in) {
25253a55002SPaolo Bonzini         iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER;
25353a55002SPaolo Bonzini     }
25453a55002SPaolo Bonzini     if (res_out < 0) {
25553a55002SPaolo Bonzini         iu->srp.rsp.flags |= SRP_RSP_FLAG_DOUNDER;
25653a55002SPaolo Bonzini         res_out = -res_out;
25753a55002SPaolo Bonzini     } else if (res_out) {
25853a55002SPaolo Bonzini         iu->srp.rsp.flags |= SRP_RSP_FLAG_DOOVER;
25953a55002SPaolo Bonzini     }
26053a55002SPaolo Bonzini     iu->srp.rsp.data_in_res_cnt = cpu_to_be32(res_in);
26153a55002SPaolo Bonzini     iu->srp.rsp.data_out_res_cnt = cpu_to_be32(res_out);
26253a55002SPaolo Bonzini 
26353a55002SPaolo Bonzini     /* We don't do response data */
26453a55002SPaolo Bonzini     /* iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID; */
26553a55002SPaolo Bonzini     iu->srp.rsp.resp_data_len = cpu_to_be32(0);
26653a55002SPaolo Bonzini 
26753a55002SPaolo Bonzini     /* Handle success vs. failure */
26853a55002SPaolo Bonzini     iu->srp.rsp.status = status;
26953a55002SPaolo Bonzini     if (status) {
270dbd94f8eSAlexey Kardashevskiy         iu->srp.rsp.sol_not = (sol_not & 0x04) >> 2;
27153a55002SPaolo Bonzini         if (req->senselen) {
27213a54905SPhilippe Mathieu-Daudé             int sense_data_len = MIN(req->senselen, SRP_MAX_IU_DATA_LEN);
27313a54905SPhilippe Mathieu-Daudé 
27406109ab3SPhilippe Mathieu-Daudé             iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
27513a54905SPhilippe Mathieu-Daudé             iu->srp.rsp.sense_data_len = cpu_to_be32(sense_data_len);
27613a54905SPhilippe Mathieu-Daudé             memcpy(iu->srp.rsp.data, req->sense, sense_data_len);
27713a54905SPhilippe Mathieu-Daudé             total_len += sense_data_len;
27853a55002SPaolo Bonzini         }
27953a55002SPaolo Bonzini     } else {
280dbd94f8eSAlexey Kardashevskiy         iu->srp.rsp.sol_not = (sol_not & 0x02) >> 1;
28153a55002SPaolo Bonzini     }
28253a55002SPaolo Bonzini 
28353a55002SPaolo Bonzini     vscsi_send_iu(s, req, total_len, VIOSRP_SRP_FORMAT);
28453a55002SPaolo Bonzini     return 0;
28553a55002SPaolo Bonzini }
28653a55002SPaolo Bonzini 
vscsi_swap_desc(struct srp_direct_buf desc)2878ca8a17cSAlexey Kardashevskiy static inline struct srp_direct_buf vscsi_swap_desc(struct srp_direct_buf desc)
28853a55002SPaolo Bonzini {
2898ca8a17cSAlexey Kardashevskiy     desc.va = be64_to_cpu(desc.va);
2908ca8a17cSAlexey Kardashevskiy     desc.len = be32_to_cpu(desc.len);
2918ca8a17cSAlexey Kardashevskiy     return desc;
2928ca8a17cSAlexey Kardashevskiy }
2938ca8a17cSAlexey Kardashevskiy 
vscsi_fetch_desc(VSCSIState * s,struct vscsi_req * req,unsigned n,unsigned buf_offset,struct srp_direct_buf * ret)2948ca8a17cSAlexey Kardashevskiy static int vscsi_fetch_desc(VSCSIState *s, struct vscsi_req *req,
2958ca8a17cSAlexey Kardashevskiy                             unsigned n, unsigned buf_offset,
2968ca8a17cSAlexey Kardashevskiy                             struct srp_direct_buf *ret)
2978ca8a17cSAlexey Kardashevskiy {
29881e70549SPhilippe Mathieu-Daudé     struct srp_cmd *cmd = &req_iu(req)->srp.cmd;
2998ca8a17cSAlexey Kardashevskiy 
3008ca8a17cSAlexey Kardashevskiy     switch (req->dma_fmt) {
3018ca8a17cSAlexey Kardashevskiy     case SRP_NO_DATA_DESC: {
302f19661c8SLaurent Vivier         trace_spapr_vscsi_fetch_desc_no_data();
3038ca8a17cSAlexey Kardashevskiy         return 0;
3048ca8a17cSAlexey Kardashevskiy     }
3058ca8a17cSAlexey Kardashevskiy     case SRP_DATA_DESC_DIRECT: {
3068ca8a17cSAlexey Kardashevskiy         memcpy(ret, cmd->add_data + req->cdb_offset, sizeof(*ret));
3078ca8a17cSAlexey Kardashevskiy         assert(req->cur_desc_num == 0);
308f19661c8SLaurent Vivier         trace_spapr_vscsi_fetch_desc_direct();
3098ca8a17cSAlexey Kardashevskiy         break;
3108ca8a17cSAlexey Kardashevskiy     }
3118ca8a17cSAlexey Kardashevskiy     case SRP_DATA_DESC_INDIRECT: {
3128ca8a17cSAlexey Kardashevskiy         struct srp_indirect_buf *tmp = (struct srp_indirect_buf *)
3138ca8a17cSAlexey Kardashevskiy                                        (cmd->add_data + req->cdb_offset);
3148ca8a17cSAlexey Kardashevskiy         if (n < req->local_desc) {
3158ca8a17cSAlexey Kardashevskiy             *ret = tmp->desc_list[n];
316f19661c8SLaurent Vivier             trace_spapr_vscsi_fetch_desc_indirect(req->qtag, n,
317f19661c8SLaurent Vivier                                                   req->local_desc);
3188ca8a17cSAlexey Kardashevskiy         } else if (n < req->total_desc) {
3198ca8a17cSAlexey Kardashevskiy             int rc;
3208ca8a17cSAlexey Kardashevskiy             struct srp_direct_buf tbl_desc = vscsi_swap_desc(tmp->table_desc);
3218ca8a17cSAlexey Kardashevskiy             unsigned desc_offset = n * sizeof(struct srp_direct_buf);
3228ca8a17cSAlexey Kardashevskiy 
3238ca8a17cSAlexey Kardashevskiy             if (desc_offset >= tbl_desc.len) {
324f19661c8SLaurent Vivier                 trace_spapr_vscsi_fetch_desc_out_of_range(n, desc_offset);
3258ca8a17cSAlexey Kardashevskiy                 return -1;
3268ca8a17cSAlexey Kardashevskiy             }
3278ca8a17cSAlexey Kardashevskiy             rc = spapr_vio_dma_read(&s->vdev, tbl_desc.va + desc_offset,
3288ca8a17cSAlexey Kardashevskiy                                     ret, sizeof(struct srp_direct_buf));
3298ca8a17cSAlexey Kardashevskiy             if (rc) {
330f19661c8SLaurent Vivier                 trace_spapr_vscsi_fetch_desc_dma_read_error(rc);
3318ca8a17cSAlexey Kardashevskiy                 return -1;
3328ca8a17cSAlexey Kardashevskiy             }
333f19661c8SLaurent Vivier             trace_spapr_vscsi_fetch_desc_indirect_seg_ext(req->qtag, n,
334f19661c8SLaurent Vivier                                                           req->total_desc,
335f19661c8SLaurent Vivier                                                           tbl_desc.va,
336f19661c8SLaurent Vivier                                                           tbl_desc.len);
3378ca8a17cSAlexey Kardashevskiy         } else {
338f19661c8SLaurent Vivier             trace_spapr_vscsi_fetch_desc_out_of_desc();
3398ca8a17cSAlexey Kardashevskiy             return 0;
3408ca8a17cSAlexey Kardashevskiy         }
3418ca8a17cSAlexey Kardashevskiy         break;
3428ca8a17cSAlexey Kardashevskiy     }
3438ca8a17cSAlexey Kardashevskiy     default:
3448ca8a17cSAlexey Kardashevskiy         fprintf(stderr, "VSCSI:   Unknown format %x\n", req->dma_fmt);
3458ca8a17cSAlexey Kardashevskiy         return -1;
3468ca8a17cSAlexey Kardashevskiy     }
3478ca8a17cSAlexey Kardashevskiy 
3488ca8a17cSAlexey Kardashevskiy     *ret = vscsi_swap_desc(*ret);
3498ca8a17cSAlexey Kardashevskiy     if (buf_offset > ret->len) {
350f19661c8SLaurent Vivier         trace_spapr_vscsi_fetch_desc_out_of_desc_boundary(buf_offset,
351f19661c8SLaurent Vivier                                                           req->cur_desc_num,
352f19661c8SLaurent Vivier                                                           ret->len);
3538ca8a17cSAlexey Kardashevskiy         return -1;
3548ca8a17cSAlexey Kardashevskiy     }
3558ca8a17cSAlexey Kardashevskiy     ret->va += buf_offset;
3568ca8a17cSAlexey Kardashevskiy     ret->len -= buf_offset;
3578ca8a17cSAlexey Kardashevskiy 
358f19661c8SLaurent Vivier     trace_spapr_vscsi_fetch_desc_done(req->cur_desc_num, req->cur_desc_offset,
359f19661c8SLaurent Vivier                                       ret->va, ret->len);
3608ca8a17cSAlexey Kardashevskiy 
3618ca8a17cSAlexey Kardashevskiy     return ret->len ? 1 : 0;
36253a55002SPaolo Bonzini }
36353a55002SPaolo Bonzini 
vscsi_srp_direct_data(VSCSIState * s,vscsi_req * req,uint8_t * buf,uint32_t len)36453a55002SPaolo Bonzini static int vscsi_srp_direct_data(VSCSIState *s, vscsi_req *req,
36553a55002SPaolo Bonzini                                  uint8_t *buf, uint32_t len)
36653a55002SPaolo Bonzini {
3678ca8a17cSAlexey Kardashevskiy     struct srp_direct_buf md;
36853a55002SPaolo Bonzini     uint32_t llen;
36953a55002SPaolo Bonzini     int rc = 0;
37053a55002SPaolo Bonzini 
3718ca8a17cSAlexey Kardashevskiy     rc = vscsi_fetch_desc(s, req, req->cur_desc_num, req->cur_desc_offset, &md);
3728ca8a17cSAlexey Kardashevskiy     if (rc < 0) {
3738ca8a17cSAlexey Kardashevskiy         return -1;
3748ca8a17cSAlexey Kardashevskiy     } else if (rc == 0) {
3758ca8a17cSAlexey Kardashevskiy         return 0;
3768ca8a17cSAlexey Kardashevskiy     }
37753a55002SPaolo Bonzini 
3788ca8a17cSAlexey Kardashevskiy     llen = MIN(len, md.len);
37953a55002SPaolo Bonzini     if (llen) {
38053a55002SPaolo Bonzini         if (req->writing) { /* writing = to device = reading from memory */
3818ca8a17cSAlexey Kardashevskiy             rc = spapr_vio_dma_read(&s->vdev, md.va, buf, llen);
38253a55002SPaolo Bonzini         } else {
3838ca8a17cSAlexey Kardashevskiy             rc = spapr_vio_dma_write(&s->vdev, md.va, buf, llen);
38453a55002SPaolo Bonzini         }
38553a55002SPaolo Bonzini     }
38653a55002SPaolo Bonzini 
38753a55002SPaolo Bonzini     if (rc) {
38853a55002SPaolo Bonzini         return -1;
38953a55002SPaolo Bonzini     }
3908ca8a17cSAlexey Kardashevskiy     req->cur_desc_offset += llen;
3918ca8a17cSAlexey Kardashevskiy 
39253a55002SPaolo Bonzini     return llen;
39353a55002SPaolo Bonzini }
39453a55002SPaolo Bonzini 
vscsi_srp_indirect_data(VSCSIState * s,vscsi_req * req,uint8_t * buf,uint32_t len)39553a55002SPaolo Bonzini static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req,
39653a55002SPaolo Bonzini                                    uint8_t *buf, uint32_t len)
39753a55002SPaolo Bonzini {
3988ca8a17cSAlexey Kardashevskiy     struct srp_direct_buf md;
39953a55002SPaolo Bonzini     int rc = 0;
40053a55002SPaolo Bonzini     uint32_t llen, total = 0;
40153a55002SPaolo Bonzini 
402f19661c8SLaurent Vivier     trace_spapr_vscsi_srp_indirect_data(len);
40353a55002SPaolo Bonzini 
40453a55002SPaolo Bonzini     /* While we have data ... */
40553a55002SPaolo Bonzini     while (len) {
4068ca8a17cSAlexey Kardashevskiy         rc = vscsi_fetch_desc(s, req, req->cur_desc_num, req->cur_desc_offset, &md);
4078ca8a17cSAlexey Kardashevskiy         if (rc < 0) {
4088ca8a17cSAlexey Kardashevskiy             return -1;
4098ca8a17cSAlexey Kardashevskiy         } else if (rc == 0) {
41053a55002SPaolo Bonzini             break;
41153a55002SPaolo Bonzini         }
41253a55002SPaolo Bonzini 
41353a55002SPaolo Bonzini         /* Perform transfer */
4148ca8a17cSAlexey Kardashevskiy         llen = MIN(len, md.len);
41553a55002SPaolo Bonzini         if (req->writing) { /* writing = to device = reading from memory */
4168ca8a17cSAlexey Kardashevskiy             rc = spapr_vio_dma_read(&s->vdev, md.va, buf, llen);
41753a55002SPaolo Bonzini         } else {
4188ca8a17cSAlexey Kardashevskiy             rc = spapr_vio_dma_write(&s->vdev, md.va, buf, llen);
41953a55002SPaolo Bonzini         }
42053a55002SPaolo Bonzini         if (rc) {
421f19661c8SLaurent Vivier             trace_spapr_vscsi_srp_indirect_data_rw(req->writing, rc);
42253a55002SPaolo Bonzini             break;
42353a55002SPaolo Bonzini         }
424f19661c8SLaurent Vivier         trace_spapr_vscsi_srp_indirect_data_buf(buf[0], buf[1], buf[2], buf[3]);
42553a55002SPaolo Bonzini 
42653a55002SPaolo Bonzini         len -= llen;
42753a55002SPaolo Bonzini         buf += llen;
4288ca8a17cSAlexey Kardashevskiy 
42953a55002SPaolo Bonzini         total += llen;
4308ca8a17cSAlexey Kardashevskiy 
4318ca8a17cSAlexey Kardashevskiy         /* Update current position in the current descriptor */
4328ca8a17cSAlexey Kardashevskiy         req->cur_desc_offset += llen;
4338ca8a17cSAlexey Kardashevskiy         if (md.len == llen) {
4348ca8a17cSAlexey Kardashevskiy             /* Go to the next descriptor if the current one finished */
4358ca8a17cSAlexey Kardashevskiy             ++req->cur_desc_num;
4368ca8a17cSAlexey Kardashevskiy             req->cur_desc_offset = 0;
43753a55002SPaolo Bonzini         }
4388ca8a17cSAlexey Kardashevskiy     }
4398ca8a17cSAlexey Kardashevskiy 
44053a55002SPaolo Bonzini     return rc ? -1 : total;
44153a55002SPaolo Bonzini }
44253a55002SPaolo Bonzini 
vscsi_srp_transfer_data(VSCSIState * s,vscsi_req * req,int writing,uint8_t * buf,uint32_t len)44353a55002SPaolo Bonzini static int vscsi_srp_transfer_data(VSCSIState *s, vscsi_req *req,
44453a55002SPaolo Bonzini                                    int writing, uint8_t *buf, uint32_t len)
44553a55002SPaolo Bonzini {
44653a55002SPaolo Bonzini     int err = 0;
44753a55002SPaolo Bonzini 
44853a55002SPaolo Bonzini     switch (req->dma_fmt) {
44953a55002SPaolo Bonzini     case SRP_NO_DATA_DESC:
450f19661c8SLaurent Vivier         trace_spapr_vscsi_srp_transfer_data(len);
45153a55002SPaolo Bonzini         break;
45253a55002SPaolo Bonzini     case SRP_DATA_DESC_DIRECT:
45353a55002SPaolo Bonzini         err = vscsi_srp_direct_data(s, req, buf, len);
45453a55002SPaolo Bonzini         break;
45553a55002SPaolo Bonzini     case SRP_DATA_DESC_INDIRECT:
45653a55002SPaolo Bonzini         err = vscsi_srp_indirect_data(s, req, buf, len);
45753a55002SPaolo Bonzini         break;
45853a55002SPaolo Bonzini     }
45953a55002SPaolo Bonzini     return err;
46053a55002SPaolo Bonzini }
46153a55002SPaolo Bonzini 
46253a55002SPaolo Bonzini /* Bits from linux srp */
data_out_desc_size(struct srp_cmd * cmd)46353a55002SPaolo Bonzini static int data_out_desc_size(struct srp_cmd *cmd)
46453a55002SPaolo Bonzini {
46553a55002SPaolo Bonzini     int size = 0;
46653a55002SPaolo Bonzini     uint8_t fmt = cmd->buf_fmt >> 4;
46753a55002SPaolo Bonzini 
46853a55002SPaolo Bonzini     switch (fmt) {
46953a55002SPaolo Bonzini     case SRP_NO_DATA_DESC:
47053a55002SPaolo Bonzini         break;
47153a55002SPaolo Bonzini     case SRP_DATA_DESC_DIRECT:
47253a55002SPaolo Bonzini         size = sizeof(struct srp_direct_buf);
47353a55002SPaolo Bonzini         break;
47453a55002SPaolo Bonzini     case SRP_DATA_DESC_INDIRECT:
47553a55002SPaolo Bonzini         size = sizeof(struct srp_indirect_buf) +
47653a55002SPaolo Bonzini             sizeof(struct srp_direct_buf)*cmd->data_out_desc_cnt;
47753a55002SPaolo Bonzini         break;
47853a55002SPaolo Bonzini     default:
47953a55002SPaolo Bonzini         break;
48053a55002SPaolo Bonzini     }
48153a55002SPaolo Bonzini     return size;
48253a55002SPaolo Bonzini }
48353a55002SPaolo Bonzini 
vscsi_preprocess_desc(vscsi_req * req)48453a55002SPaolo Bonzini static int vscsi_preprocess_desc(vscsi_req *req)
48553a55002SPaolo Bonzini {
48681e70549SPhilippe Mathieu-Daudé     struct srp_cmd *cmd = &req_iu(req)->srp.cmd;
48753a55002SPaolo Bonzini 
4888ca8a17cSAlexey Kardashevskiy     req->cdb_offset = cmd->add_cdb_len & ~3;
48953a55002SPaolo Bonzini 
49053a55002SPaolo Bonzini     if (req->writing) {
49153a55002SPaolo Bonzini         req->dma_fmt = cmd->buf_fmt >> 4;
49253a55002SPaolo Bonzini     } else {
4938ca8a17cSAlexey Kardashevskiy         req->cdb_offset += data_out_desc_size(cmd);
49453a55002SPaolo Bonzini         req->dma_fmt = cmd->buf_fmt & ((1U << 4) - 1);
49553a55002SPaolo Bonzini     }
49653a55002SPaolo Bonzini 
49753a55002SPaolo Bonzini     switch (req->dma_fmt) {
49853a55002SPaolo Bonzini     case SRP_NO_DATA_DESC:
49953a55002SPaolo Bonzini         break;
50053a55002SPaolo Bonzini     case SRP_DATA_DESC_DIRECT:
50153a55002SPaolo Bonzini         req->total_desc = req->local_desc = 1;
50253a55002SPaolo Bonzini         break;
5038ca8a17cSAlexey Kardashevskiy     case SRP_DATA_DESC_INDIRECT: {
5048ca8a17cSAlexey Kardashevskiy         struct srp_indirect_buf *ind_tmp = (struct srp_indirect_buf *)
5058ca8a17cSAlexey Kardashevskiy                 (cmd->add_data + req->cdb_offset);
5068ca8a17cSAlexey Kardashevskiy 
5078ca8a17cSAlexey Kardashevskiy         req->total_desc = be32_to_cpu(ind_tmp->table_desc.len) /
50853a55002SPaolo Bonzini                           sizeof(struct srp_direct_buf);
50953a55002SPaolo Bonzini         req->local_desc = req->writing ? cmd->data_out_desc_cnt :
51053a55002SPaolo Bonzini                           cmd->data_in_desc_cnt;
51153a55002SPaolo Bonzini         break;
5128ca8a17cSAlexey Kardashevskiy     }
51353a55002SPaolo Bonzini     default:
51453a55002SPaolo Bonzini         fprintf(stderr,
51553a55002SPaolo Bonzini                 "vscsi_preprocess_desc: Unknown format %x\n", req->dma_fmt);
51653a55002SPaolo Bonzini         return -1;
51753a55002SPaolo Bonzini     }
51853a55002SPaolo Bonzini 
51953a55002SPaolo Bonzini     return 0;
52053a55002SPaolo Bonzini }
52153a55002SPaolo Bonzini 
52253a55002SPaolo Bonzini /* Callback to indicate that the SCSI layer has completed a transfer.  */
vscsi_transfer_data(SCSIRequest * sreq,uint32_t len)52353a55002SPaolo Bonzini static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
52453a55002SPaolo Bonzini {
525fd506b4fSDavid Gibson     VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent);
52653a55002SPaolo Bonzini     vscsi_req *req = sreq->hba_private;
52753a55002SPaolo Bonzini     uint8_t *buf;
52853a55002SPaolo Bonzini     int rc = 0;
52953a55002SPaolo Bonzini 
530f19661c8SLaurent Vivier     trace_spapr_vscsi_transfer_data(sreq->tag, len, req);
53153a55002SPaolo Bonzini     if (req == NULL) {
53253a55002SPaolo Bonzini         fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
53353a55002SPaolo Bonzini         return;
53453a55002SPaolo Bonzini     }
53553a55002SPaolo Bonzini 
53653a55002SPaolo Bonzini     if (len) {
53753a55002SPaolo Bonzini         buf = scsi_req_get_buf(sreq);
53853a55002SPaolo Bonzini         rc = vscsi_srp_transfer_data(s, req, req->writing, buf, len);
53953a55002SPaolo Bonzini     }
54053a55002SPaolo Bonzini     if (rc < 0) {
54153a55002SPaolo Bonzini         fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc);
542eda470e4SFam Zheng         req->dma_error = true;
543eda470e4SFam Zheng         scsi_req_cancel(req->sreq);
54453a55002SPaolo Bonzini         return;
54553a55002SPaolo Bonzini     }
54653a55002SPaolo Bonzini 
54753a55002SPaolo Bonzini     /* Start next chunk */
54853a55002SPaolo Bonzini     req->data_len -= rc;
54953a55002SPaolo Bonzini     scsi_req_continue(sreq);
55053a55002SPaolo Bonzini }
55153a55002SPaolo Bonzini 
55253a55002SPaolo Bonzini /* Callback to indicate that the SCSI layer has completed a transfer.  */
vscsi_command_complete(SCSIRequest * sreq,size_t resid)55317ea26c2SHannes Reinecke static void vscsi_command_complete(SCSIRequest *sreq, size_t resid)
55453a55002SPaolo Bonzini {
555fd506b4fSDavid Gibson     VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent);
55653a55002SPaolo Bonzini     vscsi_req *req = sreq->hba_private;
55753a55002SPaolo Bonzini     int32_t res_in = 0, res_out = 0;
55853a55002SPaolo Bonzini 
55917ea26c2SHannes Reinecke     trace_spapr_vscsi_command_complete(sreq->tag, sreq->status, req);
56053a55002SPaolo Bonzini     if (req == NULL) {
56153a55002SPaolo Bonzini         fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
56253a55002SPaolo Bonzini         return;
56353a55002SPaolo Bonzini     }
56453a55002SPaolo Bonzini 
56517ea26c2SHannes Reinecke     if (sreq->status == CHECK_CONDITION) {
56653a55002SPaolo Bonzini         req->senselen = scsi_req_get_sense(req->sreq, req->sense,
56753a55002SPaolo Bonzini                                            sizeof(req->sense));
568f19661c8SLaurent Vivier         trace_spapr_vscsi_command_complete_sense_data1(req->senselen,
56953a55002SPaolo Bonzini                 req->sense[0], req->sense[1], req->sense[2], req->sense[3],
57053a55002SPaolo Bonzini                 req->sense[4], req->sense[5], req->sense[6], req->sense[7]);
571f19661c8SLaurent Vivier         trace_spapr_vscsi_command_complete_sense_data2(
57253a55002SPaolo Bonzini                 req->sense[8], req->sense[9], req->sense[10], req->sense[11],
57353a55002SPaolo Bonzini                 req->sense[12], req->sense[13], req->sense[14], req->sense[15]);
57453a55002SPaolo Bonzini     }
57553a55002SPaolo Bonzini 
57617ea26c2SHannes Reinecke     trace_spapr_vscsi_command_complete_status(sreq->status);
57717ea26c2SHannes Reinecke     if (sreq->status == 0) {
57853a55002SPaolo Bonzini         /* We handle overflows, not underflows for normal commands,
57953a55002SPaolo Bonzini          * but hopefully nobody cares
58053a55002SPaolo Bonzini          */
58153a55002SPaolo Bonzini         if (req->writing) {
58253a55002SPaolo Bonzini             res_out = req->data_len;
58353a55002SPaolo Bonzini         } else {
58453a55002SPaolo Bonzini             res_in = req->data_len;
58553a55002SPaolo Bonzini         }
58653a55002SPaolo Bonzini     }
58717ea26c2SHannes Reinecke     vscsi_send_rsp(s, req, sreq->status, res_in, res_out);
58853a55002SPaolo Bonzini     vscsi_put_req(req);
58953a55002SPaolo Bonzini }
59053a55002SPaolo Bonzini 
vscsi_request_cancelled(SCSIRequest * sreq)59153a55002SPaolo Bonzini static void vscsi_request_cancelled(SCSIRequest *sreq)
59253a55002SPaolo Bonzini {
59353a55002SPaolo Bonzini     vscsi_req *req = sreq->hba_private;
59453a55002SPaolo Bonzini 
595eda470e4SFam Zheng     if (req->dma_error) {
596eda470e4SFam Zheng         VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent);
597eda470e4SFam Zheng 
598eda470e4SFam Zheng         vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
599eda470e4SFam Zheng         vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
600eda470e4SFam Zheng     }
60153a55002SPaolo Bonzini     vscsi_put_req(req);
60253a55002SPaolo Bonzini }
60353a55002SPaolo Bonzini 
6041168ec7dSDavid Gibson static const VMStateDescription vmstate_spapr_vscsi_req = {
6051168ec7dSDavid Gibson     .name = "spapr_vscsi_req",
6061168ec7dSDavid Gibson     .version_id = 1,
6071168ec7dSDavid Gibson     .minimum_version_id = 1,
608*2d7b39a6SRichard Henderson     .fields = (const VMStateField[]) {
6091168ec7dSDavid Gibson         VMSTATE_BUFFER(crq.raw, vscsi_req),
610ff78b728SPhilippe Mathieu-Daudé         VMSTATE_BUFFER(viosrp_iu_buf, vscsi_req),
6111168ec7dSDavid Gibson         VMSTATE_UINT32(qtag, vscsi_req),
6121168ec7dSDavid Gibson         VMSTATE_BOOL(active, vscsi_req),
6131168ec7dSDavid Gibson         VMSTATE_UINT32(data_len, vscsi_req),
6141168ec7dSDavid Gibson         VMSTATE_BOOL(writing, vscsi_req),
6151168ec7dSDavid Gibson         VMSTATE_UINT32(senselen, vscsi_req),
6161168ec7dSDavid Gibson         VMSTATE_BUFFER(sense, vscsi_req),
6171168ec7dSDavid Gibson         VMSTATE_UINT8(dma_fmt, vscsi_req),
6181168ec7dSDavid Gibson         VMSTATE_UINT16(local_desc, vscsi_req),
6191168ec7dSDavid Gibson         VMSTATE_UINT16(total_desc, vscsi_req),
6201168ec7dSDavid Gibson         VMSTATE_UINT16(cdb_offset, vscsi_req),
6211168ec7dSDavid Gibson       /*Restart SCSI request from the beginning for now */
6221168ec7dSDavid Gibson       /*VMSTATE_UINT16(cur_desc_num, vscsi_req),
6231168ec7dSDavid Gibson         VMSTATE_UINT16(cur_desc_offset, vscsi_req),*/
6241168ec7dSDavid Gibson         VMSTATE_END_OF_LIST()
6251168ec7dSDavid Gibson     },
6261168ec7dSDavid Gibson };
6271168ec7dSDavid Gibson 
vscsi_save_request(QEMUFile * f,SCSIRequest * sreq)6281168ec7dSDavid Gibson static void vscsi_save_request(QEMUFile *f, SCSIRequest *sreq)
6291168ec7dSDavid Gibson {
6301168ec7dSDavid Gibson     vscsi_req *req = sreq->hba_private;
6311168ec7dSDavid Gibson     assert(req->active);
6321168ec7dSDavid Gibson 
6338118f095SAlexander Graf     vmstate_save_state(f, &vmstate_spapr_vscsi_req, req, NULL);
6341168ec7dSDavid Gibson 
635f19661c8SLaurent Vivier     trace_spapr_vscsi_save_request(req->qtag, req->cur_desc_num,
636f19661c8SLaurent Vivier                                    req->cur_desc_offset);
6371168ec7dSDavid Gibson }
6381168ec7dSDavid Gibson 
vscsi_load_request(QEMUFile * f,SCSIRequest * sreq)6391168ec7dSDavid Gibson static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq)
6401168ec7dSDavid Gibson {
6411168ec7dSDavid Gibson     SCSIBus *bus = sreq->bus;
6421168ec7dSDavid Gibson     VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(bus->qbus.parent);
6431168ec7dSDavid Gibson     vscsi_req *req;
6441168ec7dSDavid Gibson     int rc;
6451168ec7dSDavid Gibson 
6461168ec7dSDavid Gibson     assert(sreq->tag < VSCSI_REQ_LIMIT);
6471168ec7dSDavid Gibson     req = &s->reqs[sreq->tag];
6481168ec7dSDavid Gibson     assert(!req->active);
6491168ec7dSDavid Gibson 
6501168ec7dSDavid Gibson     memset(req, 0, sizeof(*req));
6511168ec7dSDavid Gibson     rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1);
6521168ec7dSDavid Gibson     if (rc) {
6531168ec7dSDavid Gibson         fprintf(stderr, "VSCSI: failed loading request tag#%u\n", sreq->tag);
6541168ec7dSDavid Gibson         return NULL;
6551168ec7dSDavid Gibson     }
6561168ec7dSDavid Gibson     assert(req->active);
6571168ec7dSDavid Gibson 
6581168ec7dSDavid Gibson     req->sreq = scsi_req_ref(sreq);
6591168ec7dSDavid Gibson 
660f19661c8SLaurent Vivier     trace_spapr_vscsi_load_request(req->qtag, req->cur_desc_num,
661f19661c8SLaurent Vivier                                    req->cur_desc_offset);
6621168ec7dSDavid Gibson 
6631168ec7dSDavid Gibson     return req;
6641168ec7dSDavid Gibson }
6651168ec7dSDavid Gibson 
vscsi_process_login(VSCSIState * s,vscsi_req * req)66653a55002SPaolo Bonzini static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
66753a55002SPaolo Bonzini {
66881e70549SPhilippe Mathieu-Daudé     union viosrp_iu *iu = req_iu(req);
66953a55002SPaolo Bonzini     struct srp_login_rsp *rsp = &iu->srp.login_rsp;
67053a55002SPaolo Bonzini     uint64_t tag = iu->srp.rsp.tag;
67153a55002SPaolo Bonzini 
672196fe237SFelipe Franciosi     trace_spapr_vscsi_process_login();
67353a55002SPaolo Bonzini 
67453a55002SPaolo Bonzini     /* TODO handle case that requested size is wrong and
67553a55002SPaolo Bonzini      * buffer format is wrong
67653a55002SPaolo Bonzini      */
67753a55002SPaolo Bonzini     memset(iu, 0, sizeof(struct srp_login_rsp));
67853a55002SPaolo Bonzini     rsp->opcode = SRP_LOGIN_RSP;
67953a55002SPaolo Bonzini     /* Don't advertise quite as many request as we support to
68053a55002SPaolo Bonzini      * keep room for management stuff etc...
68153a55002SPaolo Bonzini      */
68253a55002SPaolo Bonzini     rsp->req_lim_delta = cpu_to_be32(VSCSI_REQ_LIMIT-2);
68353a55002SPaolo Bonzini     rsp->tag = tag;
6840dc55698SPhilippe Mathieu-Daudé     rsp->max_it_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
6850dc55698SPhilippe Mathieu-Daudé     rsp->max_ti_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
68653a55002SPaolo Bonzini     /* direct and indirect */
68753a55002SPaolo Bonzini     rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT);
68853a55002SPaolo Bonzini 
68953a55002SPaolo Bonzini     vscsi_send_iu(s, req, sizeof(*rsp), VIOSRP_SRP_FORMAT);
69053a55002SPaolo Bonzini }
69153a55002SPaolo Bonzini 
vscsi_inquiry_no_target(VSCSIState * s,vscsi_req * req)69253a55002SPaolo Bonzini static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
69353a55002SPaolo Bonzini {
69481e70549SPhilippe Mathieu-Daudé     uint8_t *cdb = req_iu(req)->srp.cmd.cdb;
69553a55002SPaolo Bonzini     uint8_t resp_data[36];
69653a55002SPaolo Bonzini     int rc, len, alen;
69753a55002SPaolo Bonzini 
698cb8d4c8fSStefan Weil     /* We don't do EVPD. Also check that page_code is 0 */
699ec8929a5SPrasad Joshi     if ((cdb[1] & 0x01) || cdb[2] != 0) {
70053a55002SPaolo Bonzini         /* Send INVALID FIELD IN CDB */
70153a55002SPaolo Bonzini         vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0);
70253a55002SPaolo Bonzini         vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
70353a55002SPaolo Bonzini         return;
70453a55002SPaolo Bonzini     }
70553a55002SPaolo Bonzini     alen = cdb[3];
70653a55002SPaolo Bonzini     alen = (alen << 8) | cdb[4];
70753a55002SPaolo Bonzini     len = MIN(alen, 36);
70853a55002SPaolo Bonzini 
70953a55002SPaolo Bonzini     /* Fake up inquiry using PQ=3 */
71053a55002SPaolo Bonzini     memset(resp_data, 0, 36);
71153a55002SPaolo Bonzini     resp_data[0] = 0x7f;   /* Not capable of supporting a device here */
71253a55002SPaolo Bonzini     resp_data[2] = 0x06;   /* SPS-4 */
71353a55002SPaolo Bonzini     resp_data[3] = 0x02;   /* Resp data format */
71453a55002SPaolo Bonzini     resp_data[4] = 36 - 5; /* Additional length */
71553a55002SPaolo Bonzini     resp_data[7] = 0x10;   /* Sync transfers */
71653a55002SPaolo Bonzini     memcpy(&resp_data[16], "QEMU EMPTY      ", 16);
71753a55002SPaolo Bonzini     memcpy(&resp_data[8], "QEMU    ", 8);
71853a55002SPaolo Bonzini 
71953a55002SPaolo Bonzini     req->writing = 0;
72053a55002SPaolo Bonzini     vscsi_preprocess_desc(req);
72153a55002SPaolo Bonzini     rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len);
72253a55002SPaolo Bonzini     if (rc < 0) {
72353a55002SPaolo Bonzini         vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
72453a55002SPaolo Bonzini         vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
72553a55002SPaolo Bonzini     } else {
72653a55002SPaolo Bonzini         vscsi_send_rsp(s, req, 0, 36 - rc, 0);
72753a55002SPaolo Bonzini     }
72853a55002SPaolo Bonzini }
72953a55002SPaolo Bonzini 
vscsi_report_luns(VSCSIState * s,vscsi_req * req)7303052f0d5SNathan Whitehorn static void vscsi_report_luns(VSCSIState *s, vscsi_req *req)
7313052f0d5SNathan Whitehorn {
7323052f0d5SNathan Whitehorn     BusChild *kid;
7333052f0d5SNathan Whitehorn     int i, len, n, rc;
7343052f0d5SNathan Whitehorn     uint8_t *resp_data;
7353052f0d5SNathan Whitehorn     bool found_lun0;
7363052f0d5SNathan Whitehorn 
7373052f0d5SNathan Whitehorn     n = 0;
7383052f0d5SNathan Whitehorn     found_lun0 = false;
7393052f0d5SNathan Whitehorn     QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
7403052f0d5SNathan Whitehorn         SCSIDevice *dev = SCSI_DEVICE(kid->child);
7413052f0d5SNathan Whitehorn 
7423052f0d5SNathan Whitehorn         n += 8;
7433052f0d5SNathan Whitehorn         if (dev->channel == 0 && dev->id == 0 && dev->lun == 0) {
7443052f0d5SNathan Whitehorn             found_lun0 = true;
7453052f0d5SNathan Whitehorn         }
7463052f0d5SNathan Whitehorn     }
7473052f0d5SNathan Whitehorn     if (!found_lun0) {
7483052f0d5SNathan Whitehorn         n += 8;
7493052f0d5SNathan Whitehorn     }
7503052f0d5SNathan Whitehorn     len = n+8;
7513052f0d5SNathan Whitehorn 
7523052f0d5SNathan Whitehorn     resp_data = g_malloc0(len);
7533052f0d5SNathan Whitehorn     stl_be_p(resp_data, n);
7543052f0d5SNathan Whitehorn     i = found_lun0 ? 8 : 16;
7553052f0d5SNathan Whitehorn     QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
7563052f0d5SNathan Whitehorn         DeviceState *qdev = kid->child;
7573052f0d5SNathan Whitehorn         SCSIDevice *dev = SCSI_DEVICE(qdev);
7583052f0d5SNathan Whitehorn 
7593052f0d5SNathan Whitehorn         if (dev->id == 0 && dev->channel == 0) {
7603052f0d5SNathan Whitehorn             resp_data[i] = 0;         /* Use simple LUN for 0 (SAM5 4.7.7.1) */
7613052f0d5SNathan Whitehorn         } else {
7623052f0d5SNathan Whitehorn             resp_data[i] = (2 << 6);  /* Otherwise LUN addressing (4.7.7.4)  */
7633052f0d5SNathan Whitehorn         }
7643052f0d5SNathan Whitehorn         resp_data[i] |= dev->id;
7653052f0d5SNathan Whitehorn         resp_data[i+1] = (dev->channel << 5);
7663052f0d5SNathan Whitehorn         resp_data[i+1] |= dev->lun;
7673052f0d5SNathan Whitehorn         i += 8;
7683052f0d5SNathan Whitehorn     }
7693052f0d5SNathan Whitehorn 
7703052f0d5SNathan Whitehorn     vscsi_preprocess_desc(req);
7713052f0d5SNathan Whitehorn     rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len);
7723052f0d5SNathan Whitehorn     g_free(resp_data);
7733052f0d5SNathan Whitehorn     if (rc < 0) {
7743052f0d5SNathan Whitehorn         vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
7753052f0d5SNathan Whitehorn         vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
7763052f0d5SNathan Whitehorn     } else {
7773052f0d5SNathan Whitehorn         vscsi_send_rsp(s, req, 0, len - rc, 0);
7783052f0d5SNathan Whitehorn     }
7793052f0d5SNathan Whitehorn }
7803052f0d5SNathan Whitehorn 
vscsi_queue_cmd(VSCSIState * s,vscsi_req * req)78153a55002SPaolo Bonzini static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
78253a55002SPaolo Bonzini {
78381e70549SPhilippe Mathieu-Daudé     union srp_iu *srp = &req_iu(req)->srp;
78453a55002SPaolo Bonzini     SCSIDevice *sdev;
78553a55002SPaolo Bonzini     int n, lun;
786fe9d8927SJohn Millikin     size_t cdb_len = sizeof (srp->cmd.cdb) + (srp->cmd.add_cdb_len & ~3);
78753a55002SPaolo Bonzini 
7883052f0d5SNathan Whitehorn     if ((srp->cmd.lun == 0 || be64_to_cpu(srp->cmd.lun) == SRP_REPORT_LUNS_WLUN)
7893052f0d5SNathan Whitehorn       && srp->cmd.cdb[0] == REPORT_LUNS) {
7903052f0d5SNathan Whitehorn         vscsi_report_luns(s, req);
7913052f0d5SNathan Whitehorn         return 0;
7923052f0d5SNathan Whitehorn     }
7933052f0d5SNathan Whitehorn 
79453a55002SPaolo Bonzini     sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun);
79553a55002SPaolo Bonzini     if (!sdev) {
796f19661c8SLaurent Vivier         trace_spapr_vscsi_queue_cmd_no_drive(be64_to_cpu(srp->cmd.lun));
79753a55002SPaolo Bonzini         if (srp->cmd.cdb[0] == INQUIRY) {
79853a55002SPaolo Bonzini             vscsi_inquiry_no_target(s, req);
79953a55002SPaolo Bonzini         } else {
80053a55002SPaolo Bonzini             vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0x00);
80153a55002SPaolo Bonzini             vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
80253a55002SPaolo Bonzini         } return 1;
80353a55002SPaolo Bonzini     }
80453a55002SPaolo Bonzini 
805fe9d8927SJohn Millikin     req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, cdb_len, req);
80653a55002SPaolo Bonzini     n = scsi_req_enqueue(req->sreq);
80753a55002SPaolo Bonzini 
808f19661c8SLaurent Vivier     trace_spapr_vscsi_queue_cmd(req->qtag, srp->cmd.cdb[0],
809f19661c8SLaurent Vivier                                 scsi_command_name(srp->cmd.cdb[0]), lun, n);
81053a55002SPaolo Bonzini 
81153a55002SPaolo Bonzini     if (n) {
81253a55002SPaolo Bonzini         /* Transfer direction must be set before preprocessing the
81353a55002SPaolo Bonzini          * descriptors
81453a55002SPaolo Bonzini          */
81553a55002SPaolo Bonzini         req->writing = (n < 1);
81653a55002SPaolo Bonzini 
81753a55002SPaolo Bonzini         /* Preprocess RDMA descriptors */
81853a55002SPaolo Bonzini         vscsi_preprocess_desc(req);
81953a55002SPaolo Bonzini 
82053a55002SPaolo Bonzini         /* Get transfer direction and initiate transfer */
82153a55002SPaolo Bonzini         if (n > 0) {
82253a55002SPaolo Bonzini             req->data_len = n;
82353a55002SPaolo Bonzini         } else if (n < 0) {
82453a55002SPaolo Bonzini             req->data_len = -n;
82553a55002SPaolo Bonzini         }
82653a55002SPaolo Bonzini         scsi_req_continue(req->sreq);
82753a55002SPaolo Bonzini     }
82853a55002SPaolo Bonzini     /* Don't touch req here, it may have been recycled already */
82953a55002SPaolo Bonzini 
83053a55002SPaolo Bonzini     return 0;
83153a55002SPaolo Bonzini }
83253a55002SPaolo Bonzini 
vscsi_process_tsk_mgmt(VSCSIState * s,vscsi_req * req)83353a55002SPaolo Bonzini static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
83453a55002SPaolo Bonzini {
83581e70549SPhilippe Mathieu-Daudé     union viosrp_iu *iu = req_iu(req);
836eb37f146SAlexey Kardashevskiy     vscsi_req *tmpreq;
837eb37f146SAlexey Kardashevskiy     int i, lun = 0, resp = SRP_TSK_MGMT_COMPLETE;
838eb37f146SAlexey Kardashevskiy     SCSIDevice *d;
839eb37f146SAlexey Kardashevskiy     uint64_t tag = iu->srp.rsp.tag;
840eb37f146SAlexey Kardashevskiy     uint8_t sol_not = iu->srp.cmd.sol_not;
84153a55002SPaolo Bonzini 
842a7017b20SPhilippe Mathieu-Daudé     trace_spapr_vscsi_process_tsk_mgmt(iu->srp.tsk_mgmt.tsk_mgmt_func);
84381e70549SPhilippe Mathieu-Daudé     d = vscsi_device_find(&s->bus,
84481e70549SPhilippe Mathieu-Daudé                           be64_to_cpu(req_iu(req)->srp.tsk_mgmt.lun), &lun);
845eb37f146SAlexey Kardashevskiy     if (!d) {
846eb37f146SAlexey Kardashevskiy         resp = SRP_TSK_MGMT_FIELDS_INVALID;
84753a55002SPaolo Bonzini     } else {
848eb37f146SAlexey Kardashevskiy         switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
849eb37f146SAlexey Kardashevskiy         case SRP_TSK_ABORT_TASK:
850eb37f146SAlexey Kardashevskiy             if (d->lun != lun) {
851eb37f146SAlexey Kardashevskiy                 resp = SRP_TSK_MGMT_FIELDS_INVALID;
852eb37f146SAlexey Kardashevskiy                 break;
85353a55002SPaolo Bonzini             }
854eb37f146SAlexey Kardashevskiy 
85581e70549SPhilippe Mathieu-Daudé             tmpreq = vscsi_find_req(s, req_iu(req)->srp.tsk_mgmt.task_tag);
856eb37f146SAlexey Kardashevskiy             if (tmpreq && tmpreq->sreq) {
857eb37f146SAlexey Kardashevskiy                 assert(tmpreq->sreq->hba_private);
858eb37f146SAlexey Kardashevskiy                 scsi_req_cancel(tmpreq->sreq);
859eb37f146SAlexey Kardashevskiy             }
860eb37f146SAlexey Kardashevskiy             break;
861eb37f146SAlexey Kardashevskiy 
862eb37f146SAlexey Kardashevskiy         case SRP_TSK_LUN_RESET:
863eb37f146SAlexey Kardashevskiy             if (d->lun != lun) {
864eb37f146SAlexey Kardashevskiy                 resp = SRP_TSK_MGMT_FIELDS_INVALID;
865eb37f146SAlexey Kardashevskiy                 break;
866eb37f146SAlexey Kardashevskiy             }
867eb37f146SAlexey Kardashevskiy 
8684a5fc890SPeter Maydell             device_cold_reset(&d->qdev);
869eb37f146SAlexey Kardashevskiy             break;
870eb37f146SAlexey Kardashevskiy 
871eb37f146SAlexey Kardashevskiy         case SRP_TSK_ABORT_TASK_SET:
872eb37f146SAlexey Kardashevskiy         case SRP_TSK_CLEAR_TASK_SET:
873eb37f146SAlexey Kardashevskiy             if (d->lun != lun) {
874eb37f146SAlexey Kardashevskiy                 resp = SRP_TSK_MGMT_FIELDS_INVALID;
875eb37f146SAlexey Kardashevskiy                 break;
876eb37f146SAlexey Kardashevskiy             }
877eb37f146SAlexey Kardashevskiy 
878eb37f146SAlexey Kardashevskiy             for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
879eb37f146SAlexey Kardashevskiy                 tmpreq = &s->reqs[i];
88081e70549SPhilippe Mathieu-Daudé                 if (req_iu(tmpreq)->srp.cmd.lun
88181e70549SPhilippe Mathieu-Daudé                         != req_iu(req)->srp.tsk_mgmt.lun) {
882eb37f146SAlexey Kardashevskiy                     continue;
883eb37f146SAlexey Kardashevskiy                 }
884eb37f146SAlexey Kardashevskiy                 if (!tmpreq->active || !tmpreq->sreq) {
885eb37f146SAlexey Kardashevskiy                     continue;
886eb37f146SAlexey Kardashevskiy                 }
887eb37f146SAlexey Kardashevskiy                 assert(tmpreq->sreq->hba_private);
888eb37f146SAlexey Kardashevskiy                 scsi_req_cancel(tmpreq->sreq);
889eb37f146SAlexey Kardashevskiy             }
890eb37f146SAlexey Kardashevskiy             break;
891eb37f146SAlexey Kardashevskiy 
892eb37f146SAlexey Kardashevskiy         case SRP_TSK_CLEAR_ACA:
893eb37f146SAlexey Kardashevskiy             resp = SRP_TSK_MGMT_NOT_SUPPORTED;
894eb37f146SAlexey Kardashevskiy             break;
895eb37f146SAlexey Kardashevskiy 
896eb37f146SAlexey Kardashevskiy         default:
897eb37f146SAlexey Kardashevskiy             resp = SRP_TSK_MGMT_FIELDS_INVALID;
898eb37f146SAlexey Kardashevskiy             break;
899eb37f146SAlexey Kardashevskiy         }
900eb37f146SAlexey Kardashevskiy     }
901eb37f146SAlexey Kardashevskiy 
902eb37f146SAlexey Kardashevskiy     /* Compose the response here as  */
90313a54905SPhilippe Mathieu-Daudé     QEMU_BUILD_BUG_ON(SRP_MAX_IU_DATA_LEN < 4);
904eb37f146SAlexey Kardashevskiy     memset(iu, 0, sizeof(struct srp_rsp) + 4);
905eb37f146SAlexey Kardashevskiy     iu->srp.rsp.opcode = SRP_RSP;
906eb37f146SAlexey Kardashevskiy     iu->srp.rsp.req_lim_delta = cpu_to_be32(1);
907eb37f146SAlexey Kardashevskiy     iu->srp.rsp.tag = tag;
908eb37f146SAlexey Kardashevskiy     iu->srp.rsp.flags |= SRP_RSP_FLAG_RSPVALID;
909eb37f146SAlexey Kardashevskiy     iu->srp.rsp.resp_data_len = cpu_to_be32(4);
910eb37f146SAlexey Kardashevskiy     if (resp) {
911eb37f146SAlexey Kardashevskiy         iu->srp.rsp.sol_not = (sol_not & 0x04) >> 2;
912eb37f146SAlexey Kardashevskiy     } else {
913eb37f146SAlexey Kardashevskiy         iu->srp.rsp.sol_not = (sol_not & 0x02) >> 1;
914eb37f146SAlexey Kardashevskiy     }
915eb37f146SAlexey Kardashevskiy 
916eb37f146SAlexey Kardashevskiy     iu->srp.rsp.status = GOOD;
917eb37f146SAlexey Kardashevskiy     iu->srp.rsp.data[3] = resp;
918eb37f146SAlexey Kardashevskiy 
919eb37f146SAlexey Kardashevskiy     vscsi_send_iu(s, req, sizeof(iu->srp.rsp) + 4, VIOSRP_SRP_FORMAT);
920eb37f146SAlexey Kardashevskiy 
921eb37f146SAlexey Kardashevskiy     return 1;
92253a55002SPaolo Bonzini }
92353a55002SPaolo Bonzini 
vscsi_handle_srp_req(VSCSIState * s,vscsi_req * req)92453a55002SPaolo Bonzini static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req)
92553a55002SPaolo Bonzini {
92681e70549SPhilippe Mathieu-Daudé     union srp_iu *srp = &req_iu(req)->srp;
92753a55002SPaolo Bonzini     int done = 1;
92853a55002SPaolo Bonzini     uint8_t opcode = srp->rsp.opcode;
92953a55002SPaolo Bonzini 
93053a55002SPaolo Bonzini     switch (opcode) {
93153a55002SPaolo Bonzini     case SRP_LOGIN_REQ:
93253a55002SPaolo Bonzini         vscsi_process_login(s, req);
93353a55002SPaolo Bonzini         break;
93453a55002SPaolo Bonzini     case SRP_TSK_MGMT:
93553a55002SPaolo Bonzini         done = vscsi_process_tsk_mgmt(s, req);
93653a55002SPaolo Bonzini         break;
93753a55002SPaolo Bonzini     case SRP_CMD:
93853a55002SPaolo Bonzini         done = vscsi_queue_cmd(s, req);
93953a55002SPaolo Bonzini         break;
94053a55002SPaolo Bonzini     case SRP_LOGIN_RSP:
94153a55002SPaolo Bonzini     case SRP_I_LOGOUT:
94253a55002SPaolo Bonzini     case SRP_T_LOGOUT:
94353a55002SPaolo Bonzini     case SRP_RSP:
94453a55002SPaolo Bonzini     case SRP_CRED_REQ:
94553a55002SPaolo Bonzini     case SRP_CRED_RSP:
94653a55002SPaolo Bonzini     case SRP_AER_REQ:
94753a55002SPaolo Bonzini     case SRP_AER_RSP:
94853a55002SPaolo Bonzini         fprintf(stderr, "VSCSI: Unsupported opcode %02x\n", opcode);
94953a55002SPaolo Bonzini         break;
95053a55002SPaolo Bonzini     default:
95153a55002SPaolo Bonzini         fprintf(stderr, "VSCSI: Unknown type %02x\n", opcode);
95253a55002SPaolo Bonzini     }
95353a55002SPaolo Bonzini 
95453a55002SPaolo Bonzini     return done;
95553a55002SPaolo Bonzini }
95653a55002SPaolo Bonzini 
vscsi_send_adapter_info(VSCSIState * s,vscsi_req * req)95753a55002SPaolo Bonzini static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req)
95853a55002SPaolo Bonzini {
95953a55002SPaolo Bonzini     struct viosrp_adapter_info *sinfo;
96053a55002SPaolo Bonzini     struct mad_adapter_info_data info;
96153a55002SPaolo Bonzini     int rc;
96253a55002SPaolo Bonzini 
96381e70549SPhilippe Mathieu-Daudé     sinfo = &req_iu(req)->mad.adapter_info;
96453a55002SPaolo Bonzini 
96553a55002SPaolo Bonzini #if 0 /* What for ? */
96653a55002SPaolo Bonzini     rc = spapr_vio_dma_read(&s->vdev, be64_to_cpu(sinfo->buffer),
96753a55002SPaolo Bonzini                             &info, be16_to_cpu(sinfo->common.length));
96853a55002SPaolo Bonzini     if (rc) {
96953a55002SPaolo Bonzini         fprintf(stderr, "vscsi_send_adapter_info: DMA read failure !\n");
97053a55002SPaolo Bonzini     }
97153a55002SPaolo Bonzini #endif
97253a55002SPaolo Bonzini     memset(&info, 0, sizeof(info));
97353a55002SPaolo Bonzini     strcpy(info.srp_version, SRP_VERSION);
97453a55002SPaolo Bonzini     memcpy(info.partition_name, "qemu", sizeof("qemu"));
97553a55002SPaolo Bonzini     info.partition_number = cpu_to_be32(0);
97653a55002SPaolo Bonzini     info.mad_version = cpu_to_be32(1);
97753a55002SPaolo Bonzini     info.os_type = cpu_to_be32(2);
97853a55002SPaolo Bonzini     info.port_max_txu[0] = cpu_to_be32(VSCSI_MAX_SECTORS << 9);
97953a55002SPaolo Bonzini 
98053a55002SPaolo Bonzini     rc = spapr_vio_dma_write(&s->vdev, be64_to_cpu(sinfo->buffer),
98153a55002SPaolo Bonzini                              &info, be16_to_cpu(sinfo->common.length));
98253a55002SPaolo Bonzini     if (rc)  {
98353a55002SPaolo Bonzini         fprintf(stderr, "vscsi_send_adapter_info: DMA write failure !\n");
98453a55002SPaolo Bonzini     }
98553a55002SPaolo Bonzini 
98653a55002SPaolo Bonzini     sinfo->common.status = rc ? cpu_to_be32(1) : 0;
98753a55002SPaolo Bonzini 
98853a55002SPaolo Bonzini     return vscsi_send_iu(s, req, sizeof(*sinfo), VIOSRP_MAD_FORMAT);
98953a55002SPaolo Bonzini }
99053a55002SPaolo Bonzini 
vscsi_send_capabilities(VSCSIState * s,vscsi_req * req)99126573a0cSNikunj A. Dadhania static int vscsi_send_capabilities(VSCSIState *s, vscsi_req *req)
99226573a0cSNikunj A. Dadhania {
99326573a0cSNikunj A. Dadhania     struct viosrp_capabilities *vcap;
99426573a0cSNikunj A. Dadhania     struct capabilities cap = { };
99526573a0cSNikunj A. Dadhania     uint16_t len, req_len;
99626573a0cSNikunj A. Dadhania     uint64_t buffer;
99726573a0cSNikunj A. Dadhania     int rc;
99826573a0cSNikunj A. Dadhania 
99981e70549SPhilippe Mathieu-Daudé     vcap = &req_iu(req)->mad.capabilities;
100026573a0cSNikunj A. Dadhania     req_len = len = be16_to_cpu(vcap->common.length);
100126573a0cSNikunj A. Dadhania     buffer = be64_to_cpu(vcap->buffer);
100226573a0cSNikunj A. Dadhania     if (len > sizeof(cap)) {
100326573a0cSNikunj A. Dadhania         fprintf(stderr, "vscsi_send_capabilities: capabilities size mismatch !\n");
100426573a0cSNikunj A. Dadhania 
100526573a0cSNikunj A. Dadhania         /*
100626573a0cSNikunj A. Dadhania          * Just read and populate the structure that is known.
100726573a0cSNikunj A. Dadhania          * Zero rest of the structure.
100826573a0cSNikunj A. Dadhania          */
100926573a0cSNikunj A. Dadhania         len = sizeof(cap);
101026573a0cSNikunj A. Dadhania     }
101126573a0cSNikunj A. Dadhania     rc = spapr_vio_dma_read(&s->vdev, buffer, &cap, len);
101226573a0cSNikunj A. Dadhania     if (rc)  {
101326573a0cSNikunj A. Dadhania         fprintf(stderr, "vscsi_send_capabilities: DMA read failure !\n");
101426573a0cSNikunj A. Dadhania     }
101526573a0cSNikunj A. Dadhania 
101626573a0cSNikunj A. Dadhania     /*
1017118d4ed0SDr. David Alan Gilbert      * Current implementation does not support any migration or
101826573a0cSNikunj A. Dadhania      * reservation capabilities. Construct the response telling the
101926573a0cSNikunj A. Dadhania      * guest not to use them.
102026573a0cSNikunj A. Dadhania      */
102126573a0cSNikunj A. Dadhania     cap.flags = 0;
102226573a0cSNikunj A. Dadhania     cap.migration.ecl = 0;
102326573a0cSNikunj A. Dadhania     cap.reserve.type = 0;
102426573a0cSNikunj A. Dadhania     cap.migration.common.server_support = 0;
102526573a0cSNikunj A. Dadhania     cap.reserve.common.server_support = 0;
102626573a0cSNikunj A. Dadhania 
102726573a0cSNikunj A. Dadhania     rc = spapr_vio_dma_write(&s->vdev, buffer, &cap, len);
102826573a0cSNikunj A. Dadhania     if (rc)  {
102926573a0cSNikunj A. Dadhania         fprintf(stderr, "vscsi_send_capabilities: DMA write failure !\n");
103026573a0cSNikunj A. Dadhania     }
103126573a0cSNikunj A. Dadhania     if (req_len > len) {
103226573a0cSNikunj A. Dadhania         /*
103326573a0cSNikunj A. Dadhania          * Being paranoid and lets not worry about the error code
103426573a0cSNikunj A. Dadhania          * here. Actual write of the cap is done above.
103526573a0cSNikunj A. Dadhania          */
103626573a0cSNikunj A. Dadhania         spapr_vio_dma_set(&s->vdev, (buffer + len), 0, (req_len - len));
103726573a0cSNikunj A. Dadhania     }
103826573a0cSNikunj A. Dadhania     vcap->common.status = rc ? cpu_to_be32(1) : 0;
103926573a0cSNikunj A. Dadhania     return vscsi_send_iu(s, req, sizeof(*vcap), VIOSRP_MAD_FORMAT);
104026573a0cSNikunj A. Dadhania }
104126573a0cSNikunj A. Dadhania 
vscsi_handle_mad_req(VSCSIState * s,vscsi_req * req)104253a55002SPaolo Bonzini static int vscsi_handle_mad_req(VSCSIState *s, vscsi_req *req)
104353a55002SPaolo Bonzini {
104481e70549SPhilippe Mathieu-Daudé     union mad_iu *mad = &req_iu(req)->mad;
1045f4ff3b7bSAlexey Kardashevskiy     bool request_handled = false;
1046f4ff3b7bSAlexey Kardashevskiy     uint64_t retlen = 0;
104753a55002SPaolo Bonzini 
104853a55002SPaolo Bonzini     switch (be32_to_cpu(mad->empty_iu.common.type)) {
104953a55002SPaolo Bonzini     case VIOSRP_EMPTY_IU_TYPE:
105053a55002SPaolo Bonzini         fprintf(stderr, "Unsupported EMPTY MAD IU\n");
1051f4ff3b7bSAlexey Kardashevskiy         retlen = sizeof(mad->empty_iu);
105253a55002SPaolo Bonzini         break;
105353a55002SPaolo Bonzini     case VIOSRP_ERROR_LOG_TYPE:
105453a55002SPaolo Bonzini         fprintf(stderr, "Unsupported ERROR LOG MAD IU\n");
1055f4ff3b7bSAlexey Kardashevskiy         retlen = sizeof(mad->error_log);
105653a55002SPaolo Bonzini         break;
105753a55002SPaolo Bonzini     case VIOSRP_ADAPTER_INFO_TYPE:
105853a55002SPaolo Bonzini         vscsi_send_adapter_info(s, req);
1059f4ff3b7bSAlexey Kardashevskiy         request_handled = true;
106053a55002SPaolo Bonzini         break;
106153a55002SPaolo Bonzini     case VIOSRP_HOST_CONFIG_TYPE:
1062f4ff3b7bSAlexey Kardashevskiy         retlen = sizeof(mad->host_config);
106353a55002SPaolo Bonzini         break;
106426573a0cSNikunj A. Dadhania     case VIOSRP_CAPABILITIES_TYPE:
106526573a0cSNikunj A. Dadhania         vscsi_send_capabilities(s, req);
1066f4ff3b7bSAlexey Kardashevskiy         request_handled = true;
106726573a0cSNikunj A. Dadhania         break;
106853a55002SPaolo Bonzini     default:
106953a55002SPaolo Bonzini         fprintf(stderr, "VSCSI: Unknown MAD type %02x\n",
107053a55002SPaolo Bonzini                 be32_to_cpu(mad->empty_iu.common.type));
1071f4ff3b7bSAlexey Kardashevskiy         /*
1072f4ff3b7bSAlexey Kardashevskiy          * PAPR+ says that "The length field is set to the length
1073f4ff3b7bSAlexey Kardashevskiy          * of the data structure(s) used in the command".
1074f4ff3b7bSAlexey Kardashevskiy          * As we did not recognize the request type, put zero there.
1075f4ff3b7bSAlexey Kardashevskiy          */
1076f4ff3b7bSAlexey Kardashevskiy         retlen = 0;
1077f4ff3b7bSAlexey Kardashevskiy     }
1078f4ff3b7bSAlexey Kardashevskiy 
1079f4ff3b7bSAlexey Kardashevskiy     if (!request_handled) {
1080f4ff3b7bSAlexey Kardashevskiy         mad->empty_iu.common.status = cpu_to_be16(VIOSRP_MAD_NOT_SUPPORTED);
1081f4ff3b7bSAlexey Kardashevskiy         vscsi_send_iu(s, req, retlen, VIOSRP_MAD_FORMAT);
108253a55002SPaolo Bonzini     }
108353a55002SPaolo Bonzini 
108453a55002SPaolo Bonzini     return 1;
108553a55002SPaolo Bonzini }
108653a55002SPaolo Bonzini 
vscsi_got_payload(VSCSIState * s,vscsi_crq * crq)108753a55002SPaolo Bonzini static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
108853a55002SPaolo Bonzini {
108953a55002SPaolo Bonzini     vscsi_req *req;
109053a55002SPaolo Bonzini     int done;
109153a55002SPaolo Bonzini 
109253a55002SPaolo Bonzini     req = vscsi_get_req(s);
109353a55002SPaolo Bonzini     if (req == NULL) {
109453a55002SPaolo Bonzini         fprintf(stderr, "VSCSI: Failed to get a request !\n");
109553a55002SPaolo Bonzini         return;
109653a55002SPaolo Bonzini     }
109753a55002SPaolo Bonzini 
109853a55002SPaolo Bonzini     /* We only support a limited number of descriptors, we know
109953a55002SPaolo Bonzini      * the ibmvscsi driver uses up to 10 max, so it should fit
110053a55002SPaolo Bonzini      * in our 256 bytes IUs. If not we'll have to increase the size
110153a55002SPaolo Bonzini      * of the structure.
110253a55002SPaolo Bonzini      */
11030dc55698SPhilippe Mathieu-Daudé     if (crq->s.IU_length > SRP_MAX_IU_LEN) {
110453a55002SPaolo Bonzini         fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n",
110553a55002SPaolo Bonzini                 crq->s.IU_length);
110653a55002SPaolo Bonzini         vscsi_put_req(req);
110753a55002SPaolo Bonzini         return;
110853a55002SPaolo Bonzini     }
110953a55002SPaolo Bonzini 
111053a55002SPaolo Bonzini     /* XXX Handle failure differently ? */
1111ff78b728SPhilippe Mathieu-Daudé     if (spapr_vio_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->viosrp_iu_buf,
111253a55002SPaolo Bonzini                            crq->s.IU_length)) {
111353a55002SPaolo Bonzini         fprintf(stderr, "vscsi_got_payload: DMA read failure !\n");
111453a55002SPaolo Bonzini         vscsi_put_req(req);
111553a55002SPaolo Bonzini         return;
111653a55002SPaolo Bonzini     }
111753a55002SPaolo Bonzini     memcpy(&req->crq, crq, sizeof(vscsi_crq));
111853a55002SPaolo Bonzini 
111953a55002SPaolo Bonzini     if (crq->s.format == VIOSRP_MAD_FORMAT) {
112053a55002SPaolo Bonzini         done = vscsi_handle_mad_req(s, req);
112153a55002SPaolo Bonzini     } else {
112253a55002SPaolo Bonzini         done = vscsi_handle_srp_req(s, req);
112353a55002SPaolo Bonzini     }
112453a55002SPaolo Bonzini 
112553a55002SPaolo Bonzini     if (done) {
112653a55002SPaolo Bonzini         vscsi_put_req(req);
112753a55002SPaolo Bonzini     }
112853a55002SPaolo Bonzini }
112953a55002SPaolo Bonzini 
113053a55002SPaolo Bonzini 
vscsi_do_crq(struct SpaprVioDevice * dev,uint8_t * crq_data)1131ce2918cbSDavid Gibson static int vscsi_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data)
113253a55002SPaolo Bonzini {
1133fd506b4fSDavid Gibson     VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
113453a55002SPaolo Bonzini     vscsi_crq crq;
113553a55002SPaolo Bonzini 
113653a55002SPaolo Bonzini     memcpy(crq.raw, crq_data, 16);
113753a55002SPaolo Bonzini     crq.s.timeout = be16_to_cpu(crq.s.timeout);
113853a55002SPaolo Bonzini     crq.s.IU_length = be16_to_cpu(crq.s.IU_length);
113953a55002SPaolo Bonzini     crq.s.IU_data_ptr = be64_to_cpu(crq.s.IU_data_ptr);
114053a55002SPaolo Bonzini 
1141f19661c8SLaurent Vivier     trace_spapr_vscsi_do_crq(crq.raw[0], crq.raw[1]);
114253a55002SPaolo Bonzini 
114353a55002SPaolo Bonzini     switch (crq.s.valid) {
114453a55002SPaolo Bonzini     case 0xc0: /* Init command/response */
114553a55002SPaolo Bonzini 
114653a55002SPaolo Bonzini         /* Respond to initialization request */
114753a55002SPaolo Bonzini         if (crq.s.format == 0x01) {
114853a55002SPaolo Bonzini             memset(crq.raw, 0, 16);
114953a55002SPaolo Bonzini             crq.s.valid = 0xc0;
115053a55002SPaolo Bonzini             crq.s.format = 0x02;
115153a55002SPaolo Bonzini             spapr_vio_send_crq(dev, crq.raw);
115253a55002SPaolo Bonzini         }
115353a55002SPaolo Bonzini 
115453a55002SPaolo Bonzini         /* Note that in hotplug cases, we might get a 0x02
115553a55002SPaolo Bonzini          * as a result of us emitting the init request
115653a55002SPaolo Bonzini          */
115753a55002SPaolo Bonzini 
115853a55002SPaolo Bonzini         break;
115953a55002SPaolo Bonzini     case 0xff: /* Link event */
116053a55002SPaolo Bonzini 
116153a55002SPaolo Bonzini         /* Not handled for now */
116253a55002SPaolo Bonzini 
116353a55002SPaolo Bonzini         break;
116453a55002SPaolo Bonzini     case 0x80: /* Payloads */
116553a55002SPaolo Bonzini         switch (crq.s.format) {
116653a55002SPaolo Bonzini         case VIOSRP_SRP_FORMAT: /* AKA VSCSI request */
116753a55002SPaolo Bonzini         case VIOSRP_MAD_FORMAT: /* AKA VSCSI response */
116853a55002SPaolo Bonzini             vscsi_got_payload(s, &crq);
116953a55002SPaolo Bonzini             break;
117053a55002SPaolo Bonzini         case VIOSRP_OS400_FORMAT:
117153a55002SPaolo Bonzini         case VIOSRP_AIX_FORMAT:
117253a55002SPaolo Bonzini         case VIOSRP_LINUX_FORMAT:
117353a55002SPaolo Bonzini         case VIOSRP_INLINE_FORMAT:
117453a55002SPaolo Bonzini             fprintf(stderr, "vscsi_do_srq: Unsupported payload format %02x\n",
117553a55002SPaolo Bonzini                     crq.s.format);
117653a55002SPaolo Bonzini             break;
117753a55002SPaolo Bonzini         default:
117853a55002SPaolo Bonzini             fprintf(stderr, "vscsi_do_srq: Unknown payload format %02x\n",
117953a55002SPaolo Bonzini                     crq.s.format);
118053a55002SPaolo Bonzini         }
118153a55002SPaolo Bonzini         break;
118253a55002SPaolo Bonzini     default:
118353a55002SPaolo Bonzini         fprintf(stderr, "vscsi_do_crq: unknown CRQ %02x %02x ...\n",
118453a55002SPaolo Bonzini                 crq.raw[0], crq.raw[1]);
118553a55002SPaolo Bonzini     };
118653a55002SPaolo Bonzini 
118753a55002SPaolo Bonzini     return 0;
118853a55002SPaolo Bonzini }
118953a55002SPaolo Bonzini 
119053a55002SPaolo Bonzini static const struct SCSIBusInfo vscsi_scsi_info = {
119153a55002SPaolo Bonzini     .tcq = true,
119253a55002SPaolo Bonzini     .max_channel = 7, /* logical unit addressing format */
119353a55002SPaolo Bonzini     .max_target = 63,
119453a55002SPaolo Bonzini     .max_lun = 31,
119553a55002SPaolo Bonzini 
119653a55002SPaolo Bonzini     .transfer_data = vscsi_transfer_data,
119753a55002SPaolo Bonzini     .complete = vscsi_command_complete,
11981168ec7dSDavid Gibson     .cancel = vscsi_request_cancelled,
11991168ec7dSDavid Gibson     .save_request = vscsi_save_request,
12001168ec7dSDavid Gibson     .load_request = vscsi_load_request,
120153a55002SPaolo Bonzini };
120253a55002SPaolo Bonzini 
spapr_vscsi_reset(SpaprVioDevice * dev)1203ce2918cbSDavid Gibson static void spapr_vscsi_reset(SpaprVioDevice *dev)
120453a55002SPaolo Bonzini {
1205fd506b4fSDavid Gibson     VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
120653a55002SPaolo Bonzini     int i;
120753a55002SPaolo Bonzini 
120853a55002SPaolo Bonzini     memset(s->reqs, 0, sizeof(s->reqs));
120953a55002SPaolo Bonzini     for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
121053a55002SPaolo Bonzini         s->reqs[i].qtag = i;
121153a55002SPaolo Bonzini     }
121253a55002SPaolo Bonzini }
121353a55002SPaolo Bonzini 
spapr_vscsi_realize(SpaprVioDevice * dev,Error ** errp)1214ce2918cbSDavid Gibson static void spapr_vscsi_realize(SpaprVioDevice *dev, Error **errp)
121553a55002SPaolo Bonzini {
1216fd506b4fSDavid Gibson     VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
121753a55002SPaolo Bonzini 
121853a55002SPaolo Bonzini     dev->crq.SendFunc = vscsi_do_crq;
121953a55002SPaolo Bonzini 
1220739e95f5SPeter Maydell     scsi_bus_init(&s->bus, sizeof(s->bus), DEVICE(dev), &vscsi_scsi_info);
122164dbe2c8SDaniel Henrique Barboza 
122264dbe2c8SDaniel Henrique Barboza     /* ibmvscsi SCSI bus does not allow hotplug. */
122364dbe2c8SDaniel Henrique Barboza     qbus_set_hotplug_handler(BUS(&s->bus), NULL);
122453a55002SPaolo Bonzini }
122553a55002SPaolo Bonzini 
spapr_vscsi_create(SpaprVioBus * bus)1226ce2918cbSDavid Gibson void spapr_vscsi_create(SpaprVioBus *bus)
122753a55002SPaolo Bonzini {
122853a55002SPaolo Bonzini     DeviceState *dev;
122953a55002SPaolo Bonzini 
12303e80f690SMarkus Armbruster     dev = qdev_new("spapr-vscsi");
123153a55002SPaolo Bonzini 
12323e80f690SMarkus Armbruster     qdev_realize_and_unref(dev, &bus->bus, &error_fatal);
123314545097SThomas Huth     scsi_bus_legacy_handle_cmdline(&VIO_SPAPR_VSCSI_DEVICE(dev)->bus);
123453a55002SPaolo Bonzini }
123553a55002SPaolo Bonzini 
spapr_vscsi_devnode(SpaprVioDevice * dev,void * fdt,int node_off)1236ce2918cbSDavid Gibson static int spapr_vscsi_devnode(SpaprVioDevice *dev, void *fdt, int node_off)
123753a55002SPaolo Bonzini {
123853a55002SPaolo Bonzini     int ret;
123953a55002SPaolo Bonzini 
124053a55002SPaolo Bonzini     ret = fdt_setprop_cell(fdt, node_off, "#address-cells", 2);
124153a55002SPaolo Bonzini     if (ret < 0) {
124253a55002SPaolo Bonzini         return ret;
124353a55002SPaolo Bonzini     }
124453a55002SPaolo Bonzini 
124553a55002SPaolo Bonzini     ret = fdt_setprop_cell(fdt, node_off, "#size-cells", 0);
124653a55002SPaolo Bonzini     if (ret < 0) {
124753a55002SPaolo Bonzini         return ret;
124853a55002SPaolo Bonzini     }
124953a55002SPaolo Bonzini 
125053a55002SPaolo Bonzini     return 0;
125153a55002SPaolo Bonzini }
125253a55002SPaolo Bonzini 
125353a55002SPaolo Bonzini static Property spapr_vscsi_properties[] = {
125453a55002SPaolo Bonzini     DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev),
125553a55002SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
125653a55002SPaolo Bonzini };
125753a55002SPaolo Bonzini 
12581168ec7dSDavid Gibson static const VMStateDescription vmstate_spapr_vscsi = {
12591168ec7dSDavid Gibson     .name = "spapr_vscsi",
12601168ec7dSDavid Gibson     .version_id = 1,
12611168ec7dSDavid Gibson     .minimum_version_id = 1,
1262*2d7b39a6SRichard Henderson     .fields = (const VMStateField[]) {
12631168ec7dSDavid Gibson         VMSTATE_SPAPR_VIO(vdev, VSCSIState),
12641168ec7dSDavid Gibson         /* VSCSI state */
12651168ec7dSDavid Gibson         /* ???? */
12661168ec7dSDavid Gibson 
12671168ec7dSDavid Gibson         VMSTATE_END_OF_LIST()
12681168ec7dSDavid Gibson     },
12691168ec7dSDavid Gibson };
12701168ec7dSDavid Gibson 
spapr_vscsi_class_init(ObjectClass * klass,void * data)127153a55002SPaolo Bonzini static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
127253a55002SPaolo Bonzini {
127353a55002SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
1274ce2918cbSDavid Gibson     SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
127553a55002SPaolo Bonzini 
127628b07e73SMarkus Armbruster     k->realize = spapr_vscsi_realize;
127753a55002SPaolo Bonzini     k->reset = spapr_vscsi_reset;
127853a55002SPaolo Bonzini     k->devnode = spapr_vscsi_devnode;
127953a55002SPaolo Bonzini     k->dt_name = "v-scsi";
128053a55002SPaolo Bonzini     k->dt_type = "vscsi";
128153a55002SPaolo Bonzini     k->dt_compatible = "IBM,v-scsi";
128253a55002SPaolo Bonzini     k->signal_mask = 0x00000001;
128329fdedfeSAlexey Kardashevskiy     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
12844f67d30bSMarc-André Lureau     device_class_set_props(dc, spapr_vscsi_properties);
128553a55002SPaolo Bonzini     k->rtce_window_size = 0x10000000;
12861168ec7dSDavid Gibson     dc->vmsd = &vmstate_spapr_vscsi;
128753a55002SPaolo Bonzini }
128853a55002SPaolo Bonzini 
128953a55002SPaolo Bonzini static const TypeInfo spapr_vscsi_info = {
1290fd506b4fSDavid Gibson     .name          = TYPE_VIO_SPAPR_VSCSI_DEVICE,
129153a55002SPaolo Bonzini     .parent        = TYPE_VIO_SPAPR_DEVICE,
129253a55002SPaolo Bonzini     .instance_size = sizeof(VSCSIState),
129353a55002SPaolo Bonzini     .class_init    = spapr_vscsi_class_init,
129453a55002SPaolo Bonzini };
129553a55002SPaolo Bonzini 
spapr_vscsi_register_types(void)129653a55002SPaolo Bonzini static void spapr_vscsi_register_types(void)
129753a55002SPaolo Bonzini {
129853a55002SPaolo Bonzini     type_register_static(&spapr_vscsi_info);
129953a55002SPaolo Bonzini }
130053a55002SPaolo Bonzini 
130153a55002SPaolo Bonzini type_init(spapr_vscsi_register_types)
1302