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 40 typedef union PackValue { 41 uint64_t ll; 42 char *str; 43 } PackValue; 44 45 static 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 115 static 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 131 static 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 151 static 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 171 static 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 189 static 190 size_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 201 static 202 size_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 209 static 210 size_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 218 static 219 size_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 227 static 228 size_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 236 static 237 size_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 243 static 244 size_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 250 static 251 size_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 257 static 258 size_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 264 static 265 size_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 271 static 272 size_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 280 static 281 size_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 291 static 292 size_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 298 static 299 size_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 308 static 309 size_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 315 static 316 size_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 323 static 324 size_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 335 static 336 size_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 342 static 343 size_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 349 static 350 size_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 356 static 357 size_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 363 static 364 size_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 370 static 371 size_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 398 static 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 412 static 413 size_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 448 static 449 size_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 476 static 477 size_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 483 static 484 size_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 492 static 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 510 static 511 size_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 536 static 537 size_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 557 static 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 593 static 594 size_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 617 static 618 size_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 635 static 636 size_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 652 typedef 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 658 static 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 758 static 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 773 void 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 893 done: 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 901 out: 902 mptsas_fix_config_reply_endianness(&reply); 903 mptsas_reply(s, (MPIDefaultReply *)&reply); 904 g_free(data); 905 } 906