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