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