xref: /openbmc/qemu/hw/scsi/mptconfig.c (revision e351b826)
1*e351b826SPaolo Bonzini /*
2*e351b826SPaolo Bonzini  * QEMU LSI SAS1068 Host Bus Adapter emulation - configuration pages
3*e351b826SPaolo Bonzini  *
4*e351b826SPaolo Bonzini  * Copyright (c) 2016 Red Hat, Inc.
5*e351b826SPaolo Bonzini  *
6*e351b826SPaolo Bonzini  * Author: Paolo Bonzini
7*e351b826SPaolo Bonzini  *
8*e351b826SPaolo Bonzini  * This library is free software; you can redistribute it and/or
9*e351b826SPaolo Bonzini  * modify it under the terms of the GNU Lesser General Public
10*e351b826SPaolo Bonzini  * License as published by the Free Software Foundation; either
11*e351b826SPaolo Bonzini  * version 2 of the License, or (at your option) any later version.
12*e351b826SPaolo Bonzini  *
13*e351b826SPaolo Bonzini  * This library is distributed in the hope that it will be useful,
14*e351b826SPaolo Bonzini  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*e351b826SPaolo Bonzini  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16*e351b826SPaolo Bonzini  * Lesser General Public License for more details.
17*e351b826SPaolo Bonzini  */
18*e351b826SPaolo Bonzini #include "qemu/osdep.h"
19*e351b826SPaolo Bonzini #include "hw/hw.h"
20*e351b826SPaolo Bonzini #include "hw/pci/pci.h"
21*e351b826SPaolo Bonzini #include "hw/scsi/scsi.h"
22*e351b826SPaolo Bonzini 
23*e351b826SPaolo Bonzini #include "mptsas.h"
24*e351b826SPaolo Bonzini #include "mpi.h"
25*e351b826SPaolo Bonzini #include "trace.h"
26*e351b826SPaolo Bonzini 
27*e351b826SPaolo Bonzini /* Generic functions for marshaling and unmarshaling.  */
28*e351b826SPaolo Bonzini 
29*e351b826SPaolo Bonzini #define repl1(x) x
30*e351b826SPaolo Bonzini #define repl2(x) x x
31*e351b826SPaolo Bonzini #define repl3(x) x x x
32*e351b826SPaolo Bonzini #define repl4(x) x x x x
33*e351b826SPaolo Bonzini #define repl5(x) x x x x x
34*e351b826SPaolo Bonzini #define repl6(x) x x x x x x
35*e351b826SPaolo Bonzini #define repl7(x) x x x x x x x
36*e351b826SPaolo Bonzini #define repl8(x) x x x x x x x x
37*e351b826SPaolo Bonzini 
38*e351b826SPaolo Bonzini #define repl(n, x) glue(repl, n)(x)
39*e351b826SPaolo Bonzini 
40*e351b826SPaolo Bonzini typedef union PackValue {
41*e351b826SPaolo Bonzini     uint64_t ll;
42*e351b826SPaolo Bonzini     char *str;
43*e351b826SPaolo Bonzini } PackValue;
44*e351b826SPaolo Bonzini 
45*e351b826SPaolo Bonzini static size_t vfill(uint8_t *data, size_t size, const char *fmt, va_list ap)
46*e351b826SPaolo Bonzini {
47*e351b826SPaolo Bonzini     size_t ofs;
48*e351b826SPaolo Bonzini     PackValue val;
49*e351b826SPaolo Bonzini     const char *p;
50*e351b826SPaolo Bonzini 
51*e351b826SPaolo Bonzini     ofs = 0;
52*e351b826SPaolo Bonzini     p = fmt;
53*e351b826SPaolo Bonzini     while (*p) {
54*e351b826SPaolo Bonzini         memset(&val, 0, sizeof(val));
55*e351b826SPaolo Bonzini         switch (*p) {
56*e351b826SPaolo Bonzini         case '*':
57*e351b826SPaolo Bonzini             p++;
58*e351b826SPaolo Bonzini             break;
59*e351b826SPaolo Bonzini         case 'b':
60*e351b826SPaolo Bonzini         case 'w':
61*e351b826SPaolo Bonzini         case 'l':
62*e351b826SPaolo Bonzini             val.ll = va_arg(ap, int);
63*e351b826SPaolo Bonzini             break;
64*e351b826SPaolo Bonzini         case 'q':
65*e351b826SPaolo Bonzini             val.ll = va_arg(ap, int64_t);
66*e351b826SPaolo Bonzini             break;
67*e351b826SPaolo Bonzini         case 's':
68*e351b826SPaolo Bonzini             val.str = va_arg(ap, void *);
69*e351b826SPaolo Bonzini             break;
70*e351b826SPaolo Bonzini         }
71*e351b826SPaolo Bonzini         switch (*p++) {
72*e351b826SPaolo Bonzini         case 'b':
73*e351b826SPaolo Bonzini             if (data) {
74*e351b826SPaolo Bonzini                 stb_p(data + ofs, val.ll);
75*e351b826SPaolo Bonzini             }
76*e351b826SPaolo Bonzini             ofs++;
77*e351b826SPaolo Bonzini             break;
78*e351b826SPaolo Bonzini         case 'w':
79*e351b826SPaolo Bonzini             if (data) {
80*e351b826SPaolo Bonzini                 stw_le_p(data + ofs, val.ll);
81*e351b826SPaolo Bonzini             }
82*e351b826SPaolo Bonzini             ofs += 2;
83*e351b826SPaolo Bonzini             break;
84*e351b826SPaolo Bonzini         case 'l':
85*e351b826SPaolo Bonzini             if (data) {
86*e351b826SPaolo Bonzini                 stl_le_p(data + ofs, val.ll);
87*e351b826SPaolo Bonzini             }
88*e351b826SPaolo Bonzini             ofs += 4;
89*e351b826SPaolo Bonzini             break;
90*e351b826SPaolo Bonzini         case 'q':
91*e351b826SPaolo Bonzini             if (data) {
92*e351b826SPaolo Bonzini                 stq_le_p(data + ofs, val.ll);
93*e351b826SPaolo Bonzini             }
94*e351b826SPaolo Bonzini             ofs += 8;
95*e351b826SPaolo Bonzini             break;
96*e351b826SPaolo Bonzini         case 's':
97*e351b826SPaolo Bonzini             {
98*e351b826SPaolo Bonzini                 int cnt = atoi(p);
99*e351b826SPaolo Bonzini                 if (data) {
100*e351b826SPaolo Bonzini                     if (val.str) {
101*e351b826SPaolo Bonzini                         strncpy((void *)data + ofs, val.str, cnt);
102*e351b826SPaolo Bonzini                     } else {
103*e351b826SPaolo Bonzini                         memset((void *)data + ofs, 0, cnt);
104*e351b826SPaolo Bonzini                     }
105*e351b826SPaolo Bonzini                 }
106*e351b826SPaolo Bonzini                 ofs += cnt;
107*e351b826SPaolo Bonzini                 break;
108*e351b826SPaolo Bonzini             }
109*e351b826SPaolo Bonzini         }
110*e351b826SPaolo Bonzini     }
111*e351b826SPaolo Bonzini 
112*e351b826SPaolo Bonzini     return ofs;
113*e351b826SPaolo Bonzini }
114*e351b826SPaolo Bonzini 
115*e351b826SPaolo Bonzini static size_t vpack(uint8_t **p_data, const char *fmt, va_list ap1)
116*e351b826SPaolo Bonzini {
117*e351b826SPaolo Bonzini     size_t size = 0;
118*e351b826SPaolo Bonzini     uint8_t *data = NULL;
119*e351b826SPaolo Bonzini 
120*e351b826SPaolo Bonzini     if (p_data) {
121*e351b826SPaolo Bonzini         va_list ap2;
122*e351b826SPaolo Bonzini 
123*e351b826SPaolo Bonzini         va_copy(ap2, ap1);
124*e351b826SPaolo Bonzini         size = vfill(NULL, 0, fmt, ap2);
125*e351b826SPaolo Bonzini         *p_data = data = g_malloc(size);
126*e351b826SPaolo Bonzini     }
127*e351b826SPaolo Bonzini     return vfill(data, size, fmt, ap1);
128*e351b826SPaolo Bonzini }
129*e351b826SPaolo Bonzini 
130*e351b826SPaolo Bonzini static size_t fill(uint8_t *data, size_t size, const char *fmt, ...)
131*e351b826SPaolo Bonzini {
132*e351b826SPaolo Bonzini     va_list ap;
133*e351b826SPaolo Bonzini     size_t ret;
134*e351b826SPaolo Bonzini 
135*e351b826SPaolo Bonzini     va_start(ap, fmt);
136*e351b826SPaolo Bonzini     ret = vfill(data, size, fmt, ap);
137*e351b826SPaolo Bonzini     va_end(ap);
138*e351b826SPaolo Bonzini 
139*e351b826SPaolo Bonzini     return ret;
140*e351b826SPaolo Bonzini }
141*e351b826SPaolo Bonzini 
142*e351b826SPaolo Bonzini /* Functions to build the page header and fill in the length, always used
143*e351b826SPaolo Bonzini  * through the macros.
144*e351b826SPaolo Bonzini  */
145*e351b826SPaolo Bonzini 
146*e351b826SPaolo Bonzini #define MPTSAS_CONFIG_PACK(number, type, version, fmt, ...)                  \
147*e351b826SPaolo Bonzini     mptsas_config_pack(data, "b*bbb" fmt, version, number, type,             \
148*e351b826SPaolo Bonzini                        ## __VA_ARGS__)
149*e351b826SPaolo Bonzini 
150*e351b826SPaolo Bonzini static size_t mptsas_config_pack(uint8_t **data, const char *fmt, ...)
151*e351b826SPaolo Bonzini {
152*e351b826SPaolo Bonzini     va_list ap;
153*e351b826SPaolo Bonzini     size_t ret;
154*e351b826SPaolo Bonzini 
155*e351b826SPaolo Bonzini     va_start(ap, fmt);
156*e351b826SPaolo Bonzini     ret = vpack(data, fmt, ap);
157*e351b826SPaolo Bonzini     va_end(ap);
158*e351b826SPaolo Bonzini 
159*e351b826SPaolo Bonzini     if (data) {
160*e351b826SPaolo Bonzini         assert(ret < 256 && (ret % 4) == 0);
161*e351b826SPaolo Bonzini         stb_p(*data + 1, ret / 4);
162*e351b826SPaolo Bonzini     }
163*e351b826SPaolo Bonzini     return ret;
164*e351b826SPaolo Bonzini }
165*e351b826SPaolo Bonzini 
166*e351b826SPaolo Bonzini #define MPTSAS_CONFIG_PACK_EXT(number, type, version, fmt, ...)              \
167*e351b826SPaolo Bonzini     mptsas_config_pack_ext(data, "b*bbb*wb*b" fmt, version, number,          \
168*e351b826SPaolo Bonzini                            MPI_CONFIG_PAGETYPE_EXTENDED, type, ## __VA_ARGS__)
169*e351b826SPaolo Bonzini 
170*e351b826SPaolo Bonzini static size_t mptsas_config_pack_ext(uint8_t **data, const char *fmt, ...)
171*e351b826SPaolo Bonzini {
172*e351b826SPaolo Bonzini     va_list ap;
173*e351b826SPaolo Bonzini     size_t ret;
174*e351b826SPaolo Bonzini 
175*e351b826SPaolo Bonzini     va_start(ap, fmt);
176*e351b826SPaolo Bonzini     ret = vpack(data, fmt, ap);
177*e351b826SPaolo Bonzini     va_end(ap);
178*e351b826SPaolo Bonzini 
179*e351b826SPaolo Bonzini     if (data) {
180*e351b826SPaolo Bonzini         assert(ret < 65536 && (ret % 4) == 0);
181*e351b826SPaolo Bonzini         stw_le_p(*data + 4, ret / 4);
182*e351b826SPaolo Bonzini     }
183*e351b826SPaolo Bonzini     return ret;
184*e351b826SPaolo Bonzini }
185*e351b826SPaolo Bonzini 
186*e351b826SPaolo Bonzini /* Manufacturing pages */
187*e351b826SPaolo Bonzini 
188*e351b826SPaolo Bonzini static
189*e351b826SPaolo Bonzini size_t mptsas_config_manufacturing_0(MPTSASState *s, uint8_t **data, int address)
190*e351b826SPaolo Bonzini {
191*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
192*e351b826SPaolo Bonzini                               "s16s8s16s16s16",
193*e351b826SPaolo Bonzini                               "QEMU MPT Fusion",
194*e351b826SPaolo Bonzini                               "2.5",
195*e351b826SPaolo Bonzini                               "QEMU MPT Fusion",
196*e351b826SPaolo Bonzini                               "QEMU",
197*e351b826SPaolo Bonzini                               "0000111122223333");
198*e351b826SPaolo Bonzini }
199*e351b826SPaolo Bonzini 
200*e351b826SPaolo Bonzini static
201*e351b826SPaolo Bonzini size_t mptsas_config_manufacturing_1(MPTSASState *s, uint8_t **data, int address)
202*e351b826SPaolo Bonzini {
203*e351b826SPaolo Bonzini     /* VPD - all zeros */
204*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
205*e351b826SPaolo Bonzini                               "s256");
206*e351b826SPaolo Bonzini }
207*e351b826SPaolo Bonzini 
208*e351b826SPaolo Bonzini static
209*e351b826SPaolo Bonzini size_t mptsas_config_manufacturing_2(MPTSASState *s, uint8_t **data, int address)
210*e351b826SPaolo Bonzini {
211*e351b826SPaolo Bonzini     PCIDeviceClass *pcic = PCI_DEVICE_GET_CLASS(s);
212*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
213*e351b826SPaolo Bonzini                               "wb*b*l",
214*e351b826SPaolo Bonzini                               pcic->device_id, pcic->revision);
215*e351b826SPaolo Bonzini }
216*e351b826SPaolo Bonzini 
217*e351b826SPaolo Bonzini static
218*e351b826SPaolo Bonzini size_t mptsas_config_manufacturing_3(MPTSASState *s, uint8_t **data, int address)
219*e351b826SPaolo Bonzini {
220*e351b826SPaolo Bonzini     PCIDeviceClass *pcic = PCI_DEVICE_GET_CLASS(s);
221*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
222*e351b826SPaolo Bonzini                               "wb*b*l",
223*e351b826SPaolo Bonzini                               pcic->device_id, pcic->revision);
224*e351b826SPaolo Bonzini }
225*e351b826SPaolo Bonzini 
226*e351b826SPaolo Bonzini static
227*e351b826SPaolo Bonzini size_t mptsas_config_manufacturing_4(MPTSASState *s, uint8_t **data, int address)
228*e351b826SPaolo Bonzini {
229*e351b826SPaolo Bonzini     /* All zeros */
230*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x05,
231*e351b826SPaolo Bonzini                               "*l*b*b*b*b*b*b*w*s56*l*l*l*l*l*l"
232*e351b826SPaolo Bonzini                               "*b*b*w*b*b*w*l*l");
233*e351b826SPaolo Bonzini }
234*e351b826SPaolo Bonzini 
235*e351b826SPaolo Bonzini static
236*e351b826SPaolo Bonzini size_t mptsas_config_manufacturing_5(MPTSASState *s, uint8_t **data, int address)
237*e351b826SPaolo Bonzini {
238*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(5, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x02,
239*e351b826SPaolo Bonzini                               "q*b*b*w*l*l", s->sas_addr);
240*e351b826SPaolo Bonzini }
241*e351b826SPaolo Bonzini 
242*e351b826SPaolo Bonzini static
243*e351b826SPaolo Bonzini size_t mptsas_config_manufacturing_6(MPTSASState *s, uint8_t **data, int address)
244*e351b826SPaolo Bonzini {
245*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(6, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
246*e351b826SPaolo Bonzini                               "*l");
247*e351b826SPaolo Bonzini }
248*e351b826SPaolo Bonzini 
249*e351b826SPaolo Bonzini static
250*e351b826SPaolo Bonzini size_t mptsas_config_manufacturing_7(MPTSASState *s, uint8_t **data, int address)
251*e351b826SPaolo Bonzini {
252*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(7, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
253*e351b826SPaolo Bonzini                               "*l*l*l*s16*b*b*w", MPTSAS_NUM_PORTS);
254*e351b826SPaolo Bonzini }
255*e351b826SPaolo Bonzini 
256*e351b826SPaolo Bonzini static
257*e351b826SPaolo Bonzini size_t mptsas_config_manufacturing_8(MPTSASState *s, uint8_t **data, int address)
258*e351b826SPaolo Bonzini {
259*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(8, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
260*e351b826SPaolo Bonzini                               "*l");
261*e351b826SPaolo Bonzini }
262*e351b826SPaolo Bonzini 
263*e351b826SPaolo Bonzini static
264*e351b826SPaolo Bonzini size_t mptsas_config_manufacturing_9(MPTSASState *s, uint8_t **data, int address)
265*e351b826SPaolo Bonzini {
266*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(9, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
267*e351b826SPaolo Bonzini                               "*l");
268*e351b826SPaolo Bonzini }
269*e351b826SPaolo Bonzini 
270*e351b826SPaolo Bonzini static
271*e351b826SPaolo Bonzini size_t mptsas_config_manufacturing_10(MPTSASState *s, uint8_t **data, int address)
272*e351b826SPaolo Bonzini {
273*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(10, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00,
274*e351b826SPaolo Bonzini                               "*l");
275*e351b826SPaolo Bonzini }
276*e351b826SPaolo Bonzini 
277*e351b826SPaolo Bonzini /* I/O unit pages */
278*e351b826SPaolo Bonzini 
279*e351b826SPaolo Bonzini static
280*e351b826SPaolo Bonzini size_t mptsas_config_io_unit_0(MPTSASState *s, uint8_t **data, int address)
281*e351b826SPaolo Bonzini {
282*e351b826SPaolo Bonzini     PCIDevice *pci = PCI_DEVICE(s);
283*e351b826SPaolo Bonzini     uint64_t unique_value = 0x53504D554D4551LL;  /* "QEMUMPTx" */
284*e351b826SPaolo Bonzini 
285*e351b826SPaolo Bonzini     unique_value |= (uint64_t)pci->devfn << 56;
286*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x00,
287*e351b826SPaolo Bonzini                               "q", unique_value);
288*e351b826SPaolo Bonzini }
289*e351b826SPaolo Bonzini 
290*e351b826SPaolo Bonzini static
291*e351b826SPaolo Bonzini size_t mptsas_config_io_unit_1(MPTSASState *s, uint8_t **data, int address)
292*e351b826SPaolo Bonzini {
293*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x02, "l",
294*e351b826SPaolo Bonzini                               0x41 /* single function, RAID disabled */ );
295*e351b826SPaolo Bonzini }
296*e351b826SPaolo Bonzini 
297*e351b826SPaolo Bonzini static
298*e351b826SPaolo Bonzini size_t mptsas_config_io_unit_2(MPTSASState *s, uint8_t **data, int address)
299*e351b826SPaolo Bonzini {
300*e351b826SPaolo Bonzini     PCIDevice *pci = PCI_DEVICE(s);
301*e351b826SPaolo Bonzini     uint8_t devfn = pci->devfn;
302*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x02,
303*e351b826SPaolo Bonzini                               "llbbw*b*b*w*b*b*w*b*b*w*l",
304*e351b826SPaolo Bonzini                               0, 0x100, 0 /* pci bus? */, devfn, 0);
305*e351b826SPaolo Bonzini }
306*e351b826SPaolo Bonzini 
307*e351b826SPaolo Bonzini static
308*e351b826SPaolo Bonzini size_t mptsas_config_io_unit_3(MPTSASState *s, uint8_t **data, int address)
309*e351b826SPaolo Bonzini {
310*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x01,
311*e351b826SPaolo Bonzini                               "*b*b*w*l");
312*e351b826SPaolo Bonzini }
313*e351b826SPaolo Bonzini 
314*e351b826SPaolo Bonzini static
315*e351b826SPaolo Bonzini size_t mptsas_config_io_unit_4(MPTSASState *s, uint8_t **data, int address)
316*e351b826SPaolo Bonzini {
317*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x00, "*l*l*q");
318*e351b826SPaolo Bonzini }
319*e351b826SPaolo Bonzini 
320*e351b826SPaolo Bonzini /* I/O controller pages */
321*e351b826SPaolo Bonzini 
322*e351b826SPaolo Bonzini static
323*e351b826SPaolo Bonzini size_t mptsas_config_ioc_0(MPTSASState *s, uint8_t **data, int address)
324*e351b826SPaolo Bonzini {
325*e351b826SPaolo Bonzini     PCIDeviceClass *pcic = PCI_DEVICE_GET_CLASS(s);
326*e351b826SPaolo Bonzini 
327*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IOC, 0x01,
328*e351b826SPaolo Bonzini                               "*l*lwwb*b*b*blww",
329*e351b826SPaolo Bonzini                               pcic->vendor_id, pcic->device_id, pcic->revision,
330*e351b826SPaolo Bonzini                               pcic->subsystem_vendor_id,
331*e351b826SPaolo Bonzini                               pcic->subsystem_id);
332*e351b826SPaolo Bonzini }
333*e351b826SPaolo Bonzini 
334*e351b826SPaolo Bonzini static
335*e351b826SPaolo Bonzini size_t mptsas_config_ioc_1(MPTSASState *s, uint8_t **data, int address)
336*e351b826SPaolo Bonzini {
337*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_IOC, 0x03,
338*e351b826SPaolo Bonzini                               "*l*l*b*b*b*b");
339*e351b826SPaolo Bonzini }
340*e351b826SPaolo Bonzini 
341*e351b826SPaolo Bonzini static
342*e351b826SPaolo Bonzini size_t mptsas_config_ioc_2(MPTSASState *s, uint8_t **data, int address)
343*e351b826SPaolo Bonzini {
344*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_IOC, 0x04,
345*e351b826SPaolo Bonzini                               "*l*b*b*b*b");
346*e351b826SPaolo Bonzini }
347*e351b826SPaolo Bonzini 
348*e351b826SPaolo Bonzini static
349*e351b826SPaolo Bonzini size_t mptsas_config_ioc_3(MPTSASState *s, uint8_t **data, int address)
350*e351b826SPaolo Bonzini {
351*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_IOC, 0x00,
352*e351b826SPaolo Bonzini                               "*b*b*w");
353*e351b826SPaolo Bonzini }
354*e351b826SPaolo Bonzini 
355*e351b826SPaolo Bonzini static
356*e351b826SPaolo Bonzini size_t mptsas_config_ioc_4(MPTSASState *s, uint8_t **data, int address)
357*e351b826SPaolo Bonzini {
358*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_IOC, 0x00,
359*e351b826SPaolo Bonzini                               "*b*b*w");
360*e351b826SPaolo Bonzini }
361*e351b826SPaolo Bonzini 
362*e351b826SPaolo Bonzini static
363*e351b826SPaolo Bonzini size_t mptsas_config_ioc_5(MPTSASState *s, uint8_t **data, int address)
364*e351b826SPaolo Bonzini {
365*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(5, MPI_CONFIG_PAGETYPE_IOC, 0x00,
366*e351b826SPaolo Bonzini                               "*l*b*b*w");
367*e351b826SPaolo Bonzini }
368*e351b826SPaolo Bonzini 
369*e351b826SPaolo Bonzini static
370*e351b826SPaolo Bonzini size_t mptsas_config_ioc_6(MPTSASState *s, uint8_t **data, int address)
371*e351b826SPaolo Bonzini {
372*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK(6, MPI_CONFIG_PAGETYPE_IOC, 0x01,
373*e351b826SPaolo Bonzini                               "*l*b*b*b*b*b*b*b*b*b*b*w*l*l*l*l*b*b*w"
374*e351b826SPaolo Bonzini                               "*w*w*w*w*l*l*l");
375*e351b826SPaolo Bonzini }
376*e351b826SPaolo Bonzini 
377*e351b826SPaolo Bonzini /* SAS I/O unit pages (extended) */
378*e351b826SPaolo Bonzini 
379*e351b826SPaolo Bonzini #define MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE 16
380*e351b826SPaolo Bonzini 
381*e351b826SPaolo Bonzini #define MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION 0x02
382*e351b826SPaolo Bonzini #define MPI_SAS_IOUNIT0_RATE_1_5                      0x08
383*e351b826SPaolo Bonzini #define MPI_SAS_IOUNIT0_RATE_3_0                      0x09
384*e351b826SPaolo Bonzini 
385*e351b826SPaolo Bonzini #define MPI_SAS_DEVICE_INFO_NO_DEVICE                 0x00000000
386*e351b826SPaolo Bonzini #define MPI_SAS_DEVICE_INFO_END_DEVICE                0x00000001
387*e351b826SPaolo Bonzini #define MPI_SAS_DEVICE_INFO_SSP_TARGET                0x00000400
388*e351b826SPaolo Bonzini 
389*e351b826SPaolo Bonzini #define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS             0x00
390*e351b826SPaolo Bonzini 
391*e351b826SPaolo Bonzini #define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT          0x0001
392*e351b826SPaolo Bonzini #define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED           0x0002
393*e351b826SPaolo Bonzini #define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT      0x0004
394*e351b826SPaolo Bonzini 
395*e351b826SPaolo Bonzini 
396*e351b826SPaolo Bonzini 
397*e351b826SPaolo Bonzini static SCSIDevice *mptsas_phy_get_device(MPTSASState *s, int i,
398*e351b826SPaolo Bonzini                                          int *phy_handle, int *dev_handle)
399*e351b826SPaolo Bonzini {
400*e351b826SPaolo Bonzini     SCSIDevice *d = scsi_device_find(&s->bus, 0, i, 0);
401*e351b826SPaolo Bonzini 
402*e351b826SPaolo Bonzini     if (phy_handle) {
403*e351b826SPaolo Bonzini         *phy_handle = i + 1;
404*e351b826SPaolo Bonzini     }
405*e351b826SPaolo Bonzini     if (dev_handle) {
406*e351b826SPaolo Bonzini         *dev_handle = d ? i + 1 + MPTSAS_NUM_PORTS : 0;
407*e351b826SPaolo Bonzini     }
408*e351b826SPaolo Bonzini     return d;
409*e351b826SPaolo Bonzini }
410*e351b826SPaolo Bonzini 
411*e351b826SPaolo Bonzini static
412*e351b826SPaolo Bonzini size_t mptsas_config_sas_io_unit_0(MPTSASState *s, uint8_t **data, int address)
413*e351b826SPaolo Bonzini {
414*e351b826SPaolo Bonzini     size_t size = MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x04,
415*e351b826SPaolo Bonzini                                          "*w*wb*b*w"
416*e351b826SPaolo Bonzini                                          repl(MPTSAS_NUM_PORTS, "*s16"),
417*e351b826SPaolo Bonzini                                          MPTSAS_NUM_PORTS);
418*e351b826SPaolo Bonzini 
419*e351b826SPaolo Bonzini     if (data) {
420*e351b826SPaolo Bonzini         size_t ofs = size - MPTSAS_NUM_PORTS * MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE;
421*e351b826SPaolo Bonzini         int i;
422*e351b826SPaolo Bonzini 
423*e351b826SPaolo Bonzini         for (i = 0; i < MPTSAS_NUM_PORTS; i++) {
424*e351b826SPaolo Bonzini             int phy_handle, dev_handle;
425*e351b826SPaolo Bonzini             SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
426*e351b826SPaolo Bonzini 
427*e351b826SPaolo Bonzini             fill(*data + ofs, MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE,
428*e351b826SPaolo Bonzini                  "bbbblwwl", i, 0, 0,
429*e351b826SPaolo Bonzini                  (dev
430*e351b826SPaolo Bonzini                   ? MPI_SAS_IOUNIT0_RATE_3_0
431*e351b826SPaolo Bonzini                   : MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION),
432*e351b826SPaolo Bonzini                  (dev
433*e351b826SPaolo Bonzini                   ? MPI_SAS_DEVICE_INFO_END_DEVICE | MPI_SAS_DEVICE_INFO_SSP_TARGET
434*e351b826SPaolo Bonzini                   : MPI_SAS_DEVICE_INFO_NO_DEVICE),
435*e351b826SPaolo Bonzini                  dev_handle,
436*e351b826SPaolo Bonzini                  dev_handle,
437*e351b826SPaolo Bonzini                  0);
438*e351b826SPaolo Bonzini             ofs += MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE;
439*e351b826SPaolo Bonzini         }
440*e351b826SPaolo Bonzini         assert(ofs == size);
441*e351b826SPaolo Bonzini     }
442*e351b826SPaolo Bonzini     return size;
443*e351b826SPaolo Bonzini }
444*e351b826SPaolo Bonzini 
445*e351b826SPaolo Bonzini #define MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE 12
446*e351b826SPaolo Bonzini 
447*e351b826SPaolo Bonzini static
448*e351b826SPaolo Bonzini size_t mptsas_config_sas_io_unit_1(MPTSASState *s, uint8_t **data, int address)
449*e351b826SPaolo Bonzini {
450*e351b826SPaolo Bonzini     size_t size = MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x07,
451*e351b826SPaolo Bonzini                                          "*w*w*w*wb*b*b*b"
452*e351b826SPaolo Bonzini                                          repl(MPTSAS_NUM_PORTS, "*s12"),
453*e351b826SPaolo Bonzini                                          MPTSAS_NUM_PORTS);
454*e351b826SPaolo Bonzini 
455*e351b826SPaolo Bonzini     if (data) {
456*e351b826SPaolo Bonzini         size_t ofs = size - MPTSAS_NUM_PORTS * MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE;
457*e351b826SPaolo Bonzini         int i;
458*e351b826SPaolo Bonzini 
459*e351b826SPaolo Bonzini         for (i = 0; i < MPTSAS_NUM_PORTS; i++) {
460*e351b826SPaolo Bonzini             SCSIDevice *dev = mptsas_phy_get_device(s, i, NULL, NULL);
461*e351b826SPaolo Bonzini             fill(*data + ofs, MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE,
462*e351b826SPaolo Bonzini                  "bbbblww", i, 0, 0,
463*e351b826SPaolo Bonzini                  (MPI_SAS_IOUNIT0_RATE_3_0 << 4) | MPI_SAS_IOUNIT0_RATE_1_5,
464*e351b826SPaolo Bonzini                  (dev
465*e351b826SPaolo Bonzini                   ? MPI_SAS_DEVICE_INFO_END_DEVICE | MPI_SAS_DEVICE_INFO_SSP_TARGET
466*e351b826SPaolo Bonzini                   : MPI_SAS_DEVICE_INFO_NO_DEVICE),
467*e351b826SPaolo Bonzini                  0, 0);
468*e351b826SPaolo Bonzini             ofs += MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE;
469*e351b826SPaolo Bonzini         }
470*e351b826SPaolo Bonzini         assert(ofs == size);
471*e351b826SPaolo Bonzini     }
472*e351b826SPaolo Bonzini     return size;
473*e351b826SPaolo Bonzini }
474*e351b826SPaolo Bonzini 
475*e351b826SPaolo Bonzini static
476*e351b826SPaolo Bonzini size_t mptsas_config_sas_io_unit_2(MPTSASState *s, uint8_t **data, int address)
477*e351b826SPaolo Bonzini {
478*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK_EXT(2, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x06,
479*e351b826SPaolo Bonzini                                   "*b*b*w*w*w*b*b*w");
480*e351b826SPaolo Bonzini }
481*e351b826SPaolo Bonzini 
482*e351b826SPaolo Bonzini static
483*e351b826SPaolo Bonzini size_t mptsas_config_sas_io_unit_3(MPTSASState *s, uint8_t **data, int address)
484*e351b826SPaolo Bonzini {
485*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK_EXT(3, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x06,
486*e351b826SPaolo Bonzini                                   "*l*l*l*l*l*l*l*l*l");
487*e351b826SPaolo Bonzini }
488*e351b826SPaolo Bonzini 
489*e351b826SPaolo Bonzini /* SAS PHY pages (extended) */
490*e351b826SPaolo Bonzini 
491*e351b826SPaolo Bonzini static int mptsas_phy_addr_get(MPTSASState *s, int address)
492*e351b826SPaolo Bonzini {
493*e351b826SPaolo Bonzini     int i;
494*e351b826SPaolo Bonzini     if ((address >> MPI_SAS_PHY_PGAD_FORM_SHIFT) == 0) {
495*e351b826SPaolo Bonzini         i = address & 255;
496*e351b826SPaolo Bonzini     } else if ((address >> MPI_SAS_PHY_PGAD_FORM_SHIFT) == 1) {
497*e351b826SPaolo Bonzini         i = address & 65535;
498*e351b826SPaolo Bonzini     } else {
499*e351b826SPaolo Bonzini         return -EINVAL;
500*e351b826SPaolo Bonzini     }
501*e351b826SPaolo Bonzini 
502*e351b826SPaolo Bonzini     if (i >= MPTSAS_NUM_PORTS) {
503*e351b826SPaolo Bonzini         return -EINVAL;
504*e351b826SPaolo Bonzini     }
505*e351b826SPaolo Bonzini 
506*e351b826SPaolo Bonzini     return i;
507*e351b826SPaolo Bonzini }
508*e351b826SPaolo Bonzini 
509*e351b826SPaolo Bonzini static
510*e351b826SPaolo Bonzini size_t mptsas_config_phy_0(MPTSASState *s, uint8_t **data, int address)
511*e351b826SPaolo Bonzini {
512*e351b826SPaolo Bonzini     int phy_handle = -1;
513*e351b826SPaolo Bonzini     int dev_handle = -1;
514*e351b826SPaolo Bonzini     int i = mptsas_phy_addr_get(s, address);
515*e351b826SPaolo Bonzini     SCSIDevice *dev;
516*e351b826SPaolo Bonzini 
517*e351b826SPaolo Bonzini     if (i < 0) {
518*e351b826SPaolo Bonzini         trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 0);
519*e351b826SPaolo Bonzini         return i;
520*e351b826SPaolo Bonzini     }
521*e351b826SPaolo Bonzini 
522*e351b826SPaolo Bonzini     dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
523*e351b826SPaolo Bonzini     trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 0);
524*e351b826SPaolo Bonzini 
525*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 0x01,
526*e351b826SPaolo Bonzini                                   "w*wqwb*blbb*b*b*l",
527*e351b826SPaolo Bonzini                                   dev_handle, s->sas_addr, dev_handle, i,
528*e351b826SPaolo Bonzini                                   (dev
529*e351b826SPaolo Bonzini                                    ? MPI_SAS_DEVICE_INFO_END_DEVICE /* | MPI_SAS_DEVICE_INFO_SSP_TARGET?? */
530*e351b826SPaolo Bonzini                                    : MPI_SAS_DEVICE_INFO_NO_DEVICE),
531*e351b826SPaolo Bonzini                                   (MPI_SAS_IOUNIT0_RATE_3_0 << 4) | MPI_SAS_IOUNIT0_RATE_1_5,
532*e351b826SPaolo Bonzini                                   (MPI_SAS_IOUNIT0_RATE_3_0 << 4) | MPI_SAS_IOUNIT0_RATE_1_5);
533*e351b826SPaolo Bonzini }
534*e351b826SPaolo Bonzini 
535*e351b826SPaolo Bonzini static
536*e351b826SPaolo Bonzini size_t mptsas_config_phy_1(MPTSASState *s, uint8_t **data, int address)
537*e351b826SPaolo Bonzini {
538*e351b826SPaolo Bonzini     int phy_handle = -1;
539*e351b826SPaolo Bonzini     int dev_handle = -1;
540*e351b826SPaolo Bonzini     int i = mptsas_phy_addr_get(s, address);
541*e351b826SPaolo Bonzini 
542*e351b826SPaolo Bonzini     if (i < 0) {
543*e351b826SPaolo Bonzini         trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 1);
544*e351b826SPaolo Bonzini         return i;
545*e351b826SPaolo Bonzini     }
546*e351b826SPaolo Bonzini 
547*e351b826SPaolo Bonzini     (void) mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
548*e351b826SPaolo Bonzini     trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 1);
549*e351b826SPaolo Bonzini 
550*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 0x01,
551*e351b826SPaolo Bonzini                                   "*l*l*l*l*l");
552*e351b826SPaolo Bonzini }
553*e351b826SPaolo Bonzini 
554*e351b826SPaolo Bonzini /* SAS device pages (extended) */
555*e351b826SPaolo Bonzini 
556*e351b826SPaolo Bonzini static int mptsas_device_addr_get(MPTSASState *s, int address)
557*e351b826SPaolo Bonzini {
558*e351b826SPaolo Bonzini     uint32_t handle, i;
559*e351b826SPaolo Bonzini     uint32_t form = address >> MPI_SAS_PHY_PGAD_FORM_SHIFT;
560*e351b826SPaolo Bonzini     if (form == MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
561*e351b826SPaolo Bonzini         handle = address & MPI_SAS_DEVICE_PGAD_GNH_HANDLE_MASK;
562*e351b826SPaolo Bonzini         do {
563*e351b826SPaolo Bonzini             if (handle == 65535) {
564*e351b826SPaolo Bonzini                 handle = MPTSAS_NUM_PORTS + 1;
565*e351b826SPaolo Bonzini             } else {
566*e351b826SPaolo Bonzini                 ++handle;
567*e351b826SPaolo Bonzini             }
568*e351b826SPaolo Bonzini             i = handle - 1 - MPTSAS_NUM_PORTS;
569*e351b826SPaolo Bonzini         } while (i < MPTSAS_NUM_PORTS && !scsi_device_find(&s->bus, 0, i, 0));
570*e351b826SPaolo Bonzini 
571*e351b826SPaolo Bonzini     } else if (form == MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID) {
572*e351b826SPaolo Bonzini         if (address & MPI_SAS_DEVICE_PGAD_BT_BUS_MASK) {
573*e351b826SPaolo Bonzini             return -EINVAL;
574*e351b826SPaolo Bonzini         }
575*e351b826SPaolo Bonzini         i = address & MPI_SAS_DEVICE_PGAD_BT_TID_MASK;
576*e351b826SPaolo Bonzini 
577*e351b826SPaolo Bonzini     } else if (form == MPI_SAS_DEVICE_PGAD_FORM_HANDLE) {
578*e351b826SPaolo Bonzini         handle = address & MPI_SAS_DEVICE_PGAD_H_HANDLE_MASK;
579*e351b826SPaolo Bonzini         i = handle - 1 - MPTSAS_NUM_PORTS;
580*e351b826SPaolo Bonzini 
581*e351b826SPaolo Bonzini     } else {
582*e351b826SPaolo Bonzini         return -EINVAL;
583*e351b826SPaolo Bonzini     }
584*e351b826SPaolo Bonzini 
585*e351b826SPaolo Bonzini     if (i >= MPTSAS_NUM_PORTS) {
586*e351b826SPaolo Bonzini         return -EINVAL;
587*e351b826SPaolo Bonzini     }
588*e351b826SPaolo Bonzini 
589*e351b826SPaolo Bonzini     return i;
590*e351b826SPaolo Bonzini }
591*e351b826SPaolo Bonzini 
592*e351b826SPaolo Bonzini static
593*e351b826SPaolo Bonzini size_t mptsas_config_sas_device_0(MPTSASState *s, uint8_t **data, int address)
594*e351b826SPaolo Bonzini {
595*e351b826SPaolo Bonzini     int phy_handle = -1;
596*e351b826SPaolo Bonzini     int dev_handle = -1;
597*e351b826SPaolo Bonzini     int i = mptsas_device_addr_get(s, address);
598*e351b826SPaolo Bonzini     SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
599*e351b826SPaolo Bonzini 
600*e351b826SPaolo Bonzini     trace_mptsas_config_sas_device(s, address, i, phy_handle, dev_handle, 0);
601*e351b826SPaolo Bonzini     if (!dev) {
602*e351b826SPaolo Bonzini         return -ENOENT;
603*e351b826SPaolo Bonzini     }
604*e351b826SPaolo Bonzini 
605*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0x05,
606*e351b826SPaolo Bonzini                                   "*w*wqwbbwbblwb*b",
607*e351b826SPaolo Bonzini                                   dev->wwn, phy_handle, i,
608*e351b826SPaolo Bonzini                                   MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS,
609*e351b826SPaolo Bonzini                                   dev_handle, i, 0,
610*e351b826SPaolo Bonzini                                   MPI_SAS_DEVICE_INFO_END_DEVICE | MPI_SAS_DEVICE_INFO_SSP_TARGET,
611*e351b826SPaolo Bonzini                                   (MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT |
612*e351b826SPaolo Bonzini                                    MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED |
613*e351b826SPaolo Bonzini                                    MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT), i);
614*e351b826SPaolo Bonzini }
615*e351b826SPaolo Bonzini 
616*e351b826SPaolo Bonzini static
617*e351b826SPaolo Bonzini size_t mptsas_config_sas_device_1(MPTSASState *s, uint8_t **data, int address)
618*e351b826SPaolo Bonzini {
619*e351b826SPaolo Bonzini     int phy_handle = -1;
620*e351b826SPaolo Bonzini     int dev_handle = -1;
621*e351b826SPaolo Bonzini     int i = mptsas_device_addr_get(s, address);
622*e351b826SPaolo Bonzini     SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
623*e351b826SPaolo Bonzini 
624*e351b826SPaolo Bonzini     trace_mptsas_config_sas_device(s, address, i, phy_handle, dev_handle, 1);
625*e351b826SPaolo Bonzini     if (!dev) {
626*e351b826SPaolo Bonzini         return -ENOENT;
627*e351b826SPaolo Bonzini     }
628*e351b826SPaolo Bonzini 
629*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0x00,
630*e351b826SPaolo Bonzini                                   "*lq*lwbb*s20",
631*e351b826SPaolo Bonzini                                   dev->wwn, dev_handle, i, 0);
632*e351b826SPaolo Bonzini }
633*e351b826SPaolo Bonzini 
634*e351b826SPaolo Bonzini static
635*e351b826SPaolo Bonzini size_t mptsas_config_sas_device_2(MPTSASState *s, uint8_t **data, int address)
636*e351b826SPaolo Bonzini {
637*e351b826SPaolo Bonzini     int phy_handle = -1;
638*e351b826SPaolo Bonzini     int dev_handle = -1;
639*e351b826SPaolo Bonzini     int i = mptsas_device_addr_get(s, address);
640*e351b826SPaolo Bonzini     SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle);
641*e351b826SPaolo Bonzini 
642*e351b826SPaolo Bonzini     trace_mptsas_config_sas_device(s, address, i, phy_handle, dev_handle, 2);
643*e351b826SPaolo Bonzini     if (!dev) {
644*e351b826SPaolo Bonzini         return -ENOENT;
645*e351b826SPaolo Bonzini     }
646*e351b826SPaolo Bonzini 
647*e351b826SPaolo Bonzini     return MPTSAS_CONFIG_PACK_EXT(2, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0x01,
648*e351b826SPaolo Bonzini                                   "ql", dev->wwn, 0);
649*e351b826SPaolo Bonzini }
650*e351b826SPaolo Bonzini 
651*e351b826SPaolo Bonzini typedef struct MPTSASConfigPage {
652*e351b826SPaolo Bonzini     uint8_t number;
653*e351b826SPaolo Bonzini     uint8_t type;
654*e351b826SPaolo Bonzini     size_t (*mpt_config_build)(MPTSASState *s, uint8_t **data, int address);
655*e351b826SPaolo Bonzini } MPTSASConfigPage;
656*e351b826SPaolo Bonzini 
657*e351b826SPaolo Bonzini static const MPTSASConfigPage mptsas_config_pages[] = {
658*e351b826SPaolo Bonzini     {
659*e351b826SPaolo Bonzini         0, MPI_CONFIG_PAGETYPE_MANUFACTURING,
660*e351b826SPaolo Bonzini         mptsas_config_manufacturing_0,
661*e351b826SPaolo Bonzini     }, {
662*e351b826SPaolo Bonzini         1, MPI_CONFIG_PAGETYPE_MANUFACTURING,
663*e351b826SPaolo Bonzini         mptsas_config_manufacturing_1,
664*e351b826SPaolo Bonzini     }, {
665*e351b826SPaolo Bonzini         2, MPI_CONFIG_PAGETYPE_MANUFACTURING,
666*e351b826SPaolo Bonzini         mptsas_config_manufacturing_2,
667*e351b826SPaolo Bonzini     }, {
668*e351b826SPaolo Bonzini         3, MPI_CONFIG_PAGETYPE_MANUFACTURING,
669*e351b826SPaolo Bonzini         mptsas_config_manufacturing_3,
670*e351b826SPaolo Bonzini     }, {
671*e351b826SPaolo Bonzini         4, MPI_CONFIG_PAGETYPE_MANUFACTURING,
672*e351b826SPaolo Bonzini         mptsas_config_manufacturing_4,
673*e351b826SPaolo Bonzini     }, {
674*e351b826SPaolo Bonzini         5, MPI_CONFIG_PAGETYPE_MANUFACTURING,
675*e351b826SPaolo Bonzini         mptsas_config_manufacturing_5,
676*e351b826SPaolo Bonzini     }, {
677*e351b826SPaolo Bonzini         6, MPI_CONFIG_PAGETYPE_MANUFACTURING,
678*e351b826SPaolo Bonzini         mptsas_config_manufacturing_6,
679*e351b826SPaolo Bonzini     }, {
680*e351b826SPaolo Bonzini         7, MPI_CONFIG_PAGETYPE_MANUFACTURING,
681*e351b826SPaolo Bonzini         mptsas_config_manufacturing_7,
682*e351b826SPaolo Bonzini     }, {
683*e351b826SPaolo Bonzini         8, MPI_CONFIG_PAGETYPE_MANUFACTURING,
684*e351b826SPaolo Bonzini         mptsas_config_manufacturing_8,
685*e351b826SPaolo Bonzini     }, {
686*e351b826SPaolo Bonzini         9, MPI_CONFIG_PAGETYPE_MANUFACTURING,
687*e351b826SPaolo Bonzini         mptsas_config_manufacturing_9,
688*e351b826SPaolo Bonzini     }, {
689*e351b826SPaolo Bonzini         10, MPI_CONFIG_PAGETYPE_MANUFACTURING,
690*e351b826SPaolo Bonzini         mptsas_config_manufacturing_10,
691*e351b826SPaolo Bonzini     }, {
692*e351b826SPaolo Bonzini         0, MPI_CONFIG_PAGETYPE_IO_UNIT,
693*e351b826SPaolo Bonzini         mptsas_config_io_unit_0,
694*e351b826SPaolo Bonzini     }, {
695*e351b826SPaolo Bonzini         1, MPI_CONFIG_PAGETYPE_IO_UNIT,
696*e351b826SPaolo Bonzini         mptsas_config_io_unit_1,
697*e351b826SPaolo Bonzini     }, {
698*e351b826SPaolo Bonzini         2, MPI_CONFIG_PAGETYPE_IO_UNIT,
699*e351b826SPaolo Bonzini         mptsas_config_io_unit_2,
700*e351b826SPaolo Bonzini     }, {
701*e351b826SPaolo Bonzini         3, MPI_CONFIG_PAGETYPE_IO_UNIT,
702*e351b826SPaolo Bonzini         mptsas_config_io_unit_3,
703*e351b826SPaolo Bonzini     }, {
704*e351b826SPaolo Bonzini         4, MPI_CONFIG_PAGETYPE_IO_UNIT,
705*e351b826SPaolo Bonzini         mptsas_config_io_unit_4,
706*e351b826SPaolo Bonzini     }, {
707*e351b826SPaolo Bonzini         0, MPI_CONFIG_PAGETYPE_IOC,
708*e351b826SPaolo Bonzini         mptsas_config_ioc_0,
709*e351b826SPaolo Bonzini     }, {
710*e351b826SPaolo Bonzini         1, MPI_CONFIG_PAGETYPE_IOC,
711*e351b826SPaolo Bonzini         mptsas_config_ioc_1,
712*e351b826SPaolo Bonzini     }, {
713*e351b826SPaolo Bonzini         2, MPI_CONFIG_PAGETYPE_IOC,
714*e351b826SPaolo Bonzini         mptsas_config_ioc_2,
715*e351b826SPaolo Bonzini     }, {
716*e351b826SPaolo Bonzini         3, MPI_CONFIG_PAGETYPE_IOC,
717*e351b826SPaolo Bonzini         mptsas_config_ioc_3,
718*e351b826SPaolo Bonzini     }, {
719*e351b826SPaolo Bonzini         4, MPI_CONFIG_PAGETYPE_IOC,
720*e351b826SPaolo Bonzini         mptsas_config_ioc_4,
721*e351b826SPaolo Bonzini     }, {
722*e351b826SPaolo Bonzini         5, MPI_CONFIG_PAGETYPE_IOC,
723*e351b826SPaolo Bonzini         mptsas_config_ioc_5,
724*e351b826SPaolo Bonzini     }, {
725*e351b826SPaolo Bonzini         6, MPI_CONFIG_PAGETYPE_IOC,
726*e351b826SPaolo Bonzini         mptsas_config_ioc_6,
727*e351b826SPaolo Bonzini     }, {
728*e351b826SPaolo Bonzini         0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
729*e351b826SPaolo Bonzini         mptsas_config_sas_io_unit_0,
730*e351b826SPaolo Bonzini     }, {
731*e351b826SPaolo Bonzini         1, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
732*e351b826SPaolo Bonzini         mptsas_config_sas_io_unit_1,
733*e351b826SPaolo Bonzini     }, {
734*e351b826SPaolo Bonzini         2, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
735*e351b826SPaolo Bonzini         mptsas_config_sas_io_unit_2,
736*e351b826SPaolo Bonzini     }, {
737*e351b826SPaolo Bonzini         3, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
738*e351b826SPaolo Bonzini         mptsas_config_sas_io_unit_3,
739*e351b826SPaolo Bonzini     }, {
740*e351b826SPaolo Bonzini         0, MPI_CONFIG_EXTPAGETYPE_SAS_PHY,
741*e351b826SPaolo Bonzini         mptsas_config_phy_0,
742*e351b826SPaolo Bonzini     }, {
743*e351b826SPaolo Bonzini         1, MPI_CONFIG_EXTPAGETYPE_SAS_PHY,
744*e351b826SPaolo Bonzini         mptsas_config_phy_1,
745*e351b826SPaolo Bonzini     }, {
746*e351b826SPaolo Bonzini         0, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE,
747*e351b826SPaolo Bonzini         mptsas_config_sas_device_0,
748*e351b826SPaolo Bonzini     }, {
749*e351b826SPaolo Bonzini         1, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE,
750*e351b826SPaolo Bonzini         mptsas_config_sas_device_1,
751*e351b826SPaolo Bonzini     }, {
752*e351b826SPaolo Bonzini        2,  MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE,
753*e351b826SPaolo Bonzini         mptsas_config_sas_device_2,
754*e351b826SPaolo Bonzini     }
755*e351b826SPaolo Bonzini };
756*e351b826SPaolo Bonzini 
757*e351b826SPaolo Bonzini static const MPTSASConfigPage *mptsas_find_config_page(int type, int number)
758*e351b826SPaolo Bonzini {
759*e351b826SPaolo Bonzini     const MPTSASConfigPage *page;
760*e351b826SPaolo Bonzini     int i;
761*e351b826SPaolo Bonzini 
762*e351b826SPaolo Bonzini     for (i = 0; i < ARRAY_SIZE(mptsas_config_pages); i++) {
763*e351b826SPaolo Bonzini         page = &mptsas_config_pages[i];
764*e351b826SPaolo Bonzini         if (page->type == type && page->number == number) {
765*e351b826SPaolo Bonzini             return page;
766*e351b826SPaolo Bonzini         }
767*e351b826SPaolo Bonzini     }
768*e351b826SPaolo Bonzini 
769*e351b826SPaolo Bonzini     return NULL;
770*e351b826SPaolo Bonzini }
771*e351b826SPaolo Bonzini 
772*e351b826SPaolo Bonzini void mptsas_process_config(MPTSASState *s, MPIMsgConfig *req)
773*e351b826SPaolo Bonzini {
774*e351b826SPaolo Bonzini     PCIDevice *pci = PCI_DEVICE(s);
775*e351b826SPaolo Bonzini 
776*e351b826SPaolo Bonzini     MPIMsgConfigReply reply;
777*e351b826SPaolo Bonzini     const MPTSASConfigPage *page;
778*e351b826SPaolo Bonzini     size_t length;
779*e351b826SPaolo Bonzini     uint8_t type;
780*e351b826SPaolo Bonzini     uint8_t *data = NULL;
781*e351b826SPaolo Bonzini     uint32_t flags_and_length;
782*e351b826SPaolo Bonzini     uint32_t dmalen;
783*e351b826SPaolo Bonzini     uint64_t pa;
784*e351b826SPaolo Bonzini 
785*e351b826SPaolo Bonzini     mptsas_fix_config_endianness(req);
786*e351b826SPaolo Bonzini 
787*e351b826SPaolo Bonzini     QEMU_BUILD_BUG_ON(sizeof(s->doorbell_msg) < sizeof(*req));
788*e351b826SPaolo Bonzini     QEMU_BUILD_BUG_ON(sizeof(s->doorbell_reply) < sizeof(reply));
789*e351b826SPaolo Bonzini 
790*e351b826SPaolo Bonzini     /* Copy common bits from the request into the reply. */
791*e351b826SPaolo Bonzini     memset(&reply, 0, sizeof(reply));
792*e351b826SPaolo Bonzini     reply.Action      = req->Action;
793*e351b826SPaolo Bonzini     reply.Function    = req->Function;
794*e351b826SPaolo Bonzini     reply.MsgContext  = req->MsgContext;
795*e351b826SPaolo Bonzini     reply.MsgLength   = sizeof(reply) / 4;
796*e351b826SPaolo Bonzini     reply.PageType    = req->PageType;
797*e351b826SPaolo Bonzini     reply.PageNumber  = req->PageNumber;
798*e351b826SPaolo Bonzini     reply.PageLength  = req->PageLength;
799*e351b826SPaolo Bonzini     reply.PageVersion = req->PageVersion;
800*e351b826SPaolo Bonzini 
801*e351b826SPaolo Bonzini     type = req->PageType & MPI_CONFIG_PAGETYPE_MASK;
802*e351b826SPaolo Bonzini     if (type == MPI_CONFIG_PAGETYPE_EXTENDED) {
803*e351b826SPaolo Bonzini         type = req->ExtPageType;
804*e351b826SPaolo Bonzini         if (type <= MPI_CONFIG_PAGETYPE_MASK) {
805*e351b826SPaolo Bonzini             reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_TYPE;
806*e351b826SPaolo Bonzini             goto out;
807*e351b826SPaolo Bonzini         }
808*e351b826SPaolo Bonzini 
809*e351b826SPaolo Bonzini         reply.ExtPageType = req->ExtPageType;
810*e351b826SPaolo Bonzini     }
811*e351b826SPaolo Bonzini 
812*e351b826SPaolo Bonzini     page = mptsas_find_config_page(type, req->PageNumber);
813*e351b826SPaolo Bonzini 
814*e351b826SPaolo Bonzini     switch(req->Action) {
815*e351b826SPaolo Bonzini     case MPI_CONFIG_ACTION_PAGE_DEFAULT:
816*e351b826SPaolo Bonzini     case MPI_CONFIG_ACTION_PAGE_HEADER:
817*e351b826SPaolo Bonzini     case MPI_CONFIG_ACTION_PAGE_READ_NVRAM:
818*e351b826SPaolo Bonzini     case MPI_CONFIG_ACTION_PAGE_READ_CURRENT:
819*e351b826SPaolo Bonzini     case MPI_CONFIG_ACTION_PAGE_READ_DEFAULT:
820*e351b826SPaolo Bonzini     case MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT:
821*e351b826SPaolo Bonzini     case MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM:
822*e351b826SPaolo Bonzini         break;
823*e351b826SPaolo Bonzini 
824*e351b826SPaolo Bonzini     default:
825*e351b826SPaolo Bonzini         reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_ACTION;
826*e351b826SPaolo Bonzini         goto out;
827*e351b826SPaolo Bonzini     }
828*e351b826SPaolo Bonzini 
829*e351b826SPaolo Bonzini     if (!page) {
830*e351b826SPaolo Bonzini         page = mptsas_find_config_page(type, 1);
831*e351b826SPaolo Bonzini         if (page) {
832*e351b826SPaolo Bonzini             reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
833*e351b826SPaolo Bonzini         } else {
834*e351b826SPaolo Bonzini             reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_TYPE;
835*e351b826SPaolo Bonzini         }
836*e351b826SPaolo Bonzini         goto out;
837*e351b826SPaolo Bonzini     }
838*e351b826SPaolo Bonzini 
839*e351b826SPaolo Bonzini     if (req->Action == MPI_CONFIG_ACTION_PAGE_DEFAULT ||
840*e351b826SPaolo Bonzini         req->Action == MPI_CONFIG_ACTION_PAGE_HEADER) {
841*e351b826SPaolo Bonzini         length = page->mpt_config_build(s, NULL, req->PageAddress);
842*e351b826SPaolo Bonzini         if ((ssize_t)length < 0) {
843*e351b826SPaolo Bonzini             reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
844*e351b826SPaolo Bonzini             goto out;
845*e351b826SPaolo Bonzini         } else {
846*e351b826SPaolo Bonzini             goto done;
847*e351b826SPaolo Bonzini         }
848*e351b826SPaolo Bonzini     }
849*e351b826SPaolo Bonzini 
850*e351b826SPaolo Bonzini     if (req->Action == MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT ||
851*e351b826SPaolo Bonzini         req->Action == MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
852*e351b826SPaolo Bonzini         length = page->mpt_config_build(s, NULL, req->PageAddress);
853*e351b826SPaolo Bonzini         if ((ssize_t)length < 0) {
854*e351b826SPaolo Bonzini             reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
855*e351b826SPaolo Bonzini         } else {
856*e351b826SPaolo Bonzini             reply.IOCStatus = MPI_IOCSTATUS_CONFIG_CANT_COMMIT;
857*e351b826SPaolo Bonzini         }
858*e351b826SPaolo Bonzini         goto out;
859*e351b826SPaolo Bonzini     }
860*e351b826SPaolo Bonzini 
861*e351b826SPaolo Bonzini     flags_and_length = req->PageBufferSGE.FlagsLength;
862*e351b826SPaolo Bonzini     dmalen = flags_and_length & MPI_SGE_LENGTH_MASK;
863*e351b826SPaolo Bonzini     if (dmalen == 0) {
864*e351b826SPaolo Bonzini         length = page->mpt_config_build(s, NULL, req->PageAddress);
865*e351b826SPaolo Bonzini         if ((ssize_t)length < 0) {
866*e351b826SPaolo Bonzini             reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
867*e351b826SPaolo Bonzini             goto out;
868*e351b826SPaolo Bonzini         } else {
869*e351b826SPaolo Bonzini             goto done;
870*e351b826SPaolo Bonzini         }
871*e351b826SPaolo Bonzini     }
872*e351b826SPaolo Bonzini 
873*e351b826SPaolo Bonzini     if (flags_and_length & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
874*e351b826SPaolo Bonzini         pa = req->PageBufferSGE.u.Address64;
875*e351b826SPaolo Bonzini     } else {
876*e351b826SPaolo Bonzini         pa = req->PageBufferSGE.u.Address32;
877*e351b826SPaolo Bonzini     }
878*e351b826SPaolo Bonzini 
879*e351b826SPaolo Bonzini     /* Only read actions left.  */
880*e351b826SPaolo Bonzini     length = page->mpt_config_build(s, &data, req->PageAddress);
881*e351b826SPaolo Bonzini     if ((ssize_t)length < 0) {
882*e351b826SPaolo Bonzini         reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE;
883*e351b826SPaolo Bonzini         goto out;
884*e351b826SPaolo Bonzini     } else {
885*e351b826SPaolo Bonzini         assert(data[2] == page->number);
886*e351b826SPaolo Bonzini         pci_dma_write(pci, pa, data, MIN(length, dmalen));
887*e351b826SPaolo Bonzini         goto done;
888*e351b826SPaolo Bonzini     }
889*e351b826SPaolo Bonzini 
890*e351b826SPaolo Bonzini     abort();
891*e351b826SPaolo Bonzini 
892*e351b826SPaolo Bonzini done:
893*e351b826SPaolo Bonzini     if (type > MPI_CONFIG_PAGETYPE_MASK) {
894*e351b826SPaolo Bonzini         reply.ExtPageLength = length / 4;
895*e351b826SPaolo Bonzini         reply.ExtPageType   = req->ExtPageType;
896*e351b826SPaolo Bonzini     } else {
897*e351b826SPaolo Bonzini         reply.PageLength    = length / 4;
898*e351b826SPaolo Bonzini     }
899*e351b826SPaolo Bonzini 
900*e351b826SPaolo Bonzini out:
901*e351b826SPaolo Bonzini     mptsas_fix_config_reply_endianness(&reply);
902*e351b826SPaolo Bonzini     mptsas_reply(s, (MPIDefaultReply *)&reply);
903*e351b826SPaolo Bonzini     g_free(data);
904*e351b826SPaolo Bonzini }
905