cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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
     39typedef union PackValue {
     40    uint64_t ll;
     41    char *str;
     42} PackValue;
     43
     44static 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
    114static 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
    130static 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
    150static 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
    170static 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
    188static
    189size_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
    200static
    201size_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
    208static
    209size_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
    217static
    218size_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
    226static
    227size_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
    235static
    236size_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
    242static
    243size_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
    249static
    250size_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
    256static
    257size_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
    263static
    264size_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
    270static
    271size_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
    279static
    280size_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
    290static
    291size_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
    297static
    298size_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
    307static
    308size_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
    314static
    315size_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
    322static
    323size_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
    334static
    335size_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
    341static
    342size_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
    348static
    349size_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
    355static
    356size_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
    362static
    363size_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
    369static
    370size_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
    397static 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
    411static
    412size_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
    447static
    448size_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
    475static
    476size_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
    482static
    483size_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
    491static 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
    509static
    510size_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
    535static
    536size_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
    556static 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
    592static
    593size_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
    616static
    617size_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
    634static
    635size_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
    651typedef 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
    657static 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
    757static 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
    772void 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
    892done:
    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
    900out:
    901    mptsas_fix_config_reply_endianness(&reply);
    902    mptsas_reply(s, (MPIDefaultReply *)&reply);
    903    g_free(data);
    904}