Browse Source
* Coverity fixes for IPMI (Corey), i386 (Paolo), qemu-char (Paolo) * at long last, fail on wrong .pc files if -m32 is in use (Daniel) * qemu-char regression fix (Daniel) * SAS1068 device (Paolo) * memory region docs improvements (Peter) * target-i386 cleanups (Richard) * qemu-nbd docs improvements (Sitsofe) * thread-safe memory hotplug (Stefan) -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAABCAAGBQJWug86AAoJEL/70l94x66DMMoH/A4tioDjhozDBtAkz/Ny2lZs 4Q34kQOWNnE0rIFDCsdg3Eq0QyYYpLH5tSuRZUHr37pfUyTkbff87uhnNepJaphY YV6LmmGZmYewZuvS3+bhvYOV6Eq9Ycsi85eT860/n3FFnfklcPqFWgjjxblKewOl Qf+9sLRVzlaeKjQPKNXbZV/4jkEF7a4W9oVKMGXcQXzyCe6vQ/ciK2jGBSLQhL9J FYFTvm70G39t79U7zPiJNXvZBtbKJdLbqPmMBHcyVk75np3mKVln3V0gYj68ACv+ S30NedLwrxShLng98trHvD2TZqwsyxXqt7NimxLsVF5sH3GCfgYuc6fhueI0H6A= =5xD6 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging * switch to C11 atomics (Alex) * Coverity fixes for IPMI (Corey), i386 (Paolo), qemu-char (Paolo) * at long last, fail on wrong .pc files if -m32 is in use (Daniel) * qemu-char regression fix (Daniel) * SAS1068 device (Paolo) * memory region docs improvements (Peter) * target-i386 cleanups (Richard) * qemu-nbd docs improvements (Sitsofe) * thread-safe memory hotplug (Stefan) # gpg: Signature made Tue 09 Feb 2016 16:09:30 GMT using RSA key ID 78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" * remotes/bonzini/tags/for-upstream: (33 commits) qemu-char, io: fix ordering of arguments for UDP socket creation MAINTAINERS: add all-match entry for qemu-devel@ get_maintainer.pl: fall back to git if only lists are found target-i386: fix PSE36 mode docs/memory.txt: Improve list of different memory regions ipmi_bmc_sim: Add break to correct watchdog NMI check ipmi_bmc_sim: Fix off by one in check. ipmi: do not take/drop iothread lock target-i386: Deconstruct the cpu_T array target-i386: Tidy gen_add_A0_im target-i386: Rewrite leave target-i386: Rewrite gen_enter inline target-i386: Use gen_lea_v_seg in pusha/popa target-i386: Access segs via TCG registers target-i386: Use gen_lea_v_seg in stack subroutines target-i386: Use gen_lea_v_seg in gen_lea_modrm target-i386: Introduce mo_stacksize target-i386: Create gen_lea_v_seg char: fix repeated registration of tcp chardev I/O handlers kvm-all: trace: strerror fixup ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>pull/36/head
32 changed files with 5223 additions and 1195 deletions
File diff suppressed because it is too large
@ -0,0 +1,904 @@ |
|||
/*
|
|||
* QEMU LSI SAS1068 Host Bus Adapter emulation - configuration pages |
|||
* |
|||
* Copyright (c) 2016 Red Hat, Inc. |
|||
* |
|||
* Author: Paolo Bonzini |
|||
* |
|||
* This library is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU Lesser General Public |
|||
* License as published by the Free Software Foundation; either |
|||
* version 2 of the License, or (at your option) any later version. |
|||
* |
|||
* This library is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
* Lesser General Public License for more details. |
|||
*/ |
|||
#include "qemu/osdep.h" |
|||
#include "hw/hw.h" |
|||
#include "hw/pci/pci.h" |
|||
#include "hw/scsi/scsi.h" |
|||
|
|||
#include "mptsas.h" |
|||
#include "mpi.h" |
|||
#include "trace.h" |
|||
|
|||
/* Generic functions for marshaling and unmarshaling. */ |
|||
|
|||
#define repl1(x) x |
|||
#define repl2(x) x x |
|||
#define repl3(x) x x x |
|||
#define repl4(x) x x x x |
|||
#define repl5(x) x x x x x |
|||
#define repl6(x) x x x x x x |
|||
#define repl7(x) x x x x x x x |
|||
#define repl8(x) x x x x x x x x |
|||
|
|||
#define repl(n, x) glue(repl, n)(x) |
|||
|
|||
typedef union PackValue { |
|||
uint64_t ll; |
|||
char *str; |
|||
} PackValue; |
|||
|
|||
static size_t vfill(uint8_t *data, size_t size, const char *fmt, va_list ap) |
|||
{ |
|||
size_t ofs; |
|||
PackValue val; |
|||
const char *p; |
|||
|
|||
ofs = 0; |
|||
p = fmt; |
|||
while (*p) { |
|||
memset(&val, 0, sizeof(val)); |
|||
switch (*p) { |
|||
case '*': |
|||
p++; |
|||
break; |
|||
case 'b': |
|||
case 'w': |
|||
case 'l': |
|||
val.ll = va_arg(ap, int); |
|||
break; |
|||
case 'q': |
|||
val.ll = va_arg(ap, int64_t); |
|||
break; |
|||
case 's': |
|||
val.str = va_arg(ap, void *); |
|||
break; |
|||
} |
|||
switch (*p++) { |
|||
case 'b': |
|||
if (data) { |
|||
stb_p(data + ofs, val.ll); |
|||
} |
|||
ofs++; |
|||
break; |
|||
case 'w': |
|||
if (data) { |
|||
stw_le_p(data + ofs, val.ll); |
|||
} |
|||
ofs += 2; |
|||
break; |
|||
case 'l': |
|||
if (data) { |
|||
stl_le_p(data + ofs, val.ll); |
|||
} |
|||
ofs += 4; |
|||
break; |
|||
case 'q': |
|||
if (data) { |
|||
stq_le_p(data + ofs, val.ll); |
|||
} |
|||
ofs += 8; |
|||
break; |
|||
case 's': |
|||
{ |
|||
int cnt = atoi(p); |
|||
if (data) { |
|||
if (val.str) { |
|||
strncpy((void *)data + ofs, val.str, cnt); |
|||
} else { |
|||
memset((void *)data + ofs, 0, cnt); |
|||
} |
|||
} |
|||
ofs += cnt; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return ofs; |
|||
} |
|||
|
|||
static size_t vpack(uint8_t **p_data, const char *fmt, va_list ap1) |
|||
{ |
|||
size_t size = 0; |
|||
uint8_t *data = NULL; |
|||
|
|||
if (p_data) { |
|||
va_list ap2; |
|||
|
|||
va_copy(ap2, ap1); |
|||
size = vfill(NULL, 0, fmt, ap2); |
|||
*p_data = data = g_malloc(size); |
|||
} |
|||
return vfill(data, size, fmt, ap1); |
|||
} |
|||
|
|||
static size_t fill(uint8_t *data, size_t size, const char *fmt, ...) |
|||
{ |
|||
va_list ap; |
|||
size_t ret; |
|||
|
|||
va_start(ap, fmt); |
|||
ret = vfill(data, size, fmt, ap); |
|||
va_end(ap); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
/* Functions to build the page header and fill in the length, always used
|
|||
* through the macros. |
|||
*/ |
|||
|
|||
#define MPTSAS_CONFIG_PACK(number, type, version, fmt, ...) \ |
|||
mptsas_config_pack(data, "b*bbb" fmt, version, number, type, \ |
|||
## __VA_ARGS__) |
|||
|
|||
static size_t mptsas_config_pack(uint8_t **data, const char *fmt, ...) |
|||
{ |
|||
va_list ap; |
|||
size_t ret; |
|||
|
|||
va_start(ap, fmt); |
|||
ret = vpack(data, fmt, ap); |
|||
va_end(ap); |
|||
|
|||
if (data) { |
|||
assert(ret < 256 && (ret % 4) == 0); |
|||
stb_p(*data + 1, ret / 4); |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
#define MPTSAS_CONFIG_PACK_EXT(number, type, version, fmt, ...) \ |
|||
mptsas_config_pack_ext(data, "b*bbb*wb*b" fmt, version, number, \ |
|||
MPI_CONFIG_PAGETYPE_EXTENDED, type, ## __VA_ARGS__) |
|||
|
|||
static size_t mptsas_config_pack_ext(uint8_t **data, const char *fmt, ...) |
|||
{ |
|||
va_list ap; |
|||
size_t ret; |
|||
|
|||
va_start(ap, fmt); |
|||
ret = vpack(data, fmt, ap); |
|||
va_end(ap); |
|||
|
|||
if (data) { |
|||
assert(ret < 65536 && (ret % 4) == 0); |
|||
stw_le_p(*data + 4, ret / 4); |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
/* Manufacturing pages */ |
|||
|
|||
static |
|||
size_t mptsas_config_manufacturing_0(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00, |
|||
"s16s8s16s16s16", |
|||
"QEMU MPT Fusion", |
|||
"2.5", |
|||
"QEMU MPT Fusion", |
|||
"QEMU", |
|||
"0000111122223333"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_manufacturing_1(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
/* VPD - all zeros */ |
|||
return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00, |
|||
"s256"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_manufacturing_2(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
PCIDeviceClass *pcic = PCI_DEVICE_GET_CLASS(s); |
|||
return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00, |
|||
"wb*b*l", |
|||
pcic->device_id, pcic->revision); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_manufacturing_3(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
PCIDeviceClass *pcic = PCI_DEVICE_GET_CLASS(s); |
|||
return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00, |
|||
"wb*b*l", |
|||
pcic->device_id, pcic->revision); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_manufacturing_4(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
/* All zeros */ |
|||
return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x05, |
|||
"*l*b*b*b*b*b*b*w*s56*l*l*l*l*l*l" |
|||
"*b*b*w*b*b*w*l*l"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_manufacturing_5(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(5, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x02, |
|||
"q*b*b*w*l*l", s->sas_addr); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_manufacturing_6(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(6, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00, |
|||
"*l"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_manufacturing_7(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(7, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00, |
|||
"*l*l*l*s16*b*b*w", MPTSAS_NUM_PORTS); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_manufacturing_8(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(8, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00, |
|||
"*l"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_manufacturing_9(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(9, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00, |
|||
"*l"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_manufacturing_10(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(10, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0x00, |
|||
"*l"); |
|||
} |
|||
|
|||
/* I/O unit pages */ |
|||
|
|||
static |
|||
size_t mptsas_config_io_unit_0(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
PCIDevice *pci = PCI_DEVICE(s); |
|||
uint64_t unique_value = 0x53504D554D4551LL; /* "QEMUMPTx" */ |
|||
|
|||
unique_value |= (uint64_t)pci->devfn << 56; |
|||
return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x00, |
|||
"q", unique_value); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_io_unit_1(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x02, "l", |
|||
0x41 /* single function, RAID disabled */ ); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_io_unit_2(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
PCIDevice *pci = PCI_DEVICE(s); |
|||
uint8_t devfn = pci->devfn; |
|||
return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x02, |
|||
"llbbw*b*b*w*b*b*w*b*b*w*l", |
|||
0, 0x100, 0 /* pci bus? */, devfn, 0); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_io_unit_3(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x01, |
|||
"*b*b*w*l"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_io_unit_4(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_IO_UNIT, 0x00, "*l*l*q"); |
|||
} |
|||
|
|||
/* I/O controller pages */ |
|||
|
|||
static |
|||
size_t mptsas_config_ioc_0(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
PCIDeviceClass *pcic = PCI_DEVICE_GET_CLASS(s); |
|||
|
|||
return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IOC, 0x01, |
|||
"*l*lwwb*b*b*blww", |
|||
pcic->vendor_id, pcic->device_id, pcic->revision, |
|||
pcic->subsystem_vendor_id, |
|||
pcic->subsystem_id); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_ioc_1(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_IOC, 0x03, |
|||
"*l*l*b*b*b*b"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_ioc_2(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_IOC, 0x04, |
|||
"*l*b*b*b*b"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_ioc_3(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_IOC, 0x00, |
|||
"*b*b*w"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_ioc_4(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_IOC, 0x00, |
|||
"*b*b*w"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_ioc_5(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(5, MPI_CONFIG_PAGETYPE_IOC, 0x00, |
|||
"*l*b*b*w"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_ioc_6(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK(6, MPI_CONFIG_PAGETYPE_IOC, 0x01, |
|||
"*l*b*b*b*b*b*b*b*b*b*b*w*l*l*l*l*b*b*w" |
|||
"*w*w*w*w*l*l*l"); |
|||
} |
|||
|
|||
/* SAS I/O unit pages (extended) */ |
|||
|
|||
#define MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE 16 |
|||
|
|||
#define MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION 0x02 |
|||
#define MPI_SAS_IOUNIT0_RATE_1_5 0x08 |
|||
#define MPI_SAS_IOUNIT0_RATE_3_0 0x09 |
|||
|
|||
#define MPI_SAS_DEVICE_INFO_NO_DEVICE 0x00000000 |
|||
#define MPI_SAS_DEVICE_INFO_END_DEVICE 0x00000001 |
|||
#define MPI_SAS_DEVICE_INFO_SSP_TARGET 0x00000400 |
|||
|
|||
#define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS 0x00 |
|||
|
|||
#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT 0x0001 |
|||
#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED 0x0002 |
|||
#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT 0x0004 |
|||
|
|||
|
|||
|
|||
static SCSIDevice *mptsas_phy_get_device(MPTSASState *s, int i, |
|||
int *phy_handle, int *dev_handle) |
|||
{ |
|||
SCSIDevice *d = scsi_device_find(&s->bus, 0, i, 0); |
|||
|
|||
if (phy_handle) { |
|||
*phy_handle = i + 1; |
|||
} |
|||
if (dev_handle) { |
|||
*dev_handle = d ? i + 1 + MPTSAS_NUM_PORTS : 0; |
|||
} |
|||
return d; |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_sas_io_unit_0(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
size_t size = MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x04, |
|||
"*w*wb*b*w" |
|||
repl(MPTSAS_NUM_PORTS, "*s16"), |
|||
MPTSAS_NUM_PORTS); |
|||
|
|||
if (data) { |
|||
size_t ofs = size - MPTSAS_NUM_PORTS * MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE; |
|||
int i; |
|||
|
|||
for (i = 0; i < MPTSAS_NUM_PORTS; i++) { |
|||
int phy_handle, dev_handle; |
|||
SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle); |
|||
|
|||
fill(*data + ofs, MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE, |
|||
"bbbblwwl", i, 0, 0, |
|||
(dev |
|||
? MPI_SAS_IOUNIT0_RATE_3_0 |
|||
: MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION), |
|||
(dev |
|||
? MPI_SAS_DEVICE_INFO_END_DEVICE | MPI_SAS_DEVICE_INFO_SSP_TARGET |
|||
: MPI_SAS_DEVICE_INFO_NO_DEVICE), |
|||
dev_handle, |
|||
dev_handle, |
|||
0); |
|||
ofs += MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE; |
|||
} |
|||
assert(ofs == size); |
|||
} |
|||
return size; |
|||
} |
|||
|
|||
#define MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE 12 |
|||
|
|||
static |
|||
size_t mptsas_config_sas_io_unit_1(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
size_t size = MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x07, |
|||
"*w*w*w*wb*b*b*b" |
|||
repl(MPTSAS_NUM_PORTS, "*s12"), |
|||
MPTSAS_NUM_PORTS); |
|||
|
|||
if (data) { |
|||
size_t ofs = size - MPTSAS_NUM_PORTS * MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE; |
|||
int i; |
|||
|
|||
for (i = 0; i < MPTSAS_NUM_PORTS; i++) { |
|||
SCSIDevice *dev = mptsas_phy_get_device(s, i, NULL, NULL); |
|||
fill(*data + ofs, MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE, |
|||
"bbbblww", i, 0, 0, |
|||
(MPI_SAS_IOUNIT0_RATE_3_0 << 4) | MPI_SAS_IOUNIT0_RATE_1_5, |
|||
(dev |
|||
? MPI_SAS_DEVICE_INFO_END_DEVICE | MPI_SAS_DEVICE_INFO_SSP_TARGET |
|||
: MPI_SAS_DEVICE_INFO_NO_DEVICE), |
|||
0, 0); |
|||
ofs += MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE; |
|||
} |
|||
assert(ofs == size); |
|||
} |
|||
return size; |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_sas_io_unit_2(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK_EXT(2, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x06, |
|||
"*b*b*w*w*w*b*b*w"); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_sas_io_unit_3(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
return MPTSAS_CONFIG_PACK_EXT(3, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0x06, |
|||
"*l*l*l*l*l*l*l*l*l"); |
|||
} |
|||
|
|||
/* SAS PHY pages (extended) */ |
|||
|
|||
static int mptsas_phy_addr_get(MPTSASState *s, int address) |
|||
{ |
|||
int i; |
|||
if ((address >> MPI_SAS_PHY_PGAD_FORM_SHIFT) == 0) { |
|||
i = address & 255; |
|||
} else if ((address >> MPI_SAS_PHY_PGAD_FORM_SHIFT) == 1) { |
|||
i = address & 65535; |
|||
} else { |
|||
return -EINVAL; |
|||
} |
|||
|
|||
if (i >= MPTSAS_NUM_PORTS) { |
|||
return -EINVAL; |
|||
} |
|||
|
|||
return i; |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_phy_0(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
int phy_handle = -1; |
|||
int dev_handle = -1; |
|||
int i = mptsas_phy_addr_get(s, address); |
|||
SCSIDevice *dev; |
|||
|
|||
if (i < 0) { |
|||
trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 0); |
|||
return i; |
|||
} |
|||
|
|||
dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle); |
|||
trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 0); |
|||
|
|||
return MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 0x01, |
|||
"w*wqwb*blbb*b*b*l", |
|||
dev_handle, s->sas_addr, dev_handle, i, |
|||
(dev |
|||
? MPI_SAS_DEVICE_INFO_END_DEVICE /* | MPI_SAS_DEVICE_INFO_SSP_TARGET?? */ |
|||
: MPI_SAS_DEVICE_INFO_NO_DEVICE), |
|||
(MPI_SAS_IOUNIT0_RATE_3_0 << 4) | MPI_SAS_IOUNIT0_RATE_1_5, |
|||
(MPI_SAS_IOUNIT0_RATE_3_0 << 4) | MPI_SAS_IOUNIT0_RATE_1_5); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_phy_1(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
int phy_handle = -1; |
|||
int dev_handle = -1; |
|||
int i = mptsas_phy_addr_get(s, address); |
|||
|
|||
if (i < 0) { |
|||
trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 1); |
|||
return i; |
|||
} |
|||
|
|||
(void) mptsas_phy_get_device(s, i, &phy_handle, &dev_handle); |
|||
trace_mptsas_config_sas_phy(s, address, i, phy_handle, dev_handle, 1); |
|||
|
|||
return MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 0x01, |
|||
"*l*l*l*l*l"); |
|||
} |
|||
|
|||
/* SAS device pages (extended) */ |
|||
|
|||
static int mptsas_device_addr_get(MPTSASState *s, int address) |
|||
{ |
|||
uint32_t handle, i; |
|||
uint32_t form = address >> MPI_SAS_PHY_PGAD_FORM_SHIFT; |
|||
if (form == MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) { |
|||
handle = address & MPI_SAS_DEVICE_PGAD_GNH_HANDLE_MASK; |
|||
do { |
|||
if (handle == 65535) { |
|||
handle = MPTSAS_NUM_PORTS + 1; |
|||
} else { |
|||
++handle; |
|||
} |
|||
i = handle - 1 - MPTSAS_NUM_PORTS; |
|||
} while (i < MPTSAS_NUM_PORTS && !scsi_device_find(&s->bus, 0, i, 0)); |
|||
|
|||
} else if (form == MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID) { |
|||
if (address & MPI_SAS_DEVICE_PGAD_BT_BUS_MASK) { |
|||
return -EINVAL; |
|||
} |
|||
i = address & MPI_SAS_DEVICE_PGAD_BT_TID_MASK; |
|||
|
|||
} else if (form == MPI_SAS_DEVICE_PGAD_FORM_HANDLE) { |
|||
handle = address & MPI_SAS_DEVICE_PGAD_H_HANDLE_MASK; |
|||
i = handle - 1 - MPTSAS_NUM_PORTS; |
|||
|
|||
} else { |
|||
return -EINVAL; |
|||
} |
|||
|
|||
if (i >= MPTSAS_NUM_PORTS) { |
|||
return -EINVAL; |
|||
} |
|||
|
|||
return i; |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_sas_device_0(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
int phy_handle = -1; |
|||
int dev_handle = -1; |
|||
int i = mptsas_device_addr_get(s, address); |
|||
SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle); |
|||
|
|||
trace_mptsas_config_sas_device(s, address, i, phy_handle, dev_handle, 0); |
|||
if (!dev) { |
|||
return -ENOENT; |
|||
} |
|||
|
|||
return MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0x05, |
|||
"*w*wqwbbwbblwb*b", |
|||
dev->wwn, phy_handle, i, |
|||
MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS, |
|||
dev_handle, i, 0, |
|||
MPI_SAS_DEVICE_INFO_END_DEVICE | MPI_SAS_DEVICE_INFO_SSP_TARGET, |
|||
(MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT | |
|||
MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED | |
|||
MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT), i); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_sas_device_1(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
int phy_handle = -1; |
|||
int dev_handle = -1; |
|||
int i = mptsas_device_addr_get(s, address); |
|||
SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle); |
|||
|
|||
trace_mptsas_config_sas_device(s, address, i, phy_handle, dev_handle, 1); |
|||
if (!dev) { |
|||
return -ENOENT; |
|||
} |
|||
|
|||
return MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0x00, |
|||
"*lq*lwbb*s20", |
|||
dev->wwn, dev_handle, i, 0); |
|||
} |
|||
|
|||
static |
|||
size_t mptsas_config_sas_device_2(MPTSASState *s, uint8_t **data, int address) |
|||
{ |
|||
int phy_handle = -1; |
|||
int dev_handle = -1; |
|||
int i = mptsas_device_addr_get(s, address); |
|||
SCSIDevice *dev = mptsas_phy_get_device(s, i, &phy_handle, &dev_handle); |
|||
|
|||
trace_mptsas_config_sas_device(s, address, i, phy_handle, dev_handle, 2); |
|||
if (!dev) { |
|||
return -ENOENT; |
|||
} |
|||
|
|||
return MPTSAS_CONFIG_PACK_EXT(2, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0x01, |
|||
"ql", dev->wwn, 0); |
|||
} |
|||
|
|||
typedef struct MPTSASConfigPage { |
|||
uint8_t number; |
|||
uint8_t type; |
|||
size_t (*mpt_config_build)(MPTSASState *s, uint8_t **data, int address); |
|||
} MPTSASConfigPage; |
|||
|
|||
static const MPTSASConfigPage mptsas_config_pages[] = { |
|||
{ |
|||
0, MPI_CONFIG_PAGETYPE_MANUFACTURING, |
|||
mptsas_config_manufacturing_0, |
|||
}, { |
|||
1, MPI_CONFIG_PAGETYPE_MANUFACTURING, |
|||
mptsas_config_manufacturing_1, |
|||
}, { |
|||
2, MPI_CONFIG_PAGETYPE_MANUFACTURING, |
|||
mptsas_config_manufacturing_2, |
|||
}, { |
|||
3, MPI_CONFIG_PAGETYPE_MANUFACTURING, |
|||
mptsas_config_manufacturing_3, |
|||
}, { |
|||
4, MPI_CONFIG_PAGETYPE_MANUFACTURING, |
|||
mptsas_config_manufacturing_4, |
|||
}, { |
|||
5, MPI_CONFIG_PAGETYPE_MANUFACTURING, |
|||
mptsas_config_manufacturing_5, |
|||
}, { |
|||
6, MPI_CONFIG_PAGETYPE_MANUFACTURING, |
|||
mptsas_config_manufacturing_6, |
|||
}, { |
|||
7, MPI_CONFIG_PAGETYPE_MANUFACTURING, |
|||
mptsas_config_manufacturing_7, |
|||
}, { |
|||
8, MPI_CONFIG_PAGETYPE_MANUFACTURING, |
|||
mptsas_config_manufacturing_8, |
|||
}, { |
|||
9, MPI_CONFIG_PAGETYPE_MANUFACTURING, |
|||
mptsas_config_manufacturing_9, |
|||
}, { |
|||
10, MPI_CONFIG_PAGETYPE_MANUFACTURING, |
|||
mptsas_config_manufacturing_10, |
|||
}, { |
|||
0, MPI_CONFIG_PAGETYPE_IO_UNIT, |
|||
mptsas_config_io_unit_0, |
|||
}, { |
|||
1, MPI_CONFIG_PAGETYPE_IO_UNIT, |
|||
mptsas_config_io_unit_1, |
|||
}, { |
|||
2, MPI_CONFIG_PAGETYPE_IO_UNIT, |
|||
mptsas_config_io_unit_2, |
|||
}, { |
|||
3, MPI_CONFIG_PAGETYPE_IO_UNIT, |
|||
mptsas_config_io_unit_3, |
|||
}, { |
|||
4, MPI_CONFIG_PAGETYPE_IO_UNIT, |
|||
mptsas_config_io_unit_4, |
|||
}, { |
|||
0, MPI_CONFIG_PAGETYPE_IOC, |
|||
mptsas_config_ioc_0, |
|||
}, { |
|||
1, MPI_CONFIG_PAGETYPE_IOC, |
|||
mptsas_config_ioc_1, |
|||
}, { |
|||
2, MPI_CONFIG_PAGETYPE_IOC, |
|||
mptsas_config_ioc_2, |
|||
}, { |
|||
3, MPI_CONFIG_PAGETYPE_IOC, |
|||
mptsas_config_ioc_3, |
|||
}, { |
|||
4, MPI_CONFIG_PAGETYPE_IOC, |
|||
mptsas_config_ioc_4, |
|||
}, { |
|||
5, MPI_CONFIG_PAGETYPE_IOC, |
|||
mptsas_config_ioc_5, |
|||
}, { |
|||
6, MPI_CONFIG_PAGETYPE_IOC, |
|||
mptsas_config_ioc_6, |
|||
}, { |
|||
0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, |
|||
mptsas_config_sas_io_unit_0, |
|||
}, { |
|||
1, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, |
|||
mptsas_config_sas_io_unit_1, |
|||
}, { |
|||
2, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, |
|||
mptsas_config_sas_io_unit_2, |
|||
}, { |
|||
3, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, |
|||
mptsas_config_sas_io_unit_3, |
|||
}, { |
|||
0, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, |
|||
mptsas_config_phy_0, |
|||
}, { |
|||
1, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, |
|||
mptsas_config_phy_1, |
|||
}, { |
|||
0, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, |
|||
mptsas_config_sas_device_0, |
|||
}, { |
|||
1, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, |
|||
mptsas_config_sas_device_1, |
|||
}, { |
|||
2, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, |
|||
mptsas_config_sas_device_2, |
|||
} |
|||
}; |
|||
|
|||
static const MPTSASConfigPage *mptsas_find_config_page(int type, int number) |
|||
{ |
|||
const MPTSASConfigPage *page; |
|||
int i; |
|||
|
|||
for (i = 0; i < ARRAY_SIZE(mptsas_config_pages); i++) { |
|||
page = &mptsas_config_pages[i]; |
|||
if (page->type == type && page->number == number) { |
|||
return page; |
|||
} |
|||
} |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
void mptsas_process_config(MPTSASState *s, MPIMsgConfig *req) |
|||
{ |
|||
PCIDevice *pci = PCI_DEVICE(s); |
|||
|
|||
MPIMsgConfigReply reply; |
|||
const MPTSASConfigPage *page; |
|||
size_t length; |
|||
uint8_t type; |
|||
uint8_t *data = NULL; |
|||
uint32_t flags_and_length; |
|||
uint32_t dmalen; |
|||
uint64_t pa; |
|||
|
|||
mptsas_fix_config_endianness(req); |
|||
|
|||
QEMU_BUILD_BUG_ON(sizeof(s->doorbell_msg) < sizeof(*req)); |
|||
QEMU_BUILD_BUG_ON(sizeof(s->doorbell_reply) < sizeof(reply)); |
|||
|
|||
/* Copy common bits from the request into the reply. */ |
|||
memset(&reply, 0, sizeof(reply)); |
|||
reply.Action = req->Action; |
|||
reply.Function = req->Function; |
|||
reply.MsgContext = req->MsgContext; |
|||
reply.MsgLength = sizeof(reply) / 4; |
|||
reply.PageType = req->PageType; |
|||
reply.PageNumber = req->PageNumber; |
|||
reply.PageLength = req->PageLength; |
|||
reply.PageVersion = req->PageVersion; |
|||
|
|||
type = req->PageType & MPI_CONFIG_PAGETYPE_MASK; |
|||
if (type == MPI_CONFIG_PAGETYPE_EXTENDED) { |
|||
type = req->ExtPageType; |
|||
if (type <= MPI_CONFIG_PAGETYPE_MASK) { |
|||
reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_TYPE; |
|||
goto out; |
|||
} |
|||
|
|||
reply.ExtPageType = req->ExtPageType; |
|||
} |
|||
|
|||
page = mptsas_find_config_page(type, req->PageNumber); |
|||
|
|||
switch(req->Action) { |
|||
case MPI_CONFIG_ACTION_PAGE_DEFAULT: |
|||
case MPI_CONFIG_ACTION_PAGE_HEADER: |
|||
case MPI_CONFIG_ACTION_PAGE_READ_NVRAM: |
|||
case MPI_CONFIG_ACTION_PAGE_READ_CURRENT: |
|||
case MPI_CONFIG_ACTION_PAGE_READ_DEFAULT: |
|||
case MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT: |
|||
case MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM: |
|||
break; |
|||
|
|||
default: |
|||
reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_ACTION; |
|||
goto out; |
|||
} |
|||
|
|||
if (!page) { |
|||
page = mptsas_find_config_page(type, 1); |
|||
if (page) { |
|||
reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE; |
|||
} else { |
|||
reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_TYPE; |
|||
} |
|||
goto out; |
|||
} |
|||
|
|||
if (req->Action == MPI_CONFIG_ACTION_PAGE_DEFAULT || |
|||
req->Action == MPI_CONFIG_ACTION_PAGE_HEADER) { |
|||
length = page->mpt_config_build(s, NULL, req->PageAddress); |
|||
if ((ssize_t)length < 0) { |
|||
reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE; |
|||
goto out; |
|||
} else { |
|||
goto done; |
|||
} |
|||
} |
|||
|
|||
if (req->Action == MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT || |
|||
req->Action == MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM) { |
|||
length = page->mpt_config_build(s, NULL, req->PageAddress); |
|||
if ((ssize_t)length < 0) { |
|||
reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE; |
|||
} else { |
|||
reply.IOCStatus = MPI_IOCSTATUS_CONFIG_CANT_COMMIT; |
|||
} |
|||
goto out; |
|||
} |
|||
|
|||
flags_and_length = req->PageBufferSGE.FlagsLength; |
|||
dmalen = flags_and_length & MPI_SGE_LENGTH_MASK; |
|||
if (dmalen == 0) { |
|||
length = page->mpt_config_build(s, NULL, req->PageAddress); |
|||
if ((ssize_t)length < 0) { |
|||
reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE; |
|||
goto out; |
|||
} else { |
|||
goto done; |
|||
} |
|||
} |
|||
|
|||
if (flags_and_length & MPI_SGE_FLAGS_64_BIT_ADDRESSING) { |
|||
pa = req->PageBufferSGE.u.Address64; |
|||
} else { |
|||
pa = req->PageBufferSGE.u.Address32; |
|||
} |
|||
|
|||
/* Only read actions left. */ |
|||
length = page->mpt_config_build(s, &data, req->PageAddress); |
|||
if ((ssize_t)length < 0) { |
|||
reply.IOCStatus = MPI_IOCSTATUS_CONFIG_INVALID_PAGE; |
|||
goto out; |
|||
} else { |
|||
assert(data[2] == page->number); |
|||
pci_dma_write(pci, pa, data, MIN(length, dmalen)); |
|||
goto done; |
|||
} |
|||
|
|||
abort(); |
|||
|
|||
done: |
|||
if (type > MPI_CONFIG_PAGETYPE_MASK) { |
|||
reply.ExtPageLength = length / 4; |
|||
reply.ExtPageType = req->ExtPageType; |
|||
} else { |
|||
reply.PageLength = length / 4; |
|||
} |
|||
|
|||
out: |
|||
mptsas_fix_config_reply_endianness(&reply); |
|||
mptsas_reply(s, (MPIDefaultReply *)&reply); |
|||
g_free(data); |
|||
} |
|||
@ -0,0 +1,204 @@ |
|||
/*
|
|||
* QEMU LSI SAS1068 Host Bus Adapter emulation |
|||
* Endianness conversion for MPI data structures |
|||
* |
|||
* Copyright (c) 2016 Red Hat, Inc. |
|||
* |
|||
* Authors: Paolo Bonzini <pbonzini@redhat.com> |
|||
* |
|||
* This library is free software; you can redistribute it and/or |
|||
* modify it under the terms of the GNU Lesser General Public |
|||
* License as published by the Free Software Foundation; either |
|||
* version 2 of the License, or (at your option) any later version. |
|||
* |
|||
* This library is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
* Lesser General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Lesser General Public |
|||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include "hw/hw.h" |
|||
#include "hw/pci/pci.h" |
|||
#include "sysemu/dma.h" |
|||
#include "sysemu/block-backend.h" |
|||
#include "hw/pci/msi.h" |
|||
#include "qemu/iov.h" |
|||
#include "hw/scsi/scsi.h" |
|||
#include "block/scsi.h" |
|||
#include "trace.h" |
|||
|
|||
#include "mptsas.h" |
|||
#include "mpi.h" |
|||
|
|||
static void mptsas_fix_sgentry_endianness(MPISGEntry *sge) |
|||
{ |
|||
le32_to_cpus(&sge->FlagsLength); |
|||
if (sge->FlagsLength & MPI_SGE_FLAGS_64_BIT_ADDRESSING) { |
|||
le64_to_cpus(&sge->u.Address64); |
|||
} else { |
|||
le32_to_cpus(&sge->u.Address32); |
|||
} |
|||
} |
|||
|
|||
static void mptsas_fix_sgentry_endianness_reply(MPISGEntry *sge) |
|||
{ |
|||
if (sge->FlagsLength & MPI_SGE_FLAGS_64_BIT_ADDRESSING) { |
|||
cpu_to_le64s(&sge->u.Address64); |
|||
} else { |
|||
cpu_to_le32s(&sge->u.Address32); |
|||
} |
|||
cpu_to_le32s(&sge->FlagsLength); |
|||
} |
|||
|
|||
void mptsas_fix_scsi_io_endianness(MPIMsgSCSIIORequest *req) |
|||
{ |
|||
le32_to_cpus(&req->MsgContext); |
|||
le32_to_cpus(&req->Control); |
|||
le32_to_cpus(&req->DataLength); |
|||
le32_to_cpus(&req->SenseBufferLowAddr); |
|||
} |
|||
|
|||
void mptsas_fix_scsi_io_reply_endianness(MPIMsgSCSIIOReply *reply) |
|||
{ |
|||
cpu_to_le32s(&reply->MsgContext); |
|||
cpu_to_le16s(&reply->IOCStatus); |
|||
cpu_to_le32s(&reply->IOCLogInfo); |
|||
cpu_to_le32s(&reply->TransferCount); |
|||
cpu_to_le32s(&reply->SenseCount); |
|||
cpu_to_le32s(&reply->ResponseInfo); |
|||
cpu_to_le16s(&reply->TaskTag); |
|||
} |
|||
|
|||
void mptsas_fix_scsi_task_mgmt_endianness(MPIMsgSCSITaskMgmt *req) |
|||
{ |
|||
le32_to_cpus(&req->MsgContext); |
|||
le32_to_cpus(&req->TaskMsgContext); |
|||
} |
|||
|
|||
void mptsas_fix_scsi_task_mgmt_reply_endianness(MPIMsgSCSITaskMgmtReply *reply) |
|||
{ |
|||
cpu_to_le32s(&reply->MsgContext); |
|||
cpu_to_le16s(&reply->IOCStatus); |
|||
cpu_to_le32s(&reply->IOCLogInfo); |
|||
cpu_to_le32s(&reply->TerminationCount); |
|||
} |
|||
|
|||
void mptsas_fix_ioc_init_endianness(MPIMsgIOCInit *req) |
|||
{ |
|||
le32_to_cpus(&req->MsgContext); |
|||
le16_to_cpus(&req->ReplyFrameSize); |
|||
le32_to_cpus(&req->HostMfaHighAddr); |
|||
le32_to_cpus(&req->SenseBufferHighAddr); |
|||
le32_to_cpus(&req->ReplyFifoHostSignalingAddr); |
|||
mptsas_fix_sgentry_endianness(&req->HostPageBufferSGE); |
|||
le16_to_cpus(&req->MsgVersion); |
|||
le16_to_cpus(&req->HeaderVersion); |
|||
} |
|||
|
|||
void mptsas_fix_ioc_init_reply_endianness(MPIMsgIOCInitReply *reply) |
|||
{ |
|||
cpu_to_le32s(&reply->MsgContext); |
|||
cpu_to_le16s(&reply->IOCStatus); |
|||
cpu_to_le32s(&reply->IOCLogInfo); |
|||
} |
|||
|
|||
void mptsas_fix_ioc_facts_endianness(MPIMsgIOCFacts *req) |
|||
{ |
|||
le32_to_cpus(&req->MsgContext); |
|||
} |
|||
|
|||
void mptsas_fix_ioc_facts_reply_endianness(MPIMsgIOCFactsReply *reply) |
|||
{ |
|||
cpu_to_le16s(&reply->MsgVersion); |
|||
cpu_to_le16s(&reply->HeaderVersion); |
|||
cpu_to_le32s(&reply->MsgContext); |
|||
cpu_to_le16s(&reply->IOCExceptions); |
|||
cpu_to_le16s(&reply->IOCStatus); |
|||
cpu_to_le32s(&reply->IOCLogInfo); |
|||
cpu_to_le16s(&reply->ReplyQueueDepth); |
|||
cpu_to_le16s(&reply->RequestFrameSize); |
|||
cpu_to_le16s(&reply->ProductID); |
|||
cpu_to_le32s(&reply->CurrentHostMfaHighAddr); |
|||
cpu_to_le16s(&reply->GlobalCredits); |
|||
cpu_to_le32s(&reply->CurrentSenseBufferHighAddr); |
|||
cpu_to_le16s(&reply->CurReplyFrameSize); |
|||
cpu_to_le32s(&reply->FWImageSize); |
|||
cpu_to_le32s(&reply->IOCCapabilities); |
|||
cpu_to_le16s(&reply->HighPriorityQueueDepth); |
|||
mptsas_fix_sgentry_endianness_reply(&reply->HostPageBufferSGE); |
|||
cpu_to_le32s(&reply->ReplyFifoHostSignalingAddr); |
|||
} |
|||
|
|||
void mptsas_fix_config_endianness(MPIMsgConfig *req) |
|||
{ |
|||
le16_to_cpus(&req->ExtPageLength); |
|||
le32_to_cpus(&req->MsgContext); |
|||
le32_to_cpus(&req->PageAddress); |
|||
mptsas_fix_sgentry_endianness(&req->PageBufferSGE); |
|||
} |
|||
|
|||
void mptsas_fix_config_reply_endianness(MPIMsgConfigReply *reply) |
|||
{ |
|||
cpu_to_le16s(&reply->ExtPageLength); |
|||
cpu_to_le32s(&reply->MsgContext); |
|||
cpu_to_le16s(&reply->IOCStatus); |
|||
cpu_to_le32s(&reply->IOCLogInfo); |
|||
} |
|||
|
|||
void mptsas_fix_port_facts_endianness(MPIMsgPortFacts *req) |
|||
{ |
|||
le32_to_cpus(&req->MsgContext); |
|||
} |
|||
|
|||
void mptsas_fix_port_facts_reply_endianness(MPIMsgPortFactsReply *reply) |
|||
{ |
|||
cpu_to_le32s(&reply->MsgContext); |
|||
cpu_to_le16s(&reply->IOCStatus); |
|||
cpu_to_le32s(&reply->IOCLogInfo); |
|||
cpu_to_le16s(&reply->MaxDevices); |
|||
cpu_to_le16s(&reply->PortSCSIID); |
|||
cpu_to_le16s(&reply->ProtocolFlags); |
|||
cpu_to_le16s(&reply->MaxPostedCmdBuffers); |
|||
cpu_to_le16s(&reply->MaxPersistentIDs); |
|||
cpu_to_le16s(&reply->MaxLanBuckets); |
|||
} |
|||
|
|||
void mptsas_fix_port_enable_endianness(MPIMsgPortEnable *req) |
|||
{ |
|||
le32_to_cpus(&req->MsgContext); |
|||
} |
|||
|
|||
void mptsas_fix_port_enable_reply_endianness(MPIMsgPortEnableReply *reply) |
|||
{ |
|||
cpu_to_le32s(&reply->MsgContext); |
|||
cpu_to_le16s(&reply->IOCStatus); |
|||
cpu_to_le32s(&reply->IOCLogInfo); |
|||
} |
|||
|
|||
void mptsas_fix_event_notification_endianness(MPIMsgEventNotify *req) |
|||
{ |
|||
le32_to_cpus(&req->MsgContext); |
|||
} |
|||
|
|||
void mptsas_fix_event_notification_reply_endianness(MPIMsgEventNotifyReply *reply) |
|||
{ |
|||
int length = reply->EventDataLength; |
|||
int i; |
|||
|
|||
cpu_to_le16s(&reply->EventDataLength); |
|||
cpu_to_le32s(&reply->MsgContext); |
|||
cpu_to_le16s(&reply->IOCStatus); |
|||
cpu_to_le32s(&reply->IOCLogInfo); |
|||
cpu_to_le32s(&reply->Event); |
|||
cpu_to_le32s(&reply->EventContext); |
|||
|
|||
/* Really depends on the event kind. This will do for now. */ |
|||
for (i = 0; i < length; i++) { |
|||
cpu_to_le32s(&reply->Data[i]); |
|||
} |
|||
} |
|||
|
|||
File diff suppressed because it is too large
@ -0,0 +1,100 @@ |
|||
#ifndef MPTSAS_H |
|||
#define MPTSAS_H |
|||
|
|||
#include "mpi.h" |
|||
|
|||
#define MPTSAS_NUM_PORTS 8 |
|||
#define MPTSAS_MAX_FRAMES 2048 /* Firmware limit at 65535 */ |
|||
|
|||
#define MPTSAS_REQUEST_QUEUE_DEPTH 128 |
|||
#define MPTSAS_REPLY_QUEUE_DEPTH 128 |
|||
|
|||
#define MPTSAS_MAXIMUM_CHAIN_DEPTH 0x22 |
|||
|
|||
typedef struct MPTSASState MPTSASState; |
|||
typedef struct MPTSASRequest MPTSASRequest; |
|||
|
|||
enum { |
|||
DOORBELL_NONE, |
|||
DOORBELL_WRITE, |
|||
DOORBELL_READ |
|||
}; |
|||
|
|||
struct MPTSASState { |
|||
PCIDevice dev; |
|||
MemoryRegion mmio_io; |
|||
MemoryRegion port_io; |
|||
MemoryRegion diag_io; |
|||
QEMUBH *request_bh; |
|||
|
|||
uint32_t msi_available; |
|||
uint64_t sas_addr; |
|||
|
|||
bool msi_in_use; |
|||
|
|||
/* Doorbell register */ |
|||
uint32_t state; |
|||
uint8_t who_init; |
|||
uint8_t doorbell_state; |
|||
|
|||
/* Buffer for requests that are sent through the doorbell register. */ |
|||
uint32_t doorbell_msg[256]; |
|||
int doorbell_idx; |
|||
int doorbell_cnt; |
|||
|
|||
uint16_t doorbell_reply[256]; |
|||
int doorbell_reply_idx; |
|||
int doorbell_reply_size; |
|||
|
|||
/* Other registers */ |
|||
uint8_t diagnostic_idx; |
|||
uint32_t diagnostic; |
|||
uint32_t intr_mask; |
|||
uint32_t intr_status; |
|||
|
|||
/* Request queues */ |
|||
uint32_t request_post[MPTSAS_REQUEST_QUEUE_DEPTH + 1]; |
|||
uint16_t request_post_head; |
|||
uint16_t request_post_tail; |
|||
|
|||
uint32_t reply_post[MPTSAS_REPLY_QUEUE_DEPTH + 1]; |
|||
uint16_t reply_post_head; |
|||
uint16_t reply_post_tail; |
|||
|
|||
uint32_t reply_free[MPTSAS_REPLY_QUEUE_DEPTH + 1]; |
|||
uint16_t reply_free_head; |
|||
uint16_t reply_free_tail; |
|||
|
|||
/* IOC Facts */ |
|||
hwaddr host_mfa_high_addr; |
|||
hwaddr sense_buffer_high_addr; |
|||
uint16_t max_devices; |
|||
uint16_t max_buses; |
|||
uint16_t reply_frame_size; |
|||
|
|||
SCSIBus bus; |
|||
QTAILQ_HEAD(, MPTSASRequest) pending; |
|||
}; |
|||
|
|||
void mptsas_fix_scsi_io_endianness(MPIMsgSCSIIORequest *req); |
|||
void mptsas_fix_scsi_io_reply_endianness(MPIMsgSCSIIOReply *reply); |
|||
void mptsas_fix_scsi_task_mgmt_endianness(MPIMsgSCSITaskMgmt *req); |
|||
void mptsas_fix_scsi_task_mgmt_reply_endianness(MPIMsgSCSITaskMgmtReply *reply); |
|||
void mptsas_fix_ioc_init_endianness(MPIMsgIOCInit *req); |
|||
void mptsas_fix_ioc_init_reply_endianness(MPIMsgIOCInitReply *reply); |
|||
void mptsas_fix_ioc_facts_endianness(MPIMsgIOCFacts *req); |
|||
void mptsas_fix_ioc_facts_reply_endianness(MPIMsgIOCFactsReply *reply); |
|||
void mptsas_fix_config_endianness(MPIMsgConfig *req); |
|||
void mptsas_fix_config_reply_endianness(MPIMsgConfigReply *reply); |
|||
void mptsas_fix_port_facts_endianness(MPIMsgPortFacts *req); |
|||
void mptsas_fix_port_facts_reply_endianness(MPIMsgPortFactsReply *reply); |
|||
void mptsas_fix_port_enable_endianness(MPIMsgPortEnable *req); |
|||
void mptsas_fix_port_enable_reply_endianness(MPIMsgPortEnableReply *reply); |
|||
void mptsas_fix_event_notification_endianness(MPIMsgEventNotify *req); |
|||
void mptsas_fix_event_notification_reply_endianness(MPIMsgEventNotifyReply *reply); |
|||
|
|||
void mptsas_reply(MPTSASState *s, MPIDefaultReply *reply); |
|||
|
|||
void mptsas_process_config(MPTSASState *s, MPIMsgConfig *req); |
|||
|
|||
#endif /* MPTSAS_H */ |
|||
File diff suppressed because it is too large
Loading…
Reference in new issue