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