]>
Commit | Line | Data |
---|---|---|
a8eac943 DJS |
1 | /* |
2 | * s390 CCW Assignment Support | |
3 | * | |
4 | * Copyright 2017 IBM Corp | |
5 | * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> | |
6 | * Xiao Feng Ren <renxiaof@linux.vnet.ibm.com> | |
7 | * Pierre Morel <pmorel@linux.vnet.ibm.com> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2 | |
10 | * or (at your option) any later version. See the COPYING file in the | |
11 | * top-level directory. | |
12 | */ | |
d8e39b70 | 13 | |
a8eac943 | 14 | #include "qemu/osdep.h" |
d8e39b70 | 15 | #include <libgen.h> |
a8eac943 DJS |
16 | #include "qapi/error.h" |
17 | #include "hw/sysbus.h" | |
a8eac943 DJS |
18 | #include "hw/s390x/css.h" |
19 | #include "hw/s390x/css-bridge.h" | |
20 | #include "hw/s390x/s390-ccw.h" | |
21 | ||
66dc50f7 | 22 | IOInstEnding s390_ccw_cmd_request(SubchDev *sch) |
bab482d7 | 23 | { |
66dc50f7 | 24 | S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(sch->driver_data); |
bab482d7 | 25 | |
66dc50f7 HP |
26 | if (!cdc->handle_request) { |
27 | return IOINST_CC_STATUS_PRESENT; | |
bab482d7 | 28 | } |
66dc50f7 | 29 | return cdc->handle_request(sch); |
bab482d7 XFR |
30 | } |
31 | ||
a8eac943 DJS |
32 | static void s390_ccw_get_dev_info(S390CCWDevice *cdev, |
33 | char *sysfsdev, | |
34 | Error **errp) | |
35 | { | |
36 | unsigned int cssid, ssid, devid; | |
37 | char dev_path[PATH_MAX] = {0}, *tmp; | |
38 | ||
39 | if (!sysfsdev) { | |
40 | error_setg(errp, "No host device provided"); | |
41 | error_append_hint(errp, | |
42 | "Use -device vfio-ccw,sysfsdev=PATH_TO_DEVICE\n"); | |
43 | return; | |
44 | } | |
45 | ||
46 | if (!realpath(sysfsdev, dev_path)) { | |
47 | error_setg_errno(errp, errno, "Host device '%s' not found", sysfsdev); | |
48 | return; | |
49 | } | |
50 | ||
51 | cdev->mdevid = g_strdup(basename(dev_path)); | |
52 | ||
53 | tmp = basename(dirname(dev_path)); | |
54 | if (sscanf(tmp, "%2x.%1x.%4x", &cssid, &ssid, &devid) != 3) { | |
55 | error_setg_errno(errp, errno, "Failed to read %s", tmp); | |
56 | return; | |
57 | } | |
58 | ||
59 | cdev->hostid.cssid = cssid; | |
60 | cdev->hostid.ssid = ssid; | |
61 | cdev->hostid.devid = devid; | |
62 | cdev->hostid.valid = true; | |
63 | } | |
64 | ||
65 | static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp) | |
66 | { | |
67 | CcwDevice *ccw_dev = CCW_DEVICE(cdev); | |
68 | CCWDeviceClass *ck = CCW_DEVICE_GET_CLASS(ccw_dev); | |
69 | DeviceState *parent = DEVICE(ccw_dev); | |
70 | BusState *qbus = qdev_get_parent_bus(parent); | |
71 | VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus); | |
72 | SubchDev *sch; | |
73 | int ret; | |
74 | Error *err = NULL; | |
75 | ||
76 | s390_ccw_get_dev_info(cdev, sysfsdev, &err); | |
77 | if (err) { | |
78 | goto out_err_propagate; | |
79 | } | |
80 | ||
99577c49 | 81 | sch = css_create_sch(ccw_dev->devno, cbus->squash_mcss, &err); |
a8eac943 DJS |
82 | if (!sch) { |
83 | goto out_mdevid_free; | |
84 | } | |
85 | sch->driver_data = cdev; | |
bab482d7 | 86 | sch->do_subchannel_work = do_subchannel_work_passthrough; |
a8eac943 DJS |
87 | |
88 | ccw_dev->sch = sch; | |
89 | ret = css_sch_build_schib(sch, &cdev->hostid); | |
90 | if (ret) { | |
91 | error_setg_errno(&err, -ret, "%s: Failed to build initial schib", | |
92 | __func__); | |
93 | goto out_err; | |
94 | } | |
95 | ||
96 | ck->realize(ccw_dev, &err); | |
97 | if (err) { | |
98 | goto out_err; | |
99 | } | |
100 | ||
101 | css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, | |
102 | parent->hotplugged, 1); | |
103 | return; | |
104 | ||
105 | out_err: | |
106 | css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); | |
107 | ccw_dev->sch = NULL; | |
108 | g_free(sch); | |
109 | out_mdevid_free: | |
110 | g_free(cdev->mdevid); | |
111 | out_err_propagate: | |
112 | error_propagate(errp, err); | |
113 | } | |
114 | ||
115 | static void s390_ccw_unrealize(S390CCWDevice *cdev, Error **errp) | |
116 | { | |
117 | CcwDevice *ccw_dev = CCW_DEVICE(cdev); | |
118 | SubchDev *sch = ccw_dev->sch; | |
119 | ||
120 | if (sch) { | |
121 | css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); | |
122 | g_free(sch); | |
123 | ccw_dev->sch = NULL; | |
124 | } | |
125 | ||
126 | g_free(cdev->mdevid); | |
127 | } | |
128 | ||
129 | static void s390_ccw_class_init(ObjectClass *klass, void *data) | |
130 | { | |
131 | DeviceClass *dc = DEVICE_CLASS(klass); | |
132 | S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass); | |
133 | ||
134 | dc->bus_type = TYPE_VIRTUAL_CSS_BUS; | |
135 | cdc->realize = s390_ccw_realize; | |
136 | cdc->unrealize = s390_ccw_unrealize; | |
137 | } | |
138 | ||
139 | static const TypeInfo s390_ccw_info = { | |
140 | .name = TYPE_S390_CCW, | |
141 | .parent = TYPE_CCW_DEVICE, | |
142 | .instance_size = sizeof(S390CCWDevice), | |
143 | .class_size = sizeof(S390CCWDeviceClass), | |
144 | .class_init = s390_ccw_class_init, | |
145 | .abstract = true, | |
146 | }; | |
147 | ||
148 | static void register_s390_ccw_type(void) | |
149 | { | |
150 | type_register_static(&s390_ccw_info); | |
151 | } | |
152 | ||
153 | type_init(register_s390_ccw_type) |