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