2 * QEMU LSI SAS1068 Host Bus Adapter emulation - configuration pages
4 * Copyright (c) 2016 Red Hat, Inc.
6 * Author: Paolo Bonzini
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.
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.
18 #include "qemu/osdep.h"
20 #include "hw/pci/pci.h"
21 #include "hw/scsi/scsi.h"
27 /* Generic functions for marshaling and unmarshaling. */
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
38 #define repl(n, x) glue(repl, n)(x)
40 typedef union PackValue
{
45 static size_t vfill(uint8_t *data
, size_t size
, const char *fmt
, va_list ap
)
54 memset(&val
, 0, sizeof(val
));
62 val
.ll
= va_arg(ap
, int);
65 val
.ll
= va_arg(ap
, int64_t);
68 val
.str
= va_arg(ap
, void *);
74 stb_p(data
+ ofs
, val
.ll
);
80 stw_le_p(data
+ ofs
, val
.ll
);
86 stl_le_p(data
+ ofs
, val
.ll
);
92 stq_le_p(data
+ ofs
, val
.ll
);
101 strncpy((void *)data
+ ofs
, val
.str
, cnt
);
103 memset((void *)data
+ ofs
, 0, cnt
);
115 static size_t vpack(uint8_t **p_data
, const char *fmt
, va_list ap1
)
118 uint8_t *data
= NULL
;
124 size
= vfill(NULL
, 0, fmt
, ap2
);
125 *p_data
= data
= g_malloc(size
);
128 return vfill(data
, size
, fmt
, ap1
);
131 static size_t fill(uint8_t *data
, size_t size
, const char *fmt
, ...)
137 ret
= vfill(data
, size
, fmt
, ap
);
143 /* Functions to build the page header and fill in the length, always used
144 * through the macros.
147 #define MPTSAS_CONFIG_PACK(number, type, version, fmt, ...) \
148 mptsas_config_pack(data, "b*bbb" fmt, version, number, type, \
151 static size_t mptsas_config_pack(uint8_t **data
, const char *fmt
, ...)
157 ret
= vpack(data
, fmt
, ap
);
161 assert(ret
/ 4 < 256 && (ret
% 4) == 0);
162 stb_p(*data
+ 1, ret
/ 4);
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__)
171 static size_t mptsas_config_pack_ext(uint8_t **data
, const char *fmt
, ...)
177 ret
= vpack(data
, fmt
, ap
);
181 assert(ret
< 65536 && (ret
% 4) == 0);
182 stw_le_p(*data
+ 4, ret
/ 4);
187 /* Manufacturing pages */
190 size_t mptsas_config_manufacturing_0(MPTSASState
*s
, uint8_t **data
, int address
)
192 return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
202 size_t mptsas_config_manufacturing_1(MPTSASState
*s
, uint8_t **data
, int address
)
204 /* VPD - all zeros */
205 return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
210 size_t mptsas_config_manufacturing_2(MPTSASState
*s
, uint8_t **data
, int address
)
212 PCIDeviceClass
*pcic
= PCI_DEVICE_GET_CLASS(s
);
213 return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
215 pcic
->device_id
, pcic
->revision
);
219 size_t mptsas_config_manufacturing_3(MPTSASState
*s
, uint8_t **data
, int address
)
221 PCIDeviceClass
*pcic
= PCI_DEVICE_GET_CLASS(s
);
222 return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
224 pcic
->device_id
, pcic
->revision
);
228 size_t mptsas_config_manufacturing_4(MPTSASState
*s
, uint8_t **data
, int address
)
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"
237 size_t mptsas_config_manufacturing_5(MPTSASState
*s
, uint8_t **data
, int address
)
239 return MPTSAS_CONFIG_PACK(5, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x02,
240 "q*b*b*w*l*l", s
->sas_addr
);
244 size_t mptsas_config_manufacturing_6(MPTSASState
*s
, uint8_t **data
, int address
)
246 return MPTSAS_CONFIG_PACK(6, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
251 size_t mptsas_config_manufacturing_7(MPTSASState
*s
, uint8_t **data
, int address
)
253 return MPTSAS_CONFIG_PACK(7, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
254 "*l*l*l*s16*b*b*w", MPTSAS_NUM_PORTS
);
258 size_t mptsas_config_manufacturing_8(MPTSASState
*s
, uint8_t **data
, int address
)
260 return MPTSAS_CONFIG_PACK(8, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
265 size_t mptsas_config_manufacturing_9(MPTSASState
*s
, uint8_t **data
, int address
)
267 return MPTSAS_CONFIG_PACK(9, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
272 size_t mptsas_config_manufacturing_10(MPTSASState
*s
, uint8_t **data
, int address
)
274 return MPTSAS_CONFIG_PACK(10, MPI_CONFIG_PAGETYPE_MANUFACTURING
, 0x00,
281 size_t mptsas_config_io_unit_0(MPTSASState
*s
, uint8_t **data
, int address
)
283 PCIDevice
*pci
= PCI_DEVICE(s
);
284 uint64_t unique_value
= 0x53504D554D4551LL
; /* "QEMUMPTx" */
286 unique_value
|= (uint64_t)pci
->devfn
<< 56;
287 return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IO_UNIT
, 0x00,
292 size_t mptsas_config_io_unit_1(MPTSASState
*s
, uint8_t **data
, int address
)
294 return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_IO_UNIT
, 0x02, "l",
295 0x41 /* single function, RAID disabled */ );
299 size_t mptsas_config_io_unit_2(MPTSASState
*s
, uint8_t **data
, int address
)
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);
309 size_t mptsas_config_io_unit_3(MPTSASState
*s
, uint8_t **data
, int address
)
311 return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_IO_UNIT
, 0x01,
316 size_t mptsas_config_io_unit_4(MPTSASState
*s
, uint8_t **data
, int address
)
318 return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_IO_UNIT
, 0x00, "*l*l*q");
321 /* I/O controller pages */
324 size_t mptsas_config_ioc_0(MPTSASState
*s
, uint8_t **data
, int address
)
326 PCIDeviceClass
*pcic
= PCI_DEVICE_GET_CLASS(s
);
328 return MPTSAS_CONFIG_PACK(0, MPI_CONFIG_PAGETYPE_IOC
, 0x01,
330 pcic
->vendor_id
, pcic
->device_id
, pcic
->revision
,
331 pcic
->class_id
, pcic
->subsystem_vendor_id
,
336 size_t mptsas_config_ioc_1(MPTSASState
*s
, uint8_t **data
, int address
)
338 return MPTSAS_CONFIG_PACK(1, MPI_CONFIG_PAGETYPE_IOC
, 0x03,
343 size_t mptsas_config_ioc_2(MPTSASState
*s
, uint8_t **data
, int address
)
345 return MPTSAS_CONFIG_PACK(2, MPI_CONFIG_PAGETYPE_IOC
, 0x04,
350 size_t mptsas_config_ioc_3(MPTSASState
*s
, uint8_t **data
, int address
)
352 return MPTSAS_CONFIG_PACK(3, MPI_CONFIG_PAGETYPE_IOC
, 0x00,
357 size_t mptsas_config_ioc_4(MPTSASState
*s
, uint8_t **data
, int address
)
359 return MPTSAS_CONFIG_PACK(4, MPI_CONFIG_PAGETYPE_IOC
, 0x00,
364 size_t mptsas_config_ioc_5(MPTSASState
*s
, uint8_t **data
, int address
)
366 return MPTSAS_CONFIG_PACK(5, MPI_CONFIG_PAGETYPE_IOC
, 0x00,
371 size_t mptsas_config_ioc_6(MPTSASState
*s
, uint8_t **data
, int address
)
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"
378 /* SAS I/O unit pages (extended) */
380 #define MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE 16
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
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
390 #define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS 0x00
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
398 static SCSIDevice
*mptsas_phy_get_device(MPTSASState
*s
, int i
,
399 int *phy_handle
, int *dev_handle
)
401 SCSIDevice
*d
= scsi_device_find(&s
->bus
, 0, i
, 0);
407 *dev_handle
= d
? i
+ 1 + MPTSAS_NUM_PORTS
: 0;
413 size_t mptsas_config_sas_io_unit_0(MPTSASState
*s
, uint8_t **data
, int address
)
415 size_t size
= MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
, 0x04,
417 repl(MPTSAS_NUM_PORTS
, "*s16"),
421 size_t ofs
= size
- MPTSAS_NUM_PORTS
* MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE
;
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
);
428 fill(*data
+ ofs
, MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE
,
431 ? MPI_SAS_IOUNIT0_RATE_3_0
432 : MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION
),
434 ? MPI_SAS_DEVICE_INFO_END_DEVICE
| MPI_SAS_DEVICE_INFO_SSP_TARGET
435 : MPI_SAS_DEVICE_INFO_NO_DEVICE
),
439 ofs
+= MPTSAS_CONFIG_SAS_IO_UNIT_0_SIZE
;
446 #define MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE 12
449 size_t mptsas_config_sas_io_unit_1(MPTSASState
*s
, uint8_t **data
, int address
)
451 size_t size
= MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
, 0x07,
453 repl(MPTSAS_NUM_PORTS
, "*s12"),
457 size_t ofs
= size
- MPTSAS_NUM_PORTS
* MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE
;
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
,
464 (MPI_SAS_IOUNIT0_RATE_3_0
<< 4) | MPI_SAS_IOUNIT0_RATE_1_5
,
466 ? MPI_SAS_DEVICE_INFO_END_DEVICE
| MPI_SAS_DEVICE_INFO_SSP_TARGET
467 : MPI_SAS_DEVICE_INFO_NO_DEVICE
),
469 ofs
+= MPTSAS_CONFIG_SAS_IO_UNIT_1_SIZE
;
477 size_t mptsas_config_sas_io_unit_2(MPTSASState
*s
, uint8_t **data
, int address
)
479 return MPTSAS_CONFIG_PACK_EXT(2, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
, 0x06,
484 size_t mptsas_config_sas_io_unit_3(MPTSASState
*s
, uint8_t **data
, int address
)
486 return MPTSAS_CONFIG_PACK_EXT(3, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
, 0x06,
487 "*l*l*l*l*l*l*l*l*l");
490 /* SAS PHY pages (extended) */
492 static int mptsas_phy_addr_get(MPTSASState
*s
, int address
)
495 if ((address
>> MPI_SAS_PHY_PGAD_FORM_SHIFT
) == 0) {
497 } else if ((address
>> MPI_SAS_PHY_PGAD_FORM_SHIFT
) == 1) {
503 if (i
>= MPTSAS_NUM_PORTS
) {
511 size_t mptsas_config_phy_0(MPTSASState
*s
, uint8_t **data
, int address
)
515 int i
= mptsas_phy_addr_get(s
, address
);
519 trace_mptsas_config_sas_phy(s
, address
, i
, phy_handle
, dev_handle
, 0);
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);
526 return MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_PHY
, 0x01,
528 dev_handle
, s
->sas_addr
, dev_handle
, i
,
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
);
537 size_t mptsas_config_phy_1(MPTSASState
*s
, uint8_t **data
, int address
)
541 int i
= mptsas_phy_addr_get(s
, address
);
544 trace_mptsas_config_sas_phy(s
, address
, i
, phy_handle
, dev_handle
, 1);
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);
551 return MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_PHY
, 0x01,
555 /* SAS device pages (extended) */
557 static int mptsas_device_addr_get(MPTSASState
*s
, int address
)
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
;
564 if (handle
== 65535) {
565 handle
= MPTSAS_NUM_PORTS
+ 1;
569 i
= handle
- 1 - MPTSAS_NUM_PORTS
;
570 } while (i
< MPTSAS_NUM_PORTS
&& !scsi_device_find(&s
->bus
, 0, i
, 0));
572 } else if (form
== MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
) {
573 if (address
& MPI_SAS_DEVICE_PGAD_BT_BUS_MASK
) {
576 i
= address
& MPI_SAS_DEVICE_PGAD_BT_TID_MASK
;
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
;
586 if (i
>= MPTSAS_NUM_PORTS
) {
594 size_t mptsas_config_sas_device_0(MPTSASState
*s
, uint8_t **data
, int address
)
598 int i
= mptsas_device_addr_get(s
, address
);
599 SCSIDevice
*dev
= mptsas_phy_get_device(s
, i
, &phy_handle
, &dev_handle
);
601 trace_mptsas_config_sas_device(s
, address
, i
, phy_handle
, dev_handle
, 0);
606 return MPTSAS_CONFIG_PACK_EXT(0, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE
, 0x05,
608 dev
->wwn
, phy_handle
, i
,
609 MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS
,
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
);
618 size_t mptsas_config_sas_device_1(MPTSASState
*s
, uint8_t **data
, int address
)
622 int i
= mptsas_device_addr_get(s
, address
);
623 SCSIDevice
*dev
= mptsas_phy_get_device(s
, i
, &phy_handle
, &dev_handle
);
625 trace_mptsas_config_sas_device(s
, address
, i
, phy_handle
, dev_handle
, 1);
630 return MPTSAS_CONFIG_PACK_EXT(1, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE
, 0x00,
632 dev
->wwn
, dev_handle
, i
, 0);
636 size_t mptsas_config_sas_device_2(MPTSASState
*s
, uint8_t **data
, int address
)
640 int i
= mptsas_device_addr_get(s
, address
);
641 SCSIDevice
*dev
= mptsas_phy_get_device(s
, i
, &phy_handle
, &dev_handle
);
643 trace_mptsas_config_sas_device(s
, address
, i
, phy_handle
, dev_handle
, 2);
648 return MPTSAS_CONFIG_PACK_EXT(2, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE
, 0x01,
652 typedef struct MPTSASConfigPage
{
655 size_t (*mpt_config_build
)(MPTSASState
*s
, uint8_t **data
, int address
);
658 static const MPTSASConfigPage mptsas_config_pages
[] = {
660 0, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
661 mptsas_config_manufacturing_0
,
663 1, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
664 mptsas_config_manufacturing_1
,
666 2, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
667 mptsas_config_manufacturing_2
,
669 3, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
670 mptsas_config_manufacturing_3
,
672 4, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
673 mptsas_config_manufacturing_4
,
675 5, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
676 mptsas_config_manufacturing_5
,
678 6, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
679 mptsas_config_manufacturing_6
,
681 7, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
682 mptsas_config_manufacturing_7
,
684 8, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
685 mptsas_config_manufacturing_8
,
687 9, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
688 mptsas_config_manufacturing_9
,
690 10, MPI_CONFIG_PAGETYPE_MANUFACTURING
,
691 mptsas_config_manufacturing_10
,
693 0, MPI_CONFIG_PAGETYPE_IO_UNIT
,
694 mptsas_config_io_unit_0
,
696 1, MPI_CONFIG_PAGETYPE_IO_UNIT
,
697 mptsas_config_io_unit_1
,
699 2, MPI_CONFIG_PAGETYPE_IO_UNIT
,
700 mptsas_config_io_unit_2
,
702 3, MPI_CONFIG_PAGETYPE_IO_UNIT
,
703 mptsas_config_io_unit_3
,
705 4, MPI_CONFIG_PAGETYPE_IO_UNIT
,
706 mptsas_config_io_unit_4
,
708 0, MPI_CONFIG_PAGETYPE_IOC
,
711 1, MPI_CONFIG_PAGETYPE_IOC
,
714 2, MPI_CONFIG_PAGETYPE_IOC
,
717 3, MPI_CONFIG_PAGETYPE_IOC
,
720 4, MPI_CONFIG_PAGETYPE_IOC
,
723 5, MPI_CONFIG_PAGETYPE_IOC
,
726 6, MPI_CONFIG_PAGETYPE_IOC
,
729 0, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
,
730 mptsas_config_sas_io_unit_0
,
732 1, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
,
733 mptsas_config_sas_io_unit_1
,
735 2, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
,
736 mptsas_config_sas_io_unit_2
,
738 3, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
,
739 mptsas_config_sas_io_unit_3
,
741 0, MPI_CONFIG_EXTPAGETYPE_SAS_PHY
,
744 1, MPI_CONFIG_EXTPAGETYPE_SAS_PHY
,
747 0, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE
,
748 mptsas_config_sas_device_0
,
750 1, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE
,
751 mptsas_config_sas_device_1
,
753 2, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE
,
754 mptsas_config_sas_device_2
,
758 static const MPTSASConfigPage
*mptsas_find_config_page(int type
, int number
)
760 const MPTSASConfigPage
*page
;
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
) {
773 void mptsas_process_config(MPTSASState
*s
, MPIMsgConfig
*req
)
775 PCIDevice
*pci
= PCI_DEVICE(s
);
777 MPIMsgConfigReply reply
;
778 const MPTSASConfigPage
*page
;
781 uint8_t *data
= NULL
;
782 uint32_t flags_and_length
;
786 mptsas_fix_config_endianness(req
);
788 QEMU_BUILD_BUG_ON(sizeof(s
->doorbell_msg
) < sizeof(*req
));
789 QEMU_BUILD_BUG_ON(sizeof(s
->doorbell_reply
) < sizeof(reply
));
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
;
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
;
810 reply
.ExtPageType
= req
->ExtPageType
;
813 page
= mptsas_find_config_page(type
, req
->PageNumber
);
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
:
826 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_INVALID_ACTION
;
831 page
= mptsas_find_config_page(type
, 1);
833 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_INVALID_PAGE
;
835 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_INVALID_TYPE
;
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
;
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
;
857 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_CANT_COMMIT
;
862 flags_and_length
= req
->PageBufferSGE
.FlagsLength
;
863 dmalen
= flags_and_length
& MPI_SGE_LENGTH_MASK
;
865 length
= page
->mpt_config_build(s
, NULL
, req
->PageAddress
);
866 if ((ssize_t
)length
< 0) {
867 reply
.IOCStatus
= MPI_IOCSTATUS_CONFIG_INVALID_PAGE
;
874 if (flags_and_length
& MPI_SGE_FLAGS_64_BIT_ADDRESSING
) {
875 pa
= req
->PageBufferSGE
.u
.Address64
;
877 pa
= req
->PageBufferSGE
.u
.Address32
;
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
;
886 assert(data
[2] == page
->number
);
887 pci_dma_write(pci
, pa
, data
, MIN(length
, dmalen
));
894 if (type
> MPI_CONFIG_PAGETYPE_MASK
) {
895 reply
.ExtPageLength
= length
/ 4;
896 reply
.ExtPageType
= req
->ExtPageType
;
898 reply
.PageLength
= length
/ 4;
902 mptsas_fix_config_reply_endianness(&reply
);
903 mptsas_reply(s
, (MPIDefaultReply
*)&reply
);