xref: /openbmc/qemu/scsi/pr-manager-helper.c (revision 9bad2a6b)
1*9bad2a6bSPaolo Bonzini /*
2*9bad2a6bSPaolo Bonzini  * Persistent reservation manager that talks to qemu-pr-helper
3*9bad2a6bSPaolo Bonzini  *
4*9bad2a6bSPaolo Bonzini  * Copyright (c) 2017 Red Hat, Inc.
5*9bad2a6bSPaolo Bonzini  *
6*9bad2a6bSPaolo Bonzini  * Author: Paolo Bonzini <pbonzini@redhat.com>
7*9bad2a6bSPaolo Bonzini  *
8*9bad2a6bSPaolo Bonzini  * This code is licensed under the LGPL v2.1 or later.
9*9bad2a6bSPaolo Bonzini  *
10*9bad2a6bSPaolo Bonzini  */
11*9bad2a6bSPaolo Bonzini 
12*9bad2a6bSPaolo Bonzini #include "qemu/osdep.h"
13*9bad2a6bSPaolo Bonzini #include "qapi/error.h"
14*9bad2a6bSPaolo Bonzini #include "scsi/constants.h"
15*9bad2a6bSPaolo Bonzini #include "scsi/pr-manager.h"
16*9bad2a6bSPaolo Bonzini #include "scsi/utils.h"
17*9bad2a6bSPaolo Bonzini #include "io/channel.h"
18*9bad2a6bSPaolo Bonzini #include "io/channel-socket.h"
19*9bad2a6bSPaolo Bonzini #include "pr-helper.h"
20*9bad2a6bSPaolo Bonzini 
21*9bad2a6bSPaolo Bonzini #include <scsi/sg.h>
22*9bad2a6bSPaolo Bonzini 
23*9bad2a6bSPaolo Bonzini #define PR_MAX_RECONNECT_ATTEMPTS 5
24*9bad2a6bSPaolo Bonzini 
25*9bad2a6bSPaolo Bonzini #define TYPE_PR_MANAGER_HELPER "pr-manager-helper"
26*9bad2a6bSPaolo Bonzini 
27*9bad2a6bSPaolo Bonzini #define PR_MANAGER_HELPER(obj) \
28*9bad2a6bSPaolo Bonzini      OBJECT_CHECK(PRManagerHelper, (obj), \
29*9bad2a6bSPaolo Bonzini                   TYPE_PR_MANAGER_HELPER)
30*9bad2a6bSPaolo Bonzini 
31*9bad2a6bSPaolo Bonzini typedef struct PRManagerHelper {
32*9bad2a6bSPaolo Bonzini     /* <private> */
33*9bad2a6bSPaolo Bonzini     PRManager parent;
34*9bad2a6bSPaolo Bonzini 
35*9bad2a6bSPaolo Bonzini     char *path;
36*9bad2a6bSPaolo Bonzini 
37*9bad2a6bSPaolo Bonzini     QemuMutex lock;
38*9bad2a6bSPaolo Bonzini     QIOChannel *ioc;
39*9bad2a6bSPaolo Bonzini } PRManagerHelper;
40*9bad2a6bSPaolo Bonzini 
41*9bad2a6bSPaolo Bonzini /* Called with lock held.  */
42*9bad2a6bSPaolo Bonzini static int pr_manager_helper_read(PRManagerHelper *pr_mgr,
43*9bad2a6bSPaolo Bonzini                                   void *buf, int sz, Error **errp)
44*9bad2a6bSPaolo Bonzini {
45*9bad2a6bSPaolo Bonzini     ssize_t r = qio_channel_read_all(pr_mgr->ioc, buf, sz, errp);
46*9bad2a6bSPaolo Bonzini 
47*9bad2a6bSPaolo Bonzini     if (r < 0) {
48*9bad2a6bSPaolo Bonzini         object_unref(OBJECT(pr_mgr->ioc));
49*9bad2a6bSPaolo Bonzini         pr_mgr->ioc = NULL;
50*9bad2a6bSPaolo Bonzini         return -EINVAL;
51*9bad2a6bSPaolo Bonzini     }
52*9bad2a6bSPaolo Bonzini 
53*9bad2a6bSPaolo Bonzini     return 0;
54*9bad2a6bSPaolo Bonzini }
55*9bad2a6bSPaolo Bonzini 
56*9bad2a6bSPaolo Bonzini /* Called with lock held.  */
57*9bad2a6bSPaolo Bonzini static int pr_manager_helper_write(PRManagerHelper *pr_mgr,
58*9bad2a6bSPaolo Bonzini                                    int fd,
59*9bad2a6bSPaolo Bonzini                                    const void *buf, int sz, Error **errp)
60*9bad2a6bSPaolo Bonzini {
61*9bad2a6bSPaolo Bonzini     size_t nfds = (fd != -1);
62*9bad2a6bSPaolo Bonzini     while (sz > 0) {
63*9bad2a6bSPaolo Bonzini         struct iovec iov;
64*9bad2a6bSPaolo Bonzini         ssize_t n_written;
65*9bad2a6bSPaolo Bonzini 
66*9bad2a6bSPaolo Bonzini         iov.iov_base = (void *)buf;
67*9bad2a6bSPaolo Bonzini         iov.iov_len = sz;
68*9bad2a6bSPaolo Bonzini         n_written = qio_channel_writev_full(QIO_CHANNEL(pr_mgr->ioc), &iov, 1,
69*9bad2a6bSPaolo Bonzini                                             nfds ? &fd : NULL, nfds, errp);
70*9bad2a6bSPaolo Bonzini 
71*9bad2a6bSPaolo Bonzini         if (n_written <= 0) {
72*9bad2a6bSPaolo Bonzini             assert(n_written != QIO_CHANNEL_ERR_BLOCK);
73*9bad2a6bSPaolo Bonzini             object_unref(OBJECT(pr_mgr->ioc));
74*9bad2a6bSPaolo Bonzini             return n_written < 0 ? -EINVAL : 0;
75*9bad2a6bSPaolo Bonzini         }
76*9bad2a6bSPaolo Bonzini 
77*9bad2a6bSPaolo Bonzini         nfds = 0;
78*9bad2a6bSPaolo Bonzini         buf += n_written;
79*9bad2a6bSPaolo Bonzini         sz -= n_written;
80*9bad2a6bSPaolo Bonzini     }
81*9bad2a6bSPaolo Bonzini 
82*9bad2a6bSPaolo Bonzini     return 0;
83*9bad2a6bSPaolo Bonzini }
84*9bad2a6bSPaolo Bonzini 
85*9bad2a6bSPaolo Bonzini /* Called with lock held.  */
86*9bad2a6bSPaolo Bonzini static int pr_manager_helper_initialize(PRManagerHelper *pr_mgr,
87*9bad2a6bSPaolo Bonzini                                         Error **errp)
88*9bad2a6bSPaolo Bonzini {
89*9bad2a6bSPaolo Bonzini     char *path = g_strdup(pr_mgr->path);
90*9bad2a6bSPaolo Bonzini     SocketAddress saddr = {
91*9bad2a6bSPaolo Bonzini         .type = SOCKET_ADDRESS_TYPE_UNIX,
92*9bad2a6bSPaolo Bonzini         .u.q_unix.path = path
93*9bad2a6bSPaolo Bonzini     };
94*9bad2a6bSPaolo Bonzini     QIOChannelSocket *sioc = qio_channel_socket_new();
95*9bad2a6bSPaolo Bonzini     Error *local_err = NULL;
96*9bad2a6bSPaolo Bonzini 
97*9bad2a6bSPaolo Bonzini     uint32_t flags;
98*9bad2a6bSPaolo Bonzini     int r;
99*9bad2a6bSPaolo Bonzini 
100*9bad2a6bSPaolo Bonzini     assert(!pr_mgr->ioc);
101*9bad2a6bSPaolo Bonzini     qio_channel_set_name(QIO_CHANNEL(sioc), "pr-manager-helper");
102*9bad2a6bSPaolo Bonzini     qio_channel_socket_connect_sync(sioc,
103*9bad2a6bSPaolo Bonzini                                     &saddr,
104*9bad2a6bSPaolo Bonzini                                     &local_err);
105*9bad2a6bSPaolo Bonzini     g_free(path);
106*9bad2a6bSPaolo Bonzini     if (local_err) {
107*9bad2a6bSPaolo Bonzini         object_unref(OBJECT(sioc));
108*9bad2a6bSPaolo Bonzini         error_propagate(errp, local_err);
109*9bad2a6bSPaolo Bonzini         return -ENOTCONN;
110*9bad2a6bSPaolo Bonzini     }
111*9bad2a6bSPaolo Bonzini 
112*9bad2a6bSPaolo Bonzini     qio_channel_set_delay(QIO_CHANNEL(sioc), false);
113*9bad2a6bSPaolo Bonzini     pr_mgr->ioc = QIO_CHANNEL(sioc);
114*9bad2a6bSPaolo Bonzini 
115*9bad2a6bSPaolo Bonzini     /* A simple feature negotation protocol, even though there is
116*9bad2a6bSPaolo Bonzini      * no optional feature right now.
117*9bad2a6bSPaolo Bonzini      */
118*9bad2a6bSPaolo Bonzini     r = pr_manager_helper_read(pr_mgr, &flags, sizeof(flags), errp);
119*9bad2a6bSPaolo Bonzini     if (r < 0) {
120*9bad2a6bSPaolo Bonzini         goto out_close;
121*9bad2a6bSPaolo Bonzini     }
122*9bad2a6bSPaolo Bonzini 
123*9bad2a6bSPaolo Bonzini     flags = 0;
124*9bad2a6bSPaolo Bonzini     r = pr_manager_helper_write(pr_mgr, -1, &flags, sizeof(flags), errp);
125*9bad2a6bSPaolo Bonzini     if (r < 0) {
126*9bad2a6bSPaolo Bonzini         goto out_close;
127*9bad2a6bSPaolo Bonzini     }
128*9bad2a6bSPaolo Bonzini 
129*9bad2a6bSPaolo Bonzini     return 0;
130*9bad2a6bSPaolo Bonzini 
131*9bad2a6bSPaolo Bonzini out_close:
132*9bad2a6bSPaolo Bonzini     object_unref(OBJECT(pr_mgr->ioc));
133*9bad2a6bSPaolo Bonzini     pr_mgr->ioc = NULL;
134*9bad2a6bSPaolo Bonzini     return r;
135*9bad2a6bSPaolo Bonzini }
136*9bad2a6bSPaolo Bonzini 
137*9bad2a6bSPaolo Bonzini static int pr_manager_helper_run(PRManager *p,
138*9bad2a6bSPaolo Bonzini                                  int fd, struct sg_io_hdr *io_hdr)
139*9bad2a6bSPaolo Bonzini {
140*9bad2a6bSPaolo Bonzini     PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(p);
141*9bad2a6bSPaolo Bonzini 
142*9bad2a6bSPaolo Bonzini     uint32_t len;
143*9bad2a6bSPaolo Bonzini     PRHelperResponse resp;
144*9bad2a6bSPaolo Bonzini     int ret;
145*9bad2a6bSPaolo Bonzini     int expected_dir;
146*9bad2a6bSPaolo Bonzini     int attempts;
147*9bad2a6bSPaolo Bonzini     uint8_t cdb[PR_HELPER_CDB_SIZE] = { 0 };
148*9bad2a6bSPaolo Bonzini 
149*9bad2a6bSPaolo Bonzini     if (!io_hdr->cmd_len || io_hdr->cmd_len > PR_HELPER_CDB_SIZE) {
150*9bad2a6bSPaolo Bonzini         return -EINVAL;
151*9bad2a6bSPaolo Bonzini     }
152*9bad2a6bSPaolo Bonzini 
153*9bad2a6bSPaolo Bonzini     memcpy(cdb, io_hdr->cmdp, io_hdr->cmd_len);
154*9bad2a6bSPaolo Bonzini     assert(cdb[0] == PERSISTENT_RESERVE_OUT || cdb[0] == PERSISTENT_RESERVE_IN);
155*9bad2a6bSPaolo Bonzini     expected_dir =
156*9bad2a6bSPaolo Bonzini         (cdb[0] == PERSISTENT_RESERVE_OUT ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV);
157*9bad2a6bSPaolo Bonzini     if (io_hdr->dxfer_direction != expected_dir) {
158*9bad2a6bSPaolo Bonzini         return -EINVAL;
159*9bad2a6bSPaolo Bonzini     }
160*9bad2a6bSPaolo Bonzini 
161*9bad2a6bSPaolo Bonzini     len = scsi_cdb_xfer(cdb);
162*9bad2a6bSPaolo Bonzini     if (io_hdr->dxfer_len < len || len > PR_HELPER_DATA_SIZE) {
163*9bad2a6bSPaolo Bonzini         return -EINVAL;
164*9bad2a6bSPaolo Bonzini     }
165*9bad2a6bSPaolo Bonzini 
166*9bad2a6bSPaolo Bonzini     qemu_mutex_lock(&pr_mgr->lock);
167*9bad2a6bSPaolo Bonzini 
168*9bad2a6bSPaolo Bonzini     /* Try to reconnect while sending the CDB.  */
169*9bad2a6bSPaolo Bonzini     for (attempts = 0; attempts < PR_MAX_RECONNECT_ATTEMPTS; attempts++) {
170*9bad2a6bSPaolo Bonzini         if (!pr_mgr->ioc) {
171*9bad2a6bSPaolo Bonzini             ret = pr_manager_helper_initialize(pr_mgr, NULL);
172*9bad2a6bSPaolo Bonzini             if (ret < 0) {
173*9bad2a6bSPaolo Bonzini                 qemu_mutex_unlock(&pr_mgr->lock);
174*9bad2a6bSPaolo Bonzini                 g_usleep(G_USEC_PER_SEC);
175*9bad2a6bSPaolo Bonzini                 qemu_mutex_lock(&pr_mgr->lock);
176*9bad2a6bSPaolo Bonzini                 continue;
177*9bad2a6bSPaolo Bonzini             }
178*9bad2a6bSPaolo Bonzini         }
179*9bad2a6bSPaolo Bonzini 
180*9bad2a6bSPaolo Bonzini         ret = pr_manager_helper_write(pr_mgr, fd, cdb, ARRAY_SIZE(cdb), NULL);
181*9bad2a6bSPaolo Bonzini         if (ret >= 0) {
182*9bad2a6bSPaolo Bonzini             break;
183*9bad2a6bSPaolo Bonzini         }
184*9bad2a6bSPaolo Bonzini     }
185*9bad2a6bSPaolo Bonzini     if (ret < 0) {
186*9bad2a6bSPaolo Bonzini         goto out;
187*9bad2a6bSPaolo Bonzini     }
188*9bad2a6bSPaolo Bonzini 
189*9bad2a6bSPaolo Bonzini     /* After sending the CDB, any communications failure causes the
190*9bad2a6bSPaolo Bonzini      * command to fail.  The failure is transient, retrying the command
191*9bad2a6bSPaolo Bonzini      * will invoke pr_manager_helper_initialize again.
192*9bad2a6bSPaolo Bonzini      */
193*9bad2a6bSPaolo Bonzini     if (expected_dir == SG_DXFER_TO_DEV) {
194*9bad2a6bSPaolo Bonzini         io_hdr->resid = io_hdr->dxfer_len - len;
195*9bad2a6bSPaolo Bonzini         ret = pr_manager_helper_write(pr_mgr, -1, io_hdr->dxferp, len, NULL);
196*9bad2a6bSPaolo Bonzini         if (ret < 0) {
197*9bad2a6bSPaolo Bonzini             goto out;
198*9bad2a6bSPaolo Bonzini         }
199*9bad2a6bSPaolo Bonzini     }
200*9bad2a6bSPaolo Bonzini     ret = pr_manager_helper_read(pr_mgr, &resp, sizeof(resp), NULL);
201*9bad2a6bSPaolo Bonzini     if (ret < 0) {
202*9bad2a6bSPaolo Bonzini         goto out;
203*9bad2a6bSPaolo Bonzini     }
204*9bad2a6bSPaolo Bonzini 
205*9bad2a6bSPaolo Bonzini     resp.result = be32_to_cpu(resp.result);
206*9bad2a6bSPaolo Bonzini     resp.sz = be32_to_cpu(resp.sz);
207*9bad2a6bSPaolo Bonzini     if (io_hdr->dxfer_direction == SG_DXFER_FROM_DEV) {
208*9bad2a6bSPaolo Bonzini         assert(resp.sz <= io_hdr->dxfer_len);
209*9bad2a6bSPaolo Bonzini         ret = pr_manager_helper_read(pr_mgr, io_hdr->dxferp, resp.sz, NULL);
210*9bad2a6bSPaolo Bonzini         if (ret < 0) {
211*9bad2a6bSPaolo Bonzini             goto out;
212*9bad2a6bSPaolo Bonzini         }
213*9bad2a6bSPaolo Bonzini         io_hdr->resid = io_hdr->dxfer_len - resp.sz;
214*9bad2a6bSPaolo Bonzini     } else {
215*9bad2a6bSPaolo Bonzini         assert(resp.sz == 0);
216*9bad2a6bSPaolo Bonzini     }
217*9bad2a6bSPaolo Bonzini 
218*9bad2a6bSPaolo Bonzini     io_hdr->status = resp.result;
219*9bad2a6bSPaolo Bonzini     if (resp.result == CHECK_CONDITION) {
220*9bad2a6bSPaolo Bonzini         io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
221*9bad2a6bSPaolo Bonzini         io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, PR_HELPER_SENSE_SIZE);
222*9bad2a6bSPaolo Bonzini         memcpy(io_hdr->sbp, resp.sense, io_hdr->sb_len_wr);
223*9bad2a6bSPaolo Bonzini     }
224*9bad2a6bSPaolo Bonzini 
225*9bad2a6bSPaolo Bonzini out:
226*9bad2a6bSPaolo Bonzini     if (ret < 0) {
227*9bad2a6bSPaolo Bonzini         int sense_len = scsi_build_sense(io_hdr->sbp,
228*9bad2a6bSPaolo Bonzini                                          SENSE_CODE(LUN_COMM_FAILURE));
229*9bad2a6bSPaolo Bonzini         io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
230*9bad2a6bSPaolo Bonzini         io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, sense_len);
231*9bad2a6bSPaolo Bonzini         io_hdr->status = CHECK_CONDITION;
232*9bad2a6bSPaolo Bonzini     }
233*9bad2a6bSPaolo Bonzini     qemu_mutex_unlock(&pr_mgr->lock);
234*9bad2a6bSPaolo Bonzini     return ret;
235*9bad2a6bSPaolo Bonzini }
236*9bad2a6bSPaolo Bonzini 
237*9bad2a6bSPaolo Bonzini static void pr_manager_helper_complete(UserCreatable *uc, Error **errp)
238*9bad2a6bSPaolo Bonzini {
239*9bad2a6bSPaolo Bonzini     PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(uc);
240*9bad2a6bSPaolo Bonzini 
241*9bad2a6bSPaolo Bonzini     qemu_mutex_lock(&pr_mgr->lock);
242*9bad2a6bSPaolo Bonzini     pr_manager_helper_initialize(pr_mgr, errp);
243*9bad2a6bSPaolo Bonzini     qemu_mutex_unlock(&pr_mgr->lock);
244*9bad2a6bSPaolo Bonzini }
245*9bad2a6bSPaolo Bonzini 
246*9bad2a6bSPaolo Bonzini static char *get_path(Object *obj, Error **errp)
247*9bad2a6bSPaolo Bonzini {
248*9bad2a6bSPaolo Bonzini     PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
249*9bad2a6bSPaolo Bonzini 
250*9bad2a6bSPaolo Bonzini     return g_strdup(pr_mgr->path);
251*9bad2a6bSPaolo Bonzini }
252*9bad2a6bSPaolo Bonzini 
253*9bad2a6bSPaolo Bonzini static void set_path(Object *obj, const char *str, Error **errp)
254*9bad2a6bSPaolo Bonzini {
255*9bad2a6bSPaolo Bonzini     PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
256*9bad2a6bSPaolo Bonzini 
257*9bad2a6bSPaolo Bonzini     g_free(pr_mgr->path);
258*9bad2a6bSPaolo Bonzini     pr_mgr->path = g_strdup(str);
259*9bad2a6bSPaolo Bonzini }
260*9bad2a6bSPaolo Bonzini 
261*9bad2a6bSPaolo Bonzini static void pr_manager_helper_instance_finalize(Object *obj)
262*9bad2a6bSPaolo Bonzini {
263*9bad2a6bSPaolo Bonzini     PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
264*9bad2a6bSPaolo Bonzini 
265*9bad2a6bSPaolo Bonzini     object_unref(OBJECT(pr_mgr->ioc));
266*9bad2a6bSPaolo Bonzini     qemu_mutex_destroy(&pr_mgr->lock);
267*9bad2a6bSPaolo Bonzini }
268*9bad2a6bSPaolo Bonzini 
269*9bad2a6bSPaolo Bonzini static void pr_manager_helper_instance_init(Object *obj)
270*9bad2a6bSPaolo Bonzini {
271*9bad2a6bSPaolo Bonzini     PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
272*9bad2a6bSPaolo Bonzini 
273*9bad2a6bSPaolo Bonzini     qemu_mutex_init(&pr_mgr->lock);
274*9bad2a6bSPaolo Bonzini }
275*9bad2a6bSPaolo Bonzini 
276*9bad2a6bSPaolo Bonzini static void pr_manager_helper_class_init(ObjectClass *klass,
277*9bad2a6bSPaolo Bonzini                                          void *class_data G_GNUC_UNUSED)
278*9bad2a6bSPaolo Bonzini {
279*9bad2a6bSPaolo Bonzini     PRManagerClass *prmgr_klass = PR_MANAGER_CLASS(klass);
280*9bad2a6bSPaolo Bonzini     UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass);
281*9bad2a6bSPaolo Bonzini 
282*9bad2a6bSPaolo Bonzini     object_class_property_add_str(klass, "path", get_path, set_path,
283*9bad2a6bSPaolo Bonzini                                   &error_abort);
284*9bad2a6bSPaolo Bonzini     uc_klass->complete = pr_manager_helper_complete;
285*9bad2a6bSPaolo Bonzini     prmgr_klass->run = pr_manager_helper_run;
286*9bad2a6bSPaolo Bonzini }
287*9bad2a6bSPaolo Bonzini 
288*9bad2a6bSPaolo Bonzini static const TypeInfo pr_manager_helper_info = {
289*9bad2a6bSPaolo Bonzini     .parent = TYPE_PR_MANAGER,
290*9bad2a6bSPaolo Bonzini     .name = TYPE_PR_MANAGER_HELPER,
291*9bad2a6bSPaolo Bonzini     .instance_size = sizeof(PRManagerHelper),
292*9bad2a6bSPaolo Bonzini     .instance_init = pr_manager_helper_instance_init,
293*9bad2a6bSPaolo Bonzini     .instance_finalize = pr_manager_helper_instance_finalize,
294*9bad2a6bSPaolo Bonzini     .class_init = pr_manager_helper_class_init,
295*9bad2a6bSPaolo Bonzini };
296*9bad2a6bSPaolo Bonzini 
297*9bad2a6bSPaolo Bonzini static void pr_manager_helper_register_types(void)
298*9bad2a6bSPaolo Bonzini {
299*9bad2a6bSPaolo Bonzini     type_register_static(&pr_manager_helper_info);
300*9bad2a6bSPaolo Bonzini }
301*9bad2a6bSPaolo Bonzini 
302*9bad2a6bSPaolo Bonzini type_init(pr_manager_helper_register_types);
303