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 2008 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 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 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 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 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 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 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 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 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 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 /* If feature-barrier isn't present in xenstore, add it */ 562 e = xenbus_read(xbt, xsnode, "feature-barrier", (void **)&barrier, 563 &len); 564 if (e != 0) { 565 e = xenbus_printf(xbt, xsnode, "feature-barrier", "%d", 1); 566 if (e != 0) { 567 cmn_err(CE_WARN, "xdb@%s: failed to write " 568 "'feature-barrier'", ddi_get_name_addr(dip)); 569 xvdi_fatal_error(dip, e, "writing 'feature-barrier'"); 570 (void) xenbus_transaction_end(xbt, 1); 571 goto startconnectfail_xenbus_printf; 572 } 573 } else { 574 kmem_free(barrier, len); 575 } 576 577 e = xvdi_switch_state(dip, xbt, XenbusStateConnected); 578 if (e > 0) { 579 xvdi_fatal_error(dip, e, "writing 'state'"); 580 (void) xenbus_transaction_end(xbt, 1); 581 goto startconnectfail_switch_connected; 582 } 583 584 e = xenbus_transaction_end(xbt, 0); 585 if (e != 0) { 586 if (e == EAGAIN) { 587 /* transaction is ended, don't need to abort it */ 588 goto trans_retry; 589 } 590 xvdi_fatal_error(dip, e, "completing transaction"); 591 goto startconnectfail_transaction_end; 592 } 593 594 mutex_enter(&ring->ri_state.rs_mutex); 595 ring->ri_state.rs_ring_up = B_TRUE; 596 if (ring->ri_state.rs_sleeping_on_ring) { 597 ring->ri_state.rs_sleeping_on_ring = B_FALSE; 598 cv_signal(&ring->ri_state.rs_cv); 599 } 600 mutex_exit(&ring->ri_state.rs_mutex); 601 602 if (ring->ri_ringup != NULL) { 603 (*(ring->ri_ringup))(ring->ri_ringup_arg); 604 } 605 606 return (DDI_SUCCESS); 607 608 609 startconnectfail_transaction_end: 610 startconnectfail_switch_connected: 611 startconnectfail_xenbus_printf: 612 startconnectfail_transaction_start: 613 ddi_remove_intr(dip, 0, NULL); 614 startconnectfail_add_intr: 615 blk_unbindfrom_frontend(ring); 616 ring->ri_fe = (domid_t)-1; 617 startconnectfail_bindto_frontend: 618 (void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosed); 619 startconnectfail_switch_init: 620 startconnectfail_get_oeid: 621 startconnectfail_get_xsname: 622 return (DDI_FAILURE); 623 } 624 625 626 /* 627 * blk_start_disconnect() 628 * Kick-off disconnect process. ri_if_status will not be changed 629 */ 630 static void 631 blk_start_disconnect(blk_ring_t ring) 632 { 633 /* Kick-off disconnect process */ 634 (void) xvdi_switch_state(ring->ri_dip, XBT_NULL, XenbusStateClosing); 635 } 636 637 638 /* 639 * blk_ring_close() 640 * Disconnect from frontend and close backend device 641 * ifstatus will be changed to BLK_DISCONNECTED 642 * Xenbus state will be changed to XenbusStateClosed 643 */ 644 static void 645 blk_ring_close(blk_ring_t ring) 646 { 647 dev_info_t *dip; 648 649 650 /* mutex protect ri_if_status only here */ 651 ASSERT(MUTEX_HELD(&ring->ri_mutex)); 652 653 dip = ring->ri_dip; 654 655 if (ring->ri_if_status != BLK_IF_CONNECTED) { 656 return; 657 } 658 659 ring->ri_if_status = BLK_IF_DISCONNECTED; 660 mutex_exit(&ring->ri_mutex); 661 662 /* stop accepting I/O request from frontend */ 663 ddi_remove_intr(dip, 0, NULL); 664 665 blk_unbindfrom_frontend(ring); 666 ring->ri_fe = (domid_t)-1; 667 (void) xvdi_switch_state(dip, XBT_NULL, XenbusStateClosed); 668 mutex_enter(&ring->ri_mutex); 669 } 670 671 672 /* 673 * blk_bindto_frontend() 674 */ 675 static int 676 blk_bindto_frontend(blk_ring_t ring) 677 { 678 evtchn_port_t evtchn; 679 char protocol[64]; 680 grant_ref_t gref; 681 dev_info_t *dip; 682 char *oename; 683 int e; 684 685 686 dip = ring->ri_dip; 687 protocol[0] = 0x0; 688 689 /* 690 * Gather info from frontend 691 */ 692 oename = xvdi_get_oename(dip); 693 if (oename == NULL) { 694 return (DDI_FAILURE); 695 } 696 697 e = xenbus_gather(XBT_NULL, oename, "ring-ref", "%lu", &gref, 698 "event-channel", "%u", &evtchn, NULL); 699 if (e != 0) { 700 xvdi_fatal_error(dip, e, 701 "Getting ring-ref and evtchn from frontend"); 702 return (DDI_FAILURE); 703 } 704 705 e = xenbus_gather(XBT_NULL, oename, "protocol", "%63s", 706 protocol, NULL); 707 if (e != 0) { 708 (void) strcpy(protocol, "unspecified, assuming native"); 709 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE) == 0) { 710 ring->ri_protocol = BLKIF_PROTOCOL_NATIVE; 711 ring->ri_nentry = BLKIF_RING_SIZE; 712 ring->ri_entrysize = sizeof (union blkif_sring_entry); 713 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) { 714 ring->ri_protocol = BLKIF_PROTOCOL_X86_32; 715 ring->ri_nentry = BLKIF_X86_32_RING_SIZE; 716 ring->ri_entrysize = sizeof (union blkif_x86_32_sring_entry); 717 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) { 718 ring->ri_protocol = BLKIF_PROTOCOL_X86_64; 719 ring->ri_nentry = BLKIF_X86_64_RING_SIZE; 720 ring->ri_entrysize = sizeof (union blkif_x86_64_sring_entry); 721 } else { 722 xvdi_fatal_error(dip, e, "unknown fe protocol"); 723 return (DDI_FAILURE); 724 } 725 726 /* 727 * map and init ring 728 */ 729 e = xvdi_map_ring(dip, ring->ri_nentry, ring->ri_entrysize, gref, 730 &ring->ri_ring); 731 if (e != DDI_SUCCESS) { 732 return (DDI_FAILURE); 733 } 734 735 /* 736 * bind event channel 737 */ 738 e = xvdi_bind_evtchn(dip, evtchn); 739 if (e != DDI_SUCCESS) { 740 xvdi_unmap_ring(ring->ri_ring); 741 return (DDI_FAILURE); 742 } 743 744 745 return (DDI_SUCCESS); 746 } 747 748 749 /* 750 * blk_unbindfrom_frontend() 751 */ 752 static void 753 blk_unbindfrom_frontend(blk_ring_t ring) 754 { 755 xvdi_free_evtchn(ring->ri_dip); 756 xvdi_unmap_ring(ring->ri_ring); 757 } 758 759 760 /* 761 * blk_intr() 762 */ 763 static uint_t 764 blk_intr(caddr_t arg) 765 { 766 blk_ring_t ring; 767 768 ring = (blk_ring_t)arg; 769 if (ring->ri_if_status != BLK_IF_CONNECTED) { 770 return (DDI_INTR_CLAIMED); 771 } 772 773 (void) (*ring->ri_intr)(ring->ri_intr_arg); 774 return (DDI_INTR_CLAIMED); 775 } 776 777 778 /* 779 * blk_ring_request_get() 780 */ 781 boolean_t 782 blk_ring_request_get(blk_ring_t ring, blkif_request_t *req) 783 { 784 blkif_request_t *src; 785 blk_stats_t *stats; 786 787 788 mutex_enter(&ring->ri_mutex); 789 src = xvdi_ring_get_request(ring->ri_ring); 790 if (src == NULL) { 791 mutex_exit(&ring->ri_mutex); 792 return (B_FALSE); 793 } 794 795 switch (ring->ri_protocol) { 796 case BLKIF_PROTOCOL_NATIVE: 797 bcopy(src, req, sizeof (*req)); 798 break; 799 case BLKIF_PROTOCOL_X86_32: 800 blk_ring_request_32(req, (blkif_x86_32_request_t *)src); 801 break; 802 case BLKIF_PROTOCOL_X86_64: 803 blk_ring_request_64(req, (blkif_x86_64_request_t *)src); 804 break; 805 default: 806 cmn_err(CE_WARN, "blkif@%s: unrecognised protocol: %d", 807 ddi_get_name_addr(ring->ri_dip), 808 ring->ri_protocol); 809 } 810 mutex_exit(&ring->ri_mutex); 811 812 stats = &ring->ri_stats; 813 switch (req->operation) { 814 case BLKIF_OP_READ: 815 stats->bs_req_reads++; 816 break; 817 case BLKIF_OP_WRITE: 818 stats->bs_req_writes++; 819 break; 820 case BLKIF_OP_WRITE_BARRIER: 821 stats->bs_req_barriers++; 822 break; 823 case BLKIF_OP_FLUSH_DISKCACHE: 824 stats->bs_req_flushes++; 825 break; 826 } 827 828 return (B_TRUE); 829 } 830 831 832 /* 833 * blk_ring_request_requeue() 834 * if a request is requeued, caller will have to poll for request 835 * later. 836 */ 837 void 838 blk_ring_request_requeue(blk_ring_t ring) 839 { 840 ring->ri_ring->xr_sring.br.req_cons--; 841 } 842 843 844 /* 845 * blk_ring_response_put() 846 */ 847 void 848 blk_ring_response_put(blk_ring_t ring, blkif_response_t *src) 849 { 850 blkif_response_t *rsp = xvdi_ring_get_response(ring->ri_ring); 851 int e; 852 853 ASSERT(rsp); 854 855 switch (ring->ri_protocol) { 856 case BLKIF_PROTOCOL_NATIVE: 857 bcopy(src, rsp, sizeof (*rsp)); 858 break; 859 case BLKIF_PROTOCOL_X86_32: 860 blk_ring_response_32((blkif_x86_32_response_t *)rsp, src); 861 break; 862 case BLKIF_PROTOCOL_X86_64: 863 blk_ring_response_64((blkif_x86_64_response_t *)rsp, src); 864 break; 865 default: 866 cmn_err(CE_WARN, "blk@%s: unrecognised protocol: %d", 867 ddi_get_name_addr(ring->ri_dip), 868 ring->ri_protocol); 869 } 870 871 e = xvdi_ring_push_response(ring->ri_ring); 872 if (e != 0) { 873 xvdi_notify_oe(ring->ri_dip); 874 } 875 } 876 877 878 /* 879 * blk_ring_request_32() 880 */ 881 static void 882 blk_ring_request_32(blkif_request_t *dst, blkif_x86_32_request_t *src) 883 { 884 int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; 885 dst->operation = src->operation; 886 dst->nr_segments = src->nr_segments; 887 dst->handle = src->handle; 888 dst->id = src->id; 889 dst->sector_number = src->sector_number; 890 if (n > src->nr_segments) 891 n = src->nr_segments; 892 for (i = 0; i < n; i++) 893 dst->seg[i] = src->seg[i]; 894 } 895 896 897 /* 898 * blk_ring_request_64() 899 */ 900 static void 901 blk_ring_request_64(blkif_request_t *dst, blkif_x86_64_request_t *src) 902 { 903 int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; 904 dst->operation = src->operation; 905 dst->nr_segments = src->nr_segments; 906 dst->handle = src->handle; 907 dst->id = src->id; 908 dst->sector_number = src->sector_number; 909 if (n > src->nr_segments) 910 n = src->nr_segments; 911 for (i = 0; i < n; i++) 912 dst->seg[i] = src->seg[i]; 913 } 914 915 916 /* 917 * blk_ring_response_32() 918 */ 919 static void 920 blk_ring_response_32(blkif_x86_32_response_t *dst, blkif_response_t *src) 921 { 922 dst->id = src->id; 923 dst->operation = src->operation; 924 dst->status = src->status; 925 } 926 927 928 /* 929 * blk_ring_response_64() 930 */ 931 static void 932 blk_ring_response_64(blkif_x86_64_response_t *dst, blkif_response_t *src) 933 { 934 dst->id = src->id; 935 dst->operation = src->operation; 936 dst->status = src->status; 937 } 938 939 940 /* 941 * blk_ring_request_dump() 942 */ 943 void 944 blk_ring_request_dump(blkif_request_t *req) 945 { 946 int i; 947 948 /* 949 * Exploit the public interface definitions for BLKIF_OP_READ 950 * etc.. 951 */ 952 char *op_name[] = { "read", "write", "barrier", "flush" }; 953 954 cmn_err(CE_NOTE, " op=%s", op_name[req->operation]); 955 cmn_err(CE_NOTE, " num of segments=%d", req->nr_segments); 956 cmn_err(CE_NOTE, " handle=%d", req->handle); 957 cmn_err(CE_NOTE, " id=0x%llx", (unsigned long long)req->id); 958 cmn_err(CE_NOTE, " start sector=%llu", 959 (unsigned long long)req->sector_number); 960 for (i = 0; i < req->nr_segments; i++) { 961 cmn_err(CE_NOTE, " gref=%d, first sec=%d," 962 "last sec=%d", req->seg[i].gref, req->seg[i].first_sect, 963 req->seg[i].last_sect); 964 } 965 } 966 967 968 /* 969 * blk_ring_response_dump() 970 */ 971 void 972 blk_ring_response_dump(blkif_response_t *resp) 973 { 974 /* 975 * Exploit the public interface definitions for BLKIF_OP_READ 976 * etc.. 977 */ 978 char *op_name[] = { "read", "write", "barrier", "flush" }; 979 980 cmn_err(CE_NOTE, " op=%d:%s", resp->operation, 981 op_name[resp->operation]); 982 cmn_err(CE_NOTE, " op=%d", resp->operation); 983 cmn_err(CE_NOTE, " status=%d", resp->status); 984 } 985