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