xref: /openbmc/qemu/hw/scsi/mptconfig.c (revision cb5ed407a1ddadf788fd373fed41c87c9e81e5b0)
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.1 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  
vfill(uint8_t * data,size_t size,const char * fmt,va_list ap)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  
vpack(uint8_t ** p_data,const char * fmt,va_list ap1)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  
fill(uint8_t * data,size_t size,const char * fmt,...)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  
mptsas_config_pack(uint8_t ** data,const char * fmt,...)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  
mptsas_config_pack_ext(uint8_t ** data,const char * fmt,...)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
mptsas_config_manufacturing_0(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_manufacturing_1(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_manufacturing_2(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_manufacturing_3(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_manufacturing_4(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_manufacturing_5(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_manufacturing_6(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_manufacturing_7(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_manufacturing_8(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_manufacturing_9(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_manufacturing_10(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_io_unit_0(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_io_unit_1(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_io_unit_2(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_io_unit_3(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_io_unit_4(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_ioc_0(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_ioc_1(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_ioc_2(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_ioc_3(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_ioc_4(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_ioc_5(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_ioc_6(MPTSASState * s,uint8_t ** data,int address)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  
mptsas_phy_get_device(MPTSASState * s,int i,int * phy_handle,int * dev_handle)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
mptsas_config_sas_io_unit_0(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_sas_io_unit_1(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_sas_io_unit_2(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_sas_io_unit_3(MPTSASState * s,uint8_t ** data,int address)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  
mptsas_phy_addr_get(MPTSASState * s,int address)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
mptsas_config_phy_0(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_phy_1(MPTSASState * s,uint8_t ** data,int address)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  
mptsas_device_addr_get(MPTSASState * s,int address)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
mptsas_config_sas_device_0(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_sas_device_1(MPTSASState * s,uint8_t ** data,int address)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
mptsas_config_sas_device_2(MPTSASState * s,uint8_t ** data,int address)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  
mptsas_find_config_page(int type,int number)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  
mptsas_process_config(MPTSASState * s,MPIMsgConfig * req)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