qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

mptconfig.c (26942B)


      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 
     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 }