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