1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28 #include <sys/errno.h>
29 #include <sys/types.h>
30 #include <sys/conf.h>
31 #include <sys/kmem.h>
32 #include <sys/ddi.h>
33 #include <sys/stat.h>
34 #include <sys/sunddi.h>
35 #include <sys/file.h>
36 #include <sys/open.h>
37 #include <sys/modctl.h>
38 #include <sys/ddi_impldefs.h>
39 #include <sys/sysmacros.h>
40 #include <sys/ddidevmap.h>
41 #include <sys/xendev.h>
42 #include <public/io/protocols.h>
43 #include <xen/io/blkif_impl.h>
44
45 #include "blk_common.h"
46
47
48 /* blk interface status */
49 enum blk_if_state {
50 /*
51 * initial state
52 */
53 BLK_IF_UNKNOWN = 0,
54 /*
55 * frontend xenbus state changed to XenbusStateConnected,
56 * we finally connect
57 */
58 BLK_IF_CONNECTED,
59 /*
60 * frontend xenbus state changed to XenbusStateClosed,
61 * interface disconnected
62 */
63 BLK_IF_DISCONNECTED
64 };
65
66 /* backend device status */
67 enum blk_be_state {
68 /* initial state */
69 BLK_BE_UNKNOWN = 0,
70 /* backend device is ready (hotplug script finishes successfully) */
71 BLK_BE_READY
72 };
73
74 /* frontend status */
75 enum blk_fe_state {
76 /* initial state */
77 BLK_FE_UNKNOWN = 0,
78 /*
79 * frontend's xenbus state has changed to
80 * XenbusStateInitialised, is ready for connecting
81 */
82 BLK_FE_READY
83 };
84
85 typedef struct blk_ring_state_s {
86 kmutex_t rs_mutex;
87 boolean_t rs_sleeping_on_ring;
88 boolean_t rs_ring_up;
89 kcondvar_t rs_cv;
90 } blk_ring_state_t;
91
92 /* Disk Statistics */
93 static char *blk_stats[] = {
94 "rd_reqs",
95 "wr_reqs",
96 "br_reqs",
97 "fl_reqs",
98 "oo_reqs"
99 };
100
101 typedef struct blk_stats_s {
102 uint64_t bs_req_reads;
103 uint64_t bs_req_writes;
104 uint64_t bs_req_barriers;
105 uint64_t bs_req_flushes;
106 } blk_stats_t;
107
108 struct blk_ring_s {
109 kmutex_t ri_mutex;
110 dev_info_t *ri_dip;
111
112 kstat_t *ri_kstats;
113 blk_stats_t ri_stats;
114
115 blk_intr_t ri_intr;
116 caddr_t ri_intr_arg;
117 blk_ring_cb_t ri_ringup;
118 caddr_t ri_ringup_arg;
119 blk_ring_cb_t ri_ringdown;
120 caddr_t ri_ringdown_arg;
121
122 /* blk interface, backend, and frontend status */
123 enum blk_if_state ri_if_status;
124 enum blk_be_state ri_be_status;
125 enum blk_fe_state ri_fe_status;
126
127 domid_t ri_fe;
128
129 enum blkif_protocol ri_protocol;
130 size_t ri_nentry;
131 size_t ri_entrysize;
132
133 xendev_ring_t *ri_ring;
134 blk_ring_state_t ri_state;
135 };
136
137
138 static void blk_oe_state_change(dev_info_t *dip, ddi_eventcookie_t id,
139 void *arg, void *impl_data);
140 static void blk_hp_state_change(dev_info_t *dip, ddi_eventcookie_t id,
141 void *arg, void *impl_data);
142 static int blk_check_state_transition(blk_ring_t ring, XenbusState oestate);
143 static int blk_start_connect(blk_ring_t ring);
144 static void blk_start_disconnect(blk_ring_t ring);
145 static void blk_ring_close(blk_ring_t ring);
146 static int blk_bindto_frontend(blk_ring_t ring);
147 static void blk_unbindfrom_frontend(blk_ring_t ring);
148 static uint_t blk_intr(caddr_t arg);
149
150 static int blk_kstat_init(blk_ring_t ring);
151 static void blk_kstat_fini(blk_ring_t ring);
152 static int blk_kstat_update(kstat_t *ksp, int flag);
153
154 static void blk_ring_request_32(blkif_request_t *dst,
155 blkif_x86_32_request_t *src);
156 static void blk_ring_request_64(blkif_request_t *dst,
157 blkif_x86_64_request_t *src);
158
159 static void blk_ring_response_32(blkif_x86_32_response_t *dst,
160 blkif_response_t *src);
161 static void blk_ring_response_64(blkif_x86_64_response_t *dst,
162 blkif_response_t *src);
163
164
165 /*
166 * blk_ring_init()
167 */
168 int
blk_ring_init(blk_ringinit_args_t * args,blk_ring_t * ringp)169 blk_ring_init(blk_ringinit_args_t *args, blk_ring_t *ringp)
170 {
171 blk_ring_t ring;
172 int e;
173
174
175 ring = kmem_zalloc(sizeof (struct blk_ring_s), KM_SLEEP);
176 mutex_init(&ring->ri_mutex, NULL, MUTEX_DRIVER, NULL);
177 ring->ri_dip = args->ar_dip;
178 ring->ri_intr = args->ar_intr;
179 ring->ri_intr_arg = args->ar_intr_arg;
180 ring->ri_ringup = args->ar_ringup;
181 ring->ri_ringup_arg = args->ar_ringup_arg;
182 ring->ri_ringdown = args->ar_ringdown;
183 ring->ri_ringdown_arg = args->ar_ringdown_arg;
184
185 ring->ri_if_status = BLK_IF_UNKNOWN;
186 ring->ri_be_status = BLK_BE_UNKNOWN;
187 ring->ri_fe_status = BLK_FE_UNKNOWN;
188 ring->ri_state.rs_sleeping_on_ring = B_FALSE;
189 ring->ri_state.rs_ring_up = B_FALSE;
190
191 mutex_init(&ring->ri_state.rs_mutex, NULL, MUTEX_DRIVER, NULL);
192 cv_init(&ring->ri_state.rs_cv, NULL, CV_DRIVER, NULL);
193
194 e = blk_kstat_init(ring);
195 if (e != DDI_SUCCESS) {
196 goto ringinitfail_kstat;
197 }
198
199 /* Watch frontend and hotplug state change */
200 if (xvdi_add_event_handler(ring->ri_dip, XS_OE_STATE,
201 blk_oe_state_change, ring) != DDI_SUCCESS) {
202 goto ringinitfail_oestate;
203 }
204 if (xvdi_add_event_handler(ring->ri_dip, XS_HP_STATE,
205 blk_hp_state_change, ring) != DDI_SUCCESS) {
206 goto ringinitfail_hpstate;
207 }
208
209 /*
210 * Kick-off hotplug script
211 */
212 if (xvdi_post_event(ring->ri_dip, XEN_HP_ADD) != DDI_SUCCESS) {
213 cmn_err(CE_WARN, "blk@%s: failed to start hotplug script",
214 ddi_get_name_addr(ring->ri_dip));
215 goto ringinitfail_postevent;
216 }
217
218 /*
219 * start waiting for hotplug event and otherend state event
220 * mainly for debugging, frontend will not take any op seeing this
221 */
222 (void) xvdi_switch_state(ring->ri_dip, XBT_NULL, XenbusStateInitWait);
223
224 *ringp = ring;
225 return (DDI_SUCCESS);
226
227 ringinitfail_postevent:
228 xvdi_remove_event_handler(ring->ri_dip, XS_HP_STATE);
229 ringinitfail_hpstate:
230 xvdi_remove_event_handler(ring->ri_dip, XS_OE_STATE);
231 ringinitfail_oestate:
232 blk_kstat_fini(ring);
233 ringinitfail_kstat:
234 cv_destroy(&ring->ri_state.rs_cv);
235 mutex_destroy(&ring->ri_state.rs_mutex);
236 mutex_destroy(&ring->ri_mutex);
237 kmem_free(ring, sizeof (struct blk_ring_s));
238 return (DDI_FAILURE);
239 }
240
241
242 /*
243 * blk_ring_fini()
244 */
245 void
blk_ring_fini(blk_ring_t * ringp)246 blk_ring_fini(blk_ring_t *ringp)
247 {
248 blk_ring_t ring;
249
250
251 ring = *ringp;
252
253 mutex_enter(&ring->ri_mutex);
254 if (ring->ri_if_status != BLK_IF_DISCONNECTED) {
255 blk_ring_close(ring);
256 }
257 mutex_exit(&ring->ri_mutex);
258
259 xvdi_remove_event_handler(ring->ri_dip, NULL);
260 blk_kstat_fini(ring);
261 cv_destroy(&ring->ri_state.rs_cv);
262 mutex_destroy(&ring->ri_state.rs_mutex);
263 mutex_destroy(&ring->ri_mutex);
264 kmem_free(ring, sizeof (struct blk_ring_s));
265
266 *ringp = NULL;
267 }
268
269
270 /*
271 * blk_kstat_init()
272 */
273 static int
blk_kstat_init(blk_ring_t ring)274 blk_kstat_init(blk_ring_t ring)
275 {
276 int nstat = sizeof (blk_stats) / sizeof (blk_stats[0]);
277 char **cp = blk_stats;
278 kstat_named_t *knp;
279
280 ring->ri_kstats = kstat_create(ddi_get_name(ring->ri_dip),
281 ddi_get_instance(ring->ri_dip), "req_statistics", "block",
282 KSTAT_TYPE_NAMED, nstat, 0);
283 if (ring->ri_kstats == NULL) {
284 return (DDI_FAILURE);
285 }
286
287 ring->ri_kstats->ks_private = ring;
288 ring->ri_kstats->ks_update = blk_kstat_update;
289
290 knp = ring->ri_kstats->ks_data;
291 while (nstat > 0) {
292 kstat_named_init(knp, *cp, KSTAT_DATA_UINT64);
293 knp++;
294 cp++;
295 nstat--;
296 }
297
298 kstat_install(ring->ri_kstats);
299
300 return (DDI_SUCCESS);
301 }
302
303
304 /*
305 * blk_kstat_fini()
306 */
307 static void
blk_kstat_fini(blk_ring_t ring)308 blk_kstat_fini(blk_ring_t ring)
309 {
310 kstat_delete(ring->ri_kstats);
311 }
312
313
314 /*
315 * blk_kstat_update()
316 */
317 static int
blk_kstat_update(kstat_t * ksp,int flag)318 blk_kstat_update(kstat_t *ksp, int flag)
319 {
320 kstat_named_t *knp;
321 blk_stats_t *stats;
322 blk_ring_t ring;
323
324
325 if (flag != KSTAT_READ) {
326 return (EACCES);
327 }
328
329 ring = ksp->ks_private;
330 stats = &ring->ri_stats;
331 knp = ksp->ks_data;
332
333 /*
334 * Assignment order should match that of the names in
335 * blk_stats.
336 */
337 (knp++)->value.ui64 = stats->bs_req_reads;
338 (knp++)->value.ui64 = stats->bs_req_writes;
339 (knp++)->value.ui64 = stats->bs_req_barriers;
340 (knp++)->value.ui64 = stats->bs_req_flushes;
341 (knp++)->value.ui64 = 0; /* oo_req */
342
343 return (0);
344 }
345
346
347 /*
348 * blk_oe_state_change()
349 */
350 /*ARGSUSED*/
351 static void
blk_oe_state_change(dev_info_t * dip,ddi_eventcookie_t id,void * arg,void * impl_data)352 blk_oe_state_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg,
353 void *impl_data)
354 {
355 XenbusState new_state;
356 blk_ring_t ring;
357
358
359 ring = (blk_ring_t)arg;
360 new_state = *(XenbusState *)impl_data;
361
362 mutex_enter(&ring->ri_mutex);
363
364 if (blk_check_state_transition(ring, new_state) == DDI_FAILURE) {
365 mutex_exit(&ring->ri_mutex);
366 return;
367 }
368
369 switch (new_state) {
370 case XenbusStateInitialised:
371 ASSERT(ring->ri_if_status == BLK_IF_UNKNOWN);
372
373 /* frontend is ready for connecting */
374 ring->ri_fe_status = BLK_FE_READY;
375
376 if (ring->ri_be_status == BLK_BE_READY) {
377 mutex_exit(&ring->ri_mutex);
378 if (blk_start_connect(ring) != DDI_SUCCESS)
379 (void) blk_start_disconnect(ring);
380 mutex_enter(&ring->ri_mutex);
381 }
382 break;
383 case XenbusStateClosing:
384 (void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosing);
385 break;
386 case XenbusStateClosed:
387 /* clean up */
388 (void) xvdi_post_event(ring->ri_dip, XEN_HP_REMOVE);
389 if (ring->ri_ringdown != NULL) {
390 (*(ring->ri_ringdown))(ring->ri_ringdown_arg);
391 }
392 blk_ring_close(ring);
393
394 /* reset state in case of reconnect */
395 ring->ri_if_status = BLK_IF_UNKNOWN;
396 ring->ri_be_status = BLK_BE_UNKNOWN;
397 ring->ri_fe_status = BLK_FE_UNKNOWN;
398 ring->ri_state.rs_sleeping_on_ring = B_FALSE;
399 ring->ri_state.rs_ring_up = B_FALSE;
400
401 break;
402 default:
403 ASSERT(0);
404 }
405
406 mutex_exit(&ring->ri_mutex);
407 }
408
409
410 /*
411 * blk_hp_state_change()
412 */
413 /*ARGSUSED*/
414 static void
blk_hp_state_change(dev_info_t * dip,ddi_eventcookie_t id,void * arg,void * impl_data)415 blk_hp_state_change(dev_info_t *dip, ddi_eventcookie_t id, void *arg,
416 void *impl_data)
417 {
418 xendev_hotplug_state_t hpstate;
419 blk_ring_t ring;
420
421
422 ring = (blk_ring_t)arg;
423 hpstate = *(xendev_hotplug_state_t *)impl_data;
424
425 mutex_enter(&ring->ri_mutex);
426 if (hpstate == Connected) {
427 /* Hotplug script has completed successfully */
428 if (ring->ri_be_status == BLK_BE_UNKNOWN) {
429 ring->ri_be_status = BLK_BE_READY;
430 if (ring->ri_fe_status == BLK_FE_READY) {
431 mutex_exit(&ring->ri_mutex);
432 /* try to connect to frontend */
433 if (blk_start_connect(ring) != DDI_SUCCESS)
434 (void) blk_start_disconnect(ring);
435 mutex_enter(&ring->ri_mutex);
436 }
437 }
438 }
439 mutex_exit(&ring->ri_mutex);
440 }
441
442
443 /*
444 * blk_check_state_transition()
445 * check the XenbusState change to see if the change is a valid transition
446 * or not. The new state is written by frontend domain, or by running
447 * xenstore-write to change it manually in dom0.
448 */
449 static int
blk_check_state_transition(blk_ring_t ring,XenbusState oestate)450 blk_check_state_transition(blk_ring_t ring, XenbusState oestate)
451 {
452 switch (ring->ri_if_status) {
453 case BLK_IF_UNKNOWN:
454 if (ring->ri_fe_status == BLK_FE_UNKNOWN) {
455 if ((oestate == XenbusStateUnknown) ||
456 (oestate == XenbusStateConnected))
457 goto statechkfail_bug;
458 else if ((oestate == XenbusStateInitialising) ||
459 (oestate == XenbusStateInitWait))
460 goto statechkfail_nop;
461 } else {
462 if ((oestate == XenbusStateUnknown) ||
463 (oestate == XenbusStateInitialising) ||
464 (oestate == XenbusStateInitWait) ||
465 (oestate == XenbusStateConnected))
466 goto statechkfail_bug;
467 else if (oestate == XenbusStateInitialised)
468 goto statechkfail_nop;
469 }
470 break;
471
472 case BLK_IF_CONNECTED:
473 if ((oestate == XenbusStateUnknown) ||
474 (oestate == XenbusStateInitialising) ||
475 (oestate == XenbusStateInitWait) ||
476 (oestate == XenbusStateInitialised))
477 goto statechkfail_bug;
478 else if (oestate == XenbusStateConnected)
479 goto statechkfail_nop;
480 break;
481
482 case BLK_IF_DISCONNECTED:
483 default:
484 goto statechkfail_bug;
485 }
486
487 return (DDI_SUCCESS);
488
489 statechkfail_bug:
490 cmn_err(CE_NOTE, "blk@%s: unexpected otherend "
491 "state change to %d!, when status is %d",
492 ddi_get_name_addr(ring->ri_dip), oestate,
493 ring->ri_if_status);
494
495 statechkfail_nop:
496 return (DDI_FAILURE);
497 }
498
499
500 /*
501 * blk_start_connect()
502 * Kick-off connect process
503 * If ri_fe_status == BLK_FE_READY and ri_be_status == BLK_BE_READY
504 * the ri_if_status will be changed to BLK_IF_CONNECTED on success,
505 * otherwise, ri_if_status will not be changed
506 */
507 static int
blk_start_connect(blk_ring_t ring)508 blk_start_connect(blk_ring_t ring)
509 {
510 xenbus_transaction_t xbt;
511 dev_info_t *dip;
512 char *barrier;
513 char *xsnode;
514 uint_t len;
515 int e;
516
517
518 dip = ring->ri_dip;
519
520 /*
521 * Start connect to frontend only when backend device are ready
522 * and frontend has moved to XenbusStateInitialised, which means
523 * ready to connect
524 */
525 ASSERT(ring->ri_fe_status == BLK_FE_READY);
526 ASSERT(ring->ri_be_status == BLK_BE_READY);
527
528 xsnode = xvdi_get_xsname(dip);
529 if (xsnode == NULL) {
530 goto startconnectfail_get_xsname;
531 }
532
533 ring->ri_fe = xvdi_get_oeid(dip);
534 if (ring->ri_fe == (domid_t)-1) {
535 goto startconnectfail_get_oeid;
536 }
537
538 e = xvdi_switch_state(dip, XBT_NULL, XenbusStateInitialised);
539 if (e > 0) {
540 goto startconnectfail_switch_init;
541 }
542
543 e = blk_bindto_frontend(ring);
544 if (e != DDI_SUCCESS) {
545 goto startconnectfail_bindto_frontend;
546 }
547 ring->ri_if_status = BLK_IF_CONNECTED;
548
549 e = ddi_add_intr(dip, 0, NULL, NULL, blk_intr, (caddr_t)ring);
550 if (e != DDI_SUCCESS) {
551 goto startconnectfail_add_intr;
552 }
553
554 trans_retry:
555 e = xenbus_transaction_start(&xbt);
556 if (e != 0) {
557 xvdi_fatal_error(dip, e, "transaction start");
558 goto startconnectfail_transaction_start;
559 }
560
561 /* xentop requires the instance in xenstore */
562 e = xenbus_printf(xbt, xsnode, "instance", "%d",
563 ddi_get_instance(ring->ri_dip));
564 if (e != 0) {
565 cmn_err(CE_WARN, "xdb@%s: failed to write 'instance'",
566 ddi_get_name_addr(dip));
567 xvdi_fatal_error(dip, e, "writing 'instance'");
568 (void) xenbus_transaction_end(xbt, 1);
569 goto startconnectfail_xenbus_printf;
570 }
571
572 /* If feature-barrier isn't present in xenstore, add it */
573 e = xenbus_read(xbt, xsnode, "feature-barrier", (void **)&barrier,
574 &len);
575 if (e != 0) {
576 e = xenbus_printf(xbt, xsnode, "feature-barrier", "%d", 1);
577 if (e != 0) {
578 cmn_err(CE_WARN, "xdb@%s: failed to write "
579 "'feature-barrier'", ddi_get_name_addr(dip));
580 xvdi_fatal_error(dip, e, "writing 'feature-barrier'");
581 (void) xenbus_transaction_end(xbt, 1);
582 goto startconnectfail_xenbus_printf;
583 }
584 } else {
585 kmem_free(barrier, len);
586 }
587
588 e = xvdi_switch_state(dip, xbt, XenbusStateConnected);
589 if (e > 0) {
590 xvdi_fatal_error(dip, e, "writing 'state'");
591 (void) xenbus_transaction_end(xbt, 1);
592 goto startconnectfail_switch_connected;
593 }
594
595 e = xenbus_transaction_end(xbt, 0);
596 if (e != 0) {
597 if (e == EAGAIN) {
598 /* transaction is ended, don't need to abort it */
599 goto trans_retry;
600 }
601 xvdi_fatal_error(dip, e, "completing transaction");
602 goto startconnectfail_transaction_end;
603 }
604
605 mutex_enter(&ring->ri_state.rs_mutex);
606 ring->ri_state.rs_ring_up = B_TRUE;
607 if (ring->ri_state.rs_sleeping_on_ring) {
608 ring->ri_state.rs_sleeping_on_ring = B_FALSE;
609 cv_signal(&ring->ri_state.rs_cv);
610 }
611 mutex_exit(&ring->ri_state.rs_mutex);
612
613 if (ring->ri_ringup != NULL) {
614 (*(ring->ri_ringup))(ring->ri_ringup_arg);
615 }
616
617 return (DDI_SUCCESS);
618
619
620 startconnectfail_transaction_end:
621 startconnectfail_switch_connected:
622 startconnectfail_xenbus_printf:
623 startconnectfail_transaction_start:
624 ddi_remove_intr(dip, 0, NULL);
625 startconnectfail_add_intr:
626 blk_unbindfrom_frontend(ring);
627 ring->ri_fe = (domid_t)-1;
628 startconnectfail_bindto_frontend:
629 (void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosed);
630 startconnectfail_switch_init:
631 startconnectfail_get_oeid:
632 startconnectfail_get_xsname:
633 return (DDI_FAILURE);
634 }
635
636
637 /*
638 * blk_start_disconnect()
639 * Kick-off disconnect process. ri_if_status will not be changed
640 */
641 static void
blk_start_disconnect(blk_ring_t ring)642 blk_start_disconnect(blk_ring_t ring)
643 {
644 /* Kick-off disconnect process */
645 (void) xvdi_switch_state(ring->ri_dip, XBT_NULL, XenbusStateClosing);
646 }
647
648
649 /*
650 * blk_ring_close()
651 * Disconnect from frontend and close backend device
652 * ifstatus will be changed to BLK_DISCONNECTED
653 * Xenbus state will be changed to XenbusStateClosed
654 */
655 static void
blk_ring_close(blk_ring_t ring)656 blk_ring_close(blk_ring_t ring)
657 {
658 dev_info_t *dip;
659
660
661 /* mutex protect ri_if_status only here */
662 ASSERT(MUTEX_HELD(&ring->ri_mutex));
663
664 dip = ring->ri_dip;
665
666 if (ring->ri_if_status != BLK_IF_CONNECTED) {
667 return;
668 }
669
670 ring->ri_if_status = BLK_IF_DISCONNECTED;
671 mutex_exit(&ring->ri_mutex);
672
673 /* stop accepting I/O request from frontend */
674 ddi_remove_intr(dip, 0, NULL);
675
676 blk_unbindfrom_frontend(ring);
677 ring->ri_fe = (domid_t)-1;
678 (void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosed);
679 mutex_enter(&ring->ri_mutex);
680 }
681
682
683 /*
684 * blk_bindto_frontend()
685 */
686 static int
blk_bindto_frontend(blk_ring_t ring)687 blk_bindto_frontend(blk_ring_t ring)
688 {
689 evtchn_port_t evtchn;
690 char protocol[64];
691 grant_ref_t gref;
692 dev_info_t *dip;
693 char *oename;
694 int e;
695
696
697 dip = ring->ri_dip;
698 protocol[0] = 0x0;
699
700 /*
701 * Gather info from frontend
702 */
703 oename = xvdi_get_oename(dip);
704 if (oename == NULL) {
705 return (DDI_FAILURE);
706 }
707
708 e = xenbus_gather(XBT_NULL, oename, "ring-ref", "%lu", &gref,
709 "event-channel", "%u", &evtchn, NULL);
710 if (e != 0) {
711 xvdi_fatal_error(dip, e,
712 "Getting ring-ref and evtchn from frontend");
713 return (DDI_FAILURE);
714 }
715
716 e = xenbus_gather(XBT_NULL, oename, "protocol", "%63s",
717 protocol, NULL);
718 if (e != 0) {
719 (void) strcpy(protocol, "unspecified, assuming native");
720 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE) == 0) {
721 ring->ri_protocol = BLKIF_PROTOCOL_NATIVE;
722 ring->ri_nentry = BLKIF_RING_SIZE;
723 ring->ri_entrysize = sizeof (union blkif_sring_entry);
724 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
725 ring->ri_protocol = BLKIF_PROTOCOL_X86_32;
726 ring->ri_nentry = BLKIF_X86_32_RING_SIZE;
727 ring->ri_entrysize = sizeof (union blkif_x86_32_sring_entry);
728 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
729 ring->ri_protocol = BLKIF_PROTOCOL_X86_64;
730 ring->ri_nentry = BLKIF_X86_64_RING_SIZE;
731 ring->ri_entrysize = sizeof (union blkif_x86_64_sring_entry);
732 } else {
733 xvdi_fatal_error(dip, e, "unknown fe protocol");
734 return (DDI_FAILURE);
735 }
736
737 /*
738 * map and init ring
739 */
740 e = xvdi_map_ring(dip, ring->ri_nentry, ring->ri_entrysize, gref,
741 &ring->ri_ring);
742 if (e != DDI_SUCCESS) {
743 return (DDI_FAILURE);
744 }
745
746 /*
747 * bind event channel
748 */
749 e = xvdi_bind_evtchn(dip, evtchn);
750 if (e != DDI_SUCCESS) {
751 xvdi_unmap_ring(ring->ri_ring);
752 return (DDI_FAILURE);
753 }
754
755
756 return (DDI_SUCCESS);
757 }
758
759
760 /*
761 * blk_unbindfrom_frontend()
762 */
763 static void
blk_unbindfrom_frontend(blk_ring_t ring)764 blk_unbindfrom_frontend(blk_ring_t ring)
765 {
766 xvdi_free_evtchn(ring->ri_dip);
767 xvdi_unmap_ring(ring->ri_ring);
768 }
769
770
771 /*
772 * blk_intr()
773 */
774 static uint_t
blk_intr(caddr_t arg)775 blk_intr(caddr_t arg)
776 {
777 blk_ring_t ring;
778
779 ring = (blk_ring_t)arg;
780 if (ring->ri_if_status != BLK_IF_CONNECTED) {
781 return (DDI_INTR_CLAIMED);
782 }
783
784 (void) (*ring->ri_intr)(ring->ri_intr_arg);
785 return (DDI_INTR_CLAIMED);
786 }
787
788
789 /*
790 * blk_ring_request_get()
791 */
792 boolean_t
blk_ring_request_get(blk_ring_t ring,blkif_request_t * req)793 blk_ring_request_get(blk_ring_t ring, blkif_request_t *req)
794 {
795 blkif_request_t *src;
796 blk_stats_t *stats;
797
798
799 mutex_enter(&ring->ri_mutex);
800
801 if (ring->ri_if_status != BLK_IF_CONNECTED) {
802 mutex_exit(&ring->ri_mutex);
803 return (B_FALSE);
804 }
805
806 src = xvdi_ring_get_request(ring->ri_ring);
807 if (src == NULL) {
808 mutex_exit(&ring->ri_mutex);
809 return (B_FALSE);
810 }
811
812 switch (ring->ri_protocol) {
813 case BLKIF_PROTOCOL_NATIVE:
814 bcopy(src, req, sizeof (*req));
815 break;
816 case BLKIF_PROTOCOL_X86_32:
817 blk_ring_request_32(req, (blkif_x86_32_request_t *)src);
818 break;
819 case BLKIF_PROTOCOL_X86_64:
820 blk_ring_request_64(req, (blkif_x86_64_request_t *)src);
821 break;
822 default:
823 cmn_err(CE_WARN, "blkif@%s: unrecognised protocol: %d",
824 ddi_get_name_addr(ring->ri_dip),
825 ring->ri_protocol);
826 }
827 mutex_exit(&ring->ri_mutex);
828
829 stats = &ring->ri_stats;
830 switch (req->operation) {
831 case BLKIF_OP_READ:
832 stats->bs_req_reads++;
833 break;
834 case BLKIF_OP_WRITE:
835 stats->bs_req_writes++;
836 break;
837 case BLKIF_OP_WRITE_BARRIER:
838 stats->bs_req_barriers++;
839 break;
840 case BLKIF_OP_FLUSH_DISKCACHE:
841 stats->bs_req_flushes++;
842 break;
843 }
844
845 return (B_TRUE);
846 }
847
848
849 /*
850 * blk_ring_request_requeue()
851 * if a request is requeued, caller will have to poll for request
852 * later.
853 */
854 void
blk_ring_request_requeue(blk_ring_t ring)855 blk_ring_request_requeue(blk_ring_t ring)
856 {
857 mutex_enter(&ring->ri_mutex);
858
859 if (ring->ri_if_status != BLK_IF_CONNECTED) {
860 mutex_exit(&ring->ri_mutex);
861 return;
862 }
863
864 ring->ri_ring->xr_sring.br.req_cons--;
865
866 mutex_exit(&ring->ri_mutex);
867 }
868
869
870 /*
871 * blk_ring_response_put()
872 */
873 void
blk_ring_response_put(blk_ring_t ring,blkif_response_t * src)874 blk_ring_response_put(blk_ring_t ring, blkif_response_t *src)
875 {
876 blkif_response_t *rsp;
877 int e;
878
879
880 mutex_enter(&ring->ri_mutex);
881
882 if (ring->ri_if_status != BLK_IF_CONNECTED) {
883 mutex_exit(&ring->ri_mutex);
884 return;
885 }
886
887 rsp = xvdi_ring_get_response(ring->ri_ring);
888 ASSERT(rsp);
889
890 switch (ring->ri_protocol) {
891 case BLKIF_PROTOCOL_NATIVE:
892 bcopy(src, rsp, sizeof (*rsp));
893 break;
894 case BLKIF_PROTOCOL_X86_32:
895 blk_ring_response_32((blkif_x86_32_response_t *)rsp, src);
896 break;
897 case BLKIF_PROTOCOL_X86_64:
898 blk_ring_response_64((blkif_x86_64_response_t *)rsp, src);
899 break;
900 default:
901 cmn_err(CE_WARN, "blk@%s: unrecognised protocol: %d",
902 ddi_get_name_addr(ring->ri_dip),
903 ring->ri_protocol);
904 }
905
906 e = xvdi_ring_push_response(ring->ri_ring);
907 if (e != 0) {
908 xvdi_notify_oe(ring->ri_dip);
909 }
910
911 mutex_exit(&ring->ri_mutex);
912 }
913
914
915 /*
916 * blk_ring_request_32()
917 */
918 static void
blk_ring_request_32(blkif_request_t * dst,blkif_x86_32_request_t * src)919 blk_ring_request_32(blkif_request_t *dst, blkif_x86_32_request_t *src)
920 {
921 int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
922 dst->operation = src->operation;
923 dst->nr_segments = src->nr_segments;
924 dst->handle = src->handle;
925 dst->id = src->id;
926 dst->sector_number = src->sector_number;
927 if (n > src->nr_segments)
928 n = src->nr_segments;
929 for (i = 0; i < n; i++)
930 dst->seg[i] = src->seg[i];
931 }
932
933
934 /*
935 * blk_ring_request_64()
936 */
937 static void
blk_ring_request_64(blkif_request_t * dst,blkif_x86_64_request_t * src)938 blk_ring_request_64(blkif_request_t *dst, blkif_x86_64_request_t *src)
939 {
940 int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
941 dst->operation = src->operation;
942 dst->nr_segments = src->nr_segments;
943 dst->handle = src->handle;
944 dst->id = src->id;
945 dst->sector_number = src->sector_number;
946 if (n > src->nr_segments)
947 n = src->nr_segments;
948 for (i = 0; i < n; i++)
949 dst->seg[i] = src->seg[i];
950 }
951
952
953 /*
954 * blk_ring_response_32()
955 */
956 static void
blk_ring_response_32(blkif_x86_32_response_t * dst,blkif_response_t * src)957 blk_ring_response_32(blkif_x86_32_response_t *dst, blkif_response_t *src)
958 {
959 dst->id = src->id;
960 dst->operation = src->operation;
961 dst->status = src->status;
962 }
963
964
965 /*
966 * blk_ring_response_64()
967 */
968 static void
blk_ring_response_64(blkif_x86_64_response_t * dst,blkif_response_t * src)969 blk_ring_response_64(blkif_x86_64_response_t *dst, blkif_response_t *src)
970 {
971 dst->id = src->id;
972 dst->operation = src->operation;
973 dst->status = src->status;
974 }
975
976
977 /*
978 * blk_ring_request_dump()
979 */
980 void
blk_ring_request_dump(blkif_request_t * req)981 blk_ring_request_dump(blkif_request_t *req)
982 {
983 int i;
984
985 /*
986 * Exploit the public interface definitions for BLKIF_OP_READ
987 * etc..
988 */
989 char *op_name[] = { "read", "write", "barrier", "flush" };
990
991 cmn_err(CE_NOTE, " op=%s", op_name[req->operation]);
992 cmn_err(CE_NOTE, " num of segments=%d", req->nr_segments);
993 cmn_err(CE_NOTE, " handle=%d", req->handle);
994 cmn_err(CE_NOTE, " id=0x%llx", (unsigned long long)req->id);
995 cmn_err(CE_NOTE, " start sector=%llu",
996 (unsigned long long)req->sector_number);
997 for (i = 0; i < req->nr_segments; i++) {
998 cmn_err(CE_NOTE, " gref=%d, first sec=%d,"
999 "last sec=%d", req->seg[i].gref, req->seg[i].first_sect,
1000 req->seg[i].last_sect);
1001 }
1002 }
1003
1004
1005 /*
1006 * blk_ring_response_dump()
1007 */
1008 void
blk_ring_response_dump(blkif_response_t * resp)1009 blk_ring_response_dump(blkif_response_t *resp)
1010 {
1011 /*
1012 * Exploit the public interface definitions for BLKIF_OP_READ
1013 * etc..
1014 */
1015 char *op_name[] = { "read", "write", "barrier", "flush" };
1016
1017 cmn_err(CE_NOTE, " op=%d:%s", resp->operation,
1018 op_name[resp->operation]);
1019 cmn_err(CE_NOTE, " op=%d", resp->operation);
1020 cmn_err(CE_NOTE, " status=%d", resp->status);
1021 }
1022