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