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