1 /* $OpenBSD: vdsp.c,v 1.10 2011/01/07 00:46:48 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2009, 2011 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/proc.h> 20 #include <sys/buf.h> 21 #include <sys/device.h> 22 #include <sys/disklabel.h> 23 #include <sys/fcntl.h> 24 #include <sys/malloc.h> 25 #include <sys/namei.h> 26 #include <sys/systm.h> 27 #include <sys/vnode.h> 28 #include <sys/workq.h> 29 30 #include <machine/autoconf.h> 31 #include <machine/hypervisor.h> 32 #include <machine/mdesc.h> 33 34 #include <uvm/uvm.h> 35 36 #include <scsi/scsi_all.h> 37 #include <scsi/scsi_disk.h> 38 #include <scsi/scsiconf.h> 39 40 #include <isofs/cd9660/iso.h> 41 42 #include <dev/sun/disklabel.h> 43 44 #include <sparc64/dev/cbusvar.h> 45 #include <sparc64/dev/ldcvar.h> 46 #include <sparc64/dev/viovar.h> 47 48 #ifdef VDSP_DEBUG 49 #define DPRINTF(x) printf x 50 #else 51 #define DPRINTF(x) 52 #endif 53 54 #define VDSK_TX_ENTRIES 64 55 #define VDSK_RX_ENTRIES 64 56 57 #define VDSK_MAX_DESCRIPTORS 1024 58 #define VDSK_MAX_DESCRIPTOR_SIZE 512 59 60 struct vd_attr_info { 61 struct vio_msg_tag tag; 62 uint8_t xfer_mode; 63 uint8_t vd_type; 64 uint8_t vd_mtype; 65 uint8_t _reserved1; 66 uint32_t vdisk_block_size; 67 uint64_t operations; 68 uint64_t vdisk_size; 69 uint64_t max_xfer_sz; 70 uint64_t _reserved2[2]; 71 }; 72 73 #define VD_DISK_TYPE_SLICE 0x01 74 #define VD_DISK_TYPE_DISK 0x02 75 76 #define VD_MEDIA_TYPE_FIXED 0x01 77 #define VD_MEDIA_TYPE_CD 0x02 78 #define VD_MEDIA_TYPE_DVD 0x03 79 80 /* vDisk version 1.0. */ 81 #define VD_OP_BREAD 0x01 82 #define VD_OP_BWRITE 0x02 83 #define VD_OP_FLUSH 0x03 84 #define VD_OP_GET_WCE 0x04 85 #define VD_OP_SET_WCE 0x05 86 #define VD_OP_GET_VTOC 0x06 87 #define VD_OP_SET_VTOC 0x07 88 #define VD_OP_GET_DISKGEOM 0x08 89 #define VD_OP_SET_DISKGEOM 0x09 90 #define VD_OP_GET_DEVID 0x0b 91 #define VD_OP_GET_EFI 0x0c 92 #define VD_OP_SET_EFI 0x0d 93 94 /* vDisk version 1.1 */ 95 #define VD_OP_SCSICMD 0x0a 96 #define VD_OP_RESET 0x0e 97 #define VD_OP_GET_ACCESS 0x0f 98 #define VD_OP_SET_ACCESS 0x10 99 #define VD_OP_GET_CAPACITY 0x11 100 101 /* Sun standard fields. */ 102 struct sun_vtoc_preamble { 103 char sl_text[128]; 104 u_int sl_version; /* label version */ 105 char sl_volume[8]; /* short volume name */ 106 u_short sl_nparts; /* partition count */ 107 108 struct sun_partinfo sl_part[8]; 109 110 u_int sl_bootinfo[3]; 111 u_int sl_sanity; 112 }; 113 114 struct vd_vtoc_part { 115 uint16_t id_tag; 116 uint16_t perm; 117 uint32_t reserved; 118 uint64_t start; 119 uint64_t nblocks; 120 121 }; 122 struct vd_vtoc { 123 uint8_t volume_name[8]; 124 uint16_t sector_size; 125 uint16_t num_partitions; 126 uint32_t reserved; 127 uint8_t ascii_label[128]; 128 struct vd_vtoc_part partition[8]; 129 }; 130 131 struct vd_diskgeom { 132 uint16_t ncyl; 133 uint16_t acyl; 134 uint16_t bcyl; 135 uint16_t nhead; 136 uint16_t nsect; 137 uint16_t intrlv; 138 uint16_t apc; 139 uint16_t rpm; 140 uint16_t pcyl; 141 uint16_t write_reinstruct; 142 uint16_t read_reinstruct; 143 }; 144 145 struct vd_desc { 146 struct vio_dring_hdr hdr; 147 uint64_t req_id; 148 uint8_t operation; 149 uint8_t slice; 150 uint16_t _reserved1; 151 uint32_t status; 152 uint64_t offset; 153 uint64_t size; 154 uint32_t ncookies; 155 uint32_t _reserved2; 156 struct ldc_cookie cookie[1]; 157 }; 158 159 #define VD_SLICE_NONE 0xff 160 161 struct vdsk_desc_msg { 162 struct vio_msg_tag tag; 163 uint64_t seq_no; 164 uint64_t desc_handle; 165 uint64_t req_id; 166 uint8_t operation; 167 uint8_t slice; 168 uint16_t _reserved1; 169 uint32_t status; 170 uint64_t offset; 171 uint64_t size; 172 uint32_t ncookies; 173 uint32_t _reserved2; 174 struct ldc_cookie cookie[1]; 175 }; 176 177 /* 178 * We support vDisk 1.1. 179 */ 180 #define VDSK_MAJOR 1 181 #define VDSK_MINOR 1 182 183 /* 184 * But we only support a subset of the defined commands. 185 */ 186 #define VD_OP_MASK \ 187 ((1 << VD_OP_BREAD) | (1 << VD_OP_BWRITE) | (1 << VD_OP_FLUSH) | \ 188 (1 << VD_OP_GET_VTOC) | (1 << VD_OP_SET_VTOC) | \ 189 (1 << VD_OP_GET_DISKGEOM)) 190 191 struct vdsp_softc { 192 struct device sc_dv; 193 int sc_idx; 194 bus_space_tag_t sc_bustag; 195 bus_dma_tag_t sc_dmatag; 196 197 uint64_t sc_tx_sysino; 198 uint64_t sc_rx_sysino; 199 void *sc_tx_ih; 200 void *sc_rx_ih; 201 202 struct ldc_conn sc_lc; 203 204 uint16_t sc_vio_state; 205 #define VIO_SND_VER_INFO 0x0001 206 #define VIO_ACK_VER_INFO 0x0002 207 #define VIO_RCV_VER_INFO 0x0004 208 #define VIO_SND_ATTR_INFO 0x0008 209 #define VIO_ACK_ATTR_INFO 0x0010 210 #define VIO_RCV_ATTR_INFO 0x0020 211 #define VIO_SND_DRING_REG 0x0040 212 #define VIO_ACK_DRING_REG 0x0080 213 #define VIO_RCV_DRING_REG 0x0100 214 #define VIO_SND_RDX 0x0200 215 #define VIO_ACK_RDX 0x0400 216 #define VIO_RCV_RDX 0x0800 217 218 uint16_t sc_major; 219 uint16_t sc_minor; 220 221 uint8_t sc_xfer_mode; 222 223 uint32_t sc_local_sid; 224 uint64_t sc_seq_no; 225 226 uint64_t sc_dring_ident; 227 uint32_t sc_num_descriptors; 228 uint32_t sc_descriptor_size; 229 struct ldc_cookie sc_dring_cookie; 230 231 caddr_t sc_vd; 232 233 int sc_tx_cnt; 234 int sc_tx_prod; 235 int sc_tx_cons; 236 237 uint32_t sc_vdisk_block_size; 238 uint64_t sc_vdisk_size; 239 240 struct vnode *sc_vp; 241 242 struct sun_disklabel *sc_label; 243 uint16_t sc_ncyl; 244 uint16_t sc_acyl; 245 uint16_t sc_nhead; 246 uint16_t sc_nsect; 247 }; 248 249 int vdsp_match(struct device *, void *, void *); 250 void vdsp_attach(struct device *, struct device *, void *); 251 252 struct cfattach vdsp_ca = { 253 sizeof(struct vdsp_softc), vdsp_match, vdsp_attach 254 }; 255 256 struct cfdriver vdsp_cd = { 257 NULL, "vdsp", DV_DULL 258 }; 259 260 int vdsp_tx_intr(void *); 261 int vdsp_rx_intr(void *); 262 263 void vdsp_rx_data(struct ldc_conn *, struct ldc_pkt *); 264 void vdsp_rx_vio_ctrl(struct vdsp_softc *, struct vio_msg *); 265 void vdsp_rx_vio_ver_info(struct vdsp_softc *, struct vio_msg_tag *); 266 void vdsp_rx_vio_attr_info(struct vdsp_softc *, struct vio_msg_tag *); 267 void vdsp_rx_vio_dring_reg(struct vdsp_softc *, struct vio_msg_tag *); 268 void vdsp_rx_vio_rdx(struct vdsp_softc *sc, struct vio_msg_tag *); 269 void vdsp_rx_vio_data(struct vdsp_softc *sc, struct vio_msg *); 270 void vdsp_rx_vio_dring_data(struct vdsp_softc *sc, 271 struct vio_msg_tag *); 272 void vdsp_rx_vio_desc_data(struct vdsp_softc *sc, struct vio_msg_tag *); 273 274 void vdsp_ldc_reset(struct ldc_conn *); 275 void vdsp_ldc_start(struct ldc_conn *); 276 277 void vdsp_sendmsg(struct vdsp_softc *, void *, size_t); 278 279 void vdsp_mountroot(void *); 280 void vdsp_open(void *, void *); 281 void vdsp_alloc(void *, void *); 282 void vdsp_readlabel(struct vdsp_softc *); 283 int vdsp_writelabel(struct vdsp_softc *); 284 int vdsp_is_iso(struct vdsp_softc *); 285 void vdsp_read(void *, void *); 286 void vdsp_read_dring(void *, void *); 287 void vdsp_write_dring(void *, void *); 288 void vdsp_flush_dring(void *, void *); 289 void vdsp_get_vtoc(void *, void *); 290 void vdsp_set_vtoc(void *, void *); 291 void vdsp_get_diskgeom(void *, void *); 292 void vdsp_unimp(void *, void *); 293 294 void vdsp_ack_desc(struct vdsp_softc *, struct vd_desc *); 295 296 int 297 vdsp_match(struct device *parent, void *match, void *aux) 298 { 299 struct cbus_attach_args *ca = aux; 300 301 if (strcmp(ca->ca_name, "vds-port") == 0) 302 return (1); 303 304 return (0); 305 } 306 307 void 308 vdsp_attach(struct device *parent, struct device *self, void *aux) 309 { 310 struct vdsp_softc *sc = (struct vdsp_softc *)self; 311 struct cbus_attach_args *ca = aux; 312 struct ldc_conn *lc; 313 314 sc->sc_idx = ca->ca_idx; 315 sc->sc_bustag = ca->ca_bustag; 316 sc->sc_dmatag = ca->ca_dmatag; 317 318 if (cbus_intr_map(ca->ca_node, ca->ca_tx_ino, &sc->sc_tx_sysino) || 319 cbus_intr_map(ca->ca_node, ca->ca_rx_ino, &sc->sc_rx_sysino)) { 320 printf(": can't map interrupt\n"); 321 return; 322 } 323 printf(": ivec 0x%lx, 0x%lx", sc->sc_tx_sysino, sc->sc_tx_sysino); 324 325 /* 326 * Un-configure queues before registering interrupt handlers, 327 * such that we dont get any stale LDC packets or events. 328 */ 329 hv_ldc_tx_qconf(ca->ca_id, 0, 0); 330 hv_ldc_rx_qconf(ca->ca_id, 0, 0); 331 332 sc->sc_tx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_tx_sysino, 333 IPL_BIO, 0, vdsp_tx_intr, sc, sc->sc_dv.dv_xname); 334 sc->sc_rx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_rx_sysino, 335 IPL_BIO, 0, vdsp_rx_intr, sc, sc->sc_dv.dv_xname); 336 if (sc->sc_tx_ih == NULL || sc->sc_rx_ih == NULL) { 337 printf(", can't establish interrupt\n"); 338 return; 339 } 340 341 /* 342 * Disable interrupts while we have no queues allocated. 343 * Otherwise we may end up with an interrupt storm as soon as 344 * our peer places a packet in their transmit queue. 345 */ 346 cbus_intr_setenabled(sc->sc_tx_sysino, INTR_DISABLED); 347 cbus_intr_setenabled(sc->sc_rx_sysino, INTR_DISABLED); 348 349 lc = &sc->sc_lc; 350 lc->lc_id = ca->ca_id; 351 lc->lc_sc = sc; 352 lc->lc_reset = vdsp_ldc_reset; 353 lc->lc_start = vdsp_ldc_start; 354 lc->lc_rx_data = vdsp_rx_data; 355 356 lc->lc_txq = ldc_queue_alloc(sc->sc_dmatag, VDSK_TX_ENTRIES); 357 if (lc->lc_txq == NULL) { 358 printf(", can't allocate tx queue\n"); 359 return; 360 } 361 362 lc->lc_rxq = ldc_queue_alloc(sc->sc_dmatag, VDSK_RX_ENTRIES); 363 if (lc->lc_rxq == NULL) { 364 printf(", can't allocate rx queue\n"); 365 goto free_txqueue; 366 } 367 368 printf("\n"); 369 370 mountroothook_establish(vdsp_mountroot, sc); 371 return; 372 373 #if 0 374 free_rxqueue: 375 ldc_queue_free(sc->sc_dmatag, lc->lc_rxq); 376 #endif 377 free_txqueue: 378 ldc_queue_free(sc->sc_dmatag, lc->lc_txq); 379 } 380 381 int 382 vdsp_tx_intr(void *arg) 383 { 384 struct vdsp_softc *sc = arg; 385 struct ldc_conn *lc = &sc->sc_lc; 386 uint64_t tx_head, tx_tail, tx_state; 387 388 hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); 389 if (tx_state != lc->lc_tx_state) { 390 switch (tx_state) { 391 case LDC_CHANNEL_DOWN: 392 DPRINTF(("Tx link down\n")); 393 break; 394 case LDC_CHANNEL_UP: 395 DPRINTF(("Tx link up\n")); 396 break; 397 case LDC_CHANNEL_RESET: 398 DPRINTF(("Tx link reset\n")); 399 break; 400 } 401 lc->lc_tx_state = tx_state; 402 } 403 404 return (1); 405 } 406 407 int 408 vdsp_rx_intr(void *arg) 409 { 410 struct vdsp_softc *sc = arg; 411 struct ldc_conn *lc = &sc->sc_lc; 412 uint64_t rx_head, rx_tail, rx_state; 413 struct ldc_pkt *lp; 414 int err; 415 416 err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state); 417 if (err == H_EINVAL) 418 return (0); 419 if (err != H_EOK) { 420 printf("hv_ldc_rx_get_state %d\n", err); 421 return (0); 422 } 423 424 if (rx_state != lc->lc_rx_state) { 425 switch (rx_state) { 426 case LDC_CHANNEL_DOWN: 427 DPRINTF(("Rx link down\n")); 428 lc->lc_tx_seqid = 0; 429 lc->lc_state = 0; 430 lc->lc_reset(lc); 431 break; 432 case LDC_CHANNEL_UP: 433 DPRINTF(("Rx link up\n")); 434 break; 435 case LDC_CHANNEL_RESET: 436 DPRINTF(("Rx link reset\n")); 437 lc->lc_tx_seqid = 0; 438 lc->lc_state = 0; 439 lc->lc_reset(lc); 440 break; 441 } 442 lc->lc_rx_state = rx_state; 443 return (1); 444 } 445 446 if (lc->lc_rx_state == LDC_CHANNEL_DOWN) 447 return (1); 448 449 lp = (struct ldc_pkt *)(lc->lc_rxq->lq_va + rx_head); 450 switch (lp->type) { 451 case LDC_CTRL: 452 ldc_rx_ctrl(lc, lp); 453 break; 454 455 case LDC_DATA: 456 ldc_rx_data(lc, lp); 457 break; 458 459 default: 460 DPRINTF(("0x%02x/0x%02x/0x%02x\n", lp->type, lp->stype, 461 lp->ctrl)); 462 ldc_reset(lc); 463 break; 464 } 465 466 rx_head += sizeof(*lp); 467 rx_head &= ((lc->lc_rxq->lq_nentries * sizeof(*lp)) - 1); 468 err = hv_ldc_rx_set_qhead(lc->lc_id, rx_head); 469 if (err != H_EOK) 470 printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err); 471 472 return (1); 473 } 474 475 void 476 vdsp_rx_data(struct ldc_conn *lc, struct ldc_pkt *lp) 477 { 478 struct vio_msg *vm = (struct vio_msg *)lp; 479 480 switch (vm->type) { 481 case VIO_TYPE_CTRL: 482 if ((lp->env & LDC_FRAG_START) == 0 && 483 (lp->env & LDC_FRAG_STOP) == 0) 484 return; 485 vdsp_rx_vio_ctrl(lc->lc_sc, vm); 486 break; 487 488 case VIO_TYPE_DATA: 489 if((lp->env & LDC_FRAG_START) == 0) 490 return; 491 vdsp_rx_vio_data(lc->lc_sc, vm); 492 break; 493 494 default: 495 DPRINTF(("Unhandled packet type 0x%02x\n", vm->type)); 496 ldc_reset(lc); 497 break; 498 } 499 } 500 501 void 502 vdsp_rx_vio_ctrl(struct vdsp_softc *sc, struct vio_msg *vm) 503 { 504 struct vio_msg_tag *tag = (struct vio_msg_tag *)&vm->type; 505 506 switch (tag->stype_env) { 507 case VIO_VER_INFO: 508 vdsp_rx_vio_ver_info(sc, tag); 509 break; 510 case VIO_ATTR_INFO: 511 vdsp_rx_vio_attr_info(sc, tag); 512 break; 513 case VIO_DRING_REG: 514 vdsp_rx_vio_dring_reg(sc, tag); 515 break; 516 case VIO_RDX: 517 vdsp_rx_vio_rdx(sc, tag); 518 break; 519 default: 520 DPRINTF(("CTRL/0x%02x/0x%04x\n", tag->stype, tag->stype_env)); 521 break; 522 } 523 } 524 525 void 526 vdsp_rx_vio_ver_info(struct vdsp_softc *sc, struct vio_msg_tag *tag) 527 { 528 struct vio_ver_info *vi = (struct vio_ver_info *)tag; 529 530 switch (vi->tag.stype) { 531 case VIO_SUBTYPE_INFO: 532 DPRINTF(("CTRL/INFO/VER_INFO\n")); 533 534 /* Make sure we're talking to a virtual disk. */ 535 if (vi->dev_class != VDEV_DISK) { 536 /* Huh, we're not talking to a disk device? */ 537 printf("%s: peer is not a disk device\n", 538 sc->sc_dv.dv_xname); 539 vi->tag.stype = VIO_SUBTYPE_NACK; 540 vi->major = 0; 541 vdsp_sendmsg(sc, vi, sizeof(*vi)); 542 return; 543 } 544 545 if (vi->major != VDSK_MAJOR) { 546 vi->tag.stype = VIO_SUBTYPE_NACK; 547 vi->major = VDSK_MAJOR; 548 vi->minor = VDSK_MINOR; 549 vdsp_sendmsg(sc, vi, sizeof(*vi)); 550 return; 551 } 552 553 sc->sc_major = vi->major; 554 sc->sc_minor = vi->minor; 555 sc->sc_local_sid = vi->tag.sid; 556 557 vi->tag.stype = VIO_SUBTYPE_ACK; 558 if (vi->minor > VDSK_MINOR) 559 vi->minor = VDSK_MINOR; 560 vi->dev_class = VDEV_DISK_SERVER; 561 vdsp_sendmsg(sc, vi, sizeof(*vi)); 562 sc->sc_vio_state |= VIO_RCV_VER_INFO; 563 break; 564 565 case VIO_SUBTYPE_ACK: 566 DPRINTF(("CTRL/ACK/VER_INFO\n")); 567 break; 568 569 default: 570 DPRINTF(("CTRL/0x%02x/VER_INFO\n", vi->tag.stype)); 571 break; 572 } 573 } 574 575 void 576 vdsp_rx_vio_attr_info(struct vdsp_softc *sc, struct vio_msg_tag *tag) 577 { 578 struct vd_attr_info *ai = (struct vd_attr_info *)tag; 579 580 switch (ai->tag.stype) { 581 case VIO_SUBTYPE_INFO: 582 DPRINTF(("CTRL/INFO/ATTR_INFO\n")); 583 584 if (ai->xfer_mode != VIO_DESC_MODE && 585 ai->xfer_mode != VIO_DRING_MODE) { 586 printf("%s: peer uses unsupported xfer mode 0x%02x\n", 587 sc->sc_dv.dv_xname, ai->xfer_mode); 588 ai->tag.stype = VIO_SUBTYPE_NACK; 589 vdsp_sendmsg(sc, ai, sizeof(*ai)); 590 return; 591 } 592 sc->sc_xfer_mode = ai->xfer_mode; 593 sc->sc_vio_state |= VIO_RCV_ATTR_INFO; 594 595 workq_add_task(NULL, 0, vdsp_open, sc, NULL); 596 break; 597 598 case VIO_SUBTYPE_ACK: 599 DPRINTF(("CTRL/ACK/ATTR_INFO\n")); 600 break; 601 602 default: 603 DPRINTF(("CTRL/0x%02x/ATTR_INFO\n", ai->tag.stype)); 604 break; 605 } 606 } 607 608 void 609 vdsp_rx_vio_dring_reg(struct vdsp_softc *sc, struct vio_msg_tag *tag) 610 { 611 struct vio_dring_reg *dr = (struct vio_dring_reg *)tag; 612 613 switch (dr->tag.stype) { 614 case VIO_SUBTYPE_INFO: 615 DPRINTF(("CTRL/INFO/DRING_REG\n")); 616 617 if (dr->num_descriptors > VDSK_MAX_DESCRIPTORS || 618 dr->descriptor_size > VDSK_MAX_DESCRIPTOR_SIZE || 619 dr->ncookies > 1) { 620 dr->tag.stype = VIO_SUBTYPE_NACK; 621 vdsp_sendmsg(sc, dr, sizeof(*dr)); 622 return; 623 } 624 sc->sc_num_descriptors = dr->num_descriptors; 625 sc->sc_descriptor_size = dr->descriptor_size; 626 sc->sc_dring_cookie = dr->cookie[0]; 627 sc->sc_vio_state |= VIO_RCV_DRING_REG; 628 629 workq_add_task(NULL, 0, vdsp_alloc, sc, NULL); 630 break; 631 632 case VIO_SUBTYPE_ACK: 633 DPRINTF(("CTRL/ACK/DRING_REG\n")); 634 break; 635 636 default: 637 DPRINTF(("CTRL/0x%02x/DRING_REG\n", dr->tag.stype)); 638 break; 639 } 640 } 641 642 void 643 vdsp_rx_vio_rdx(struct vdsp_softc *sc, struct vio_msg_tag *tag) 644 { 645 switch(tag->stype) { 646 case VIO_SUBTYPE_INFO: 647 DPRINTF(("CTRL/INFO/RDX\n")); 648 649 tag->stype = VIO_SUBTYPE_ACK; 650 tag->sid = sc->sc_local_sid; 651 vdsp_sendmsg(sc, tag, sizeof(*tag)); 652 sc->sc_vio_state |= VIO_RCV_RDX; 653 break; 654 655 case VIO_SUBTYPE_ACK: 656 DPRINTF(("CTRL/ACK/RDX\n")); 657 break; 658 659 default: 660 DPRINTF(("CTRL/0x%02x/RDX (VIO)\n", tag->stype)); 661 break; 662 } 663 } 664 665 void 666 vdsp_rx_vio_data(struct vdsp_softc *sc, struct vio_msg *vm) 667 { 668 struct vio_msg_tag *tag = (struct vio_msg_tag *)&vm->type; 669 670 if (!ISSET(sc->sc_vio_state, VIO_RCV_RDX)) { 671 DPRINTF(("Spurious DATA/0x%02x/0x%04x\n", tag->stype, 672 tag->stype_env)); 673 return; 674 } 675 676 switch(tag->stype_env) { 677 case VIO_DESC_DATA: 678 vdsp_rx_vio_desc_data(sc, tag); 679 break; 680 681 case VIO_DRING_DATA: 682 vdsp_rx_vio_dring_data(sc, tag); 683 break; 684 685 default: 686 DPRINTF(("DATA/0x%02x/0x%04x\n", tag->stype, tag->stype_env)); 687 break; 688 } 689 } 690 691 void 692 vdsp_rx_vio_dring_data(struct vdsp_softc *sc, struct vio_msg_tag *tag) 693 { 694 struct vio_dring_msg *dm = (struct vio_dring_msg *)tag; 695 struct vd_desc *vd; 696 vaddr_t va; 697 paddr_t pa; 698 uint64_t size, off; 699 psize_t nbytes; 700 int err; 701 702 switch(tag->stype) { 703 case VIO_SUBTYPE_INFO: 704 DPRINTF(("DATA/INFO/DRING_DATA\n")); 705 706 if (dm->dring_ident != sc->sc_dring_ident || 707 dm->start_idx >= sc->sc_num_descriptors) { 708 dm->tag.stype = VIO_SUBTYPE_NACK; 709 vdsp_sendmsg(sc, dm, sizeof(*dm)); 710 return; 711 } 712 713 off = dm->start_idx * sc->sc_descriptor_size; 714 vd = (struct vd_desc *)(sc->sc_vd + off); 715 va = (vaddr_t)vd; 716 size = sc->sc_descriptor_size; 717 while (size > 0) { 718 pmap_extract(pmap_kernel(), va, &pa); 719 nbytes = min(size, PAGE_SIZE - (off & PAGE_MASK)); 720 err = hv_ldc_copy(sc->sc_lc.lc_id, LDC_COPY_IN, 721 sc->sc_dring_cookie.addr | off, pa, 722 nbytes, &nbytes); 723 va += nbytes; 724 size -= nbytes; 725 off += nbytes; 726 } 727 if (err != H_EOK) { 728 printf("%s: hv_ldc_copy %d\n", __func__, err); 729 return; 730 } 731 732 DPRINTF(("%s: start_idx %d, end_idx %d, operation %x\n", 733 sc->sc_dv.dv_xname, dm->start_idx, dm->end_idx, 734 vd->operation)); 735 switch (vd->operation) { 736 case VD_OP_BREAD: 737 workq_add_task(NULL, 0, vdsp_read_dring, sc, vd); 738 break; 739 case VD_OP_BWRITE: 740 workq_add_task(NULL, 0, vdsp_write_dring, sc, vd); 741 break; 742 case VD_OP_FLUSH: 743 workq_add_task(NULL, 0, vdsp_flush_dring, sc, vd); 744 break; 745 case VD_OP_GET_VTOC: 746 workq_add_task(NULL, 0, vdsp_get_vtoc, sc, vd); 747 break; 748 case VD_OP_SET_VTOC: 749 workq_add_task(NULL, 0, vdsp_set_vtoc, sc, vd); 750 break; 751 case VD_OP_GET_DISKGEOM: 752 workq_add_task(NULL, 0, vdsp_get_diskgeom, sc, vd); 753 break; 754 default: 755 printf("%s: unsupported operation 0x%02x\n", 756 sc->sc_dv.dv_xname, vd->operation); 757 workq_add_task(NULL, 0, vdsp_unimp, sc, vd); 758 break; 759 } 760 break; 761 762 case VIO_SUBTYPE_ACK: 763 DPRINTF(("DATA/ACK/DRING_DATA\n")); 764 break; 765 766 case VIO_SUBTYPE_NACK: 767 DPRINTF(("DATA/NACK/DRING_DATA\n")); 768 break; 769 770 default: 771 DPRINTF(("DATA/0x%02x/DRING_DATA\n", tag->stype)); 772 break; 773 } 774 } 775 776 void 777 vdsp_rx_vio_desc_data(struct vdsp_softc *sc, struct vio_msg_tag *tag) 778 { 779 struct vdsk_desc_msg *dm = (struct vdsk_desc_msg *)tag; 780 781 switch(tag->stype) { 782 case VIO_SUBTYPE_INFO: 783 DPRINTF(("DATA/INFO/DESC_DATA\n")); 784 785 switch (dm->operation) { 786 case VD_OP_BREAD: 787 workq_add_task(NULL, 0, vdsp_read, sc, dm); 788 break; 789 default: 790 printf("%s: unsupported operation 0x%02x\n", 791 sc->sc_dv.dv_xname, dm->operation); 792 break; 793 } 794 break; 795 796 case VIO_SUBTYPE_ACK: 797 DPRINTF(("DATA/ACK/DESC_DATA\n")); 798 break; 799 800 case VIO_SUBTYPE_NACK: 801 DPRINTF(("DATA/NACK/DESC_DATA\n")); 802 break; 803 804 default: 805 DPRINTF(("DATA/0x%02x/DESC_DATA\n", tag->stype)); 806 break; 807 } 808 } 809 810 void 811 vdsp_ldc_reset(struct ldc_conn *lc) 812 { 813 struct vdsp_softc *sc = lc->lc_sc; 814 815 sc->sc_vio_state = 0; 816 sc->sc_seq_no = 0; 817 if (sc->sc_vd) { 818 free(sc->sc_vd, M_DEVBUF); 819 sc->sc_vd = NULL; 820 } 821 if (sc->sc_label) { 822 free(sc->sc_label, M_DEVBUF); 823 sc->sc_label = NULL; 824 } 825 } 826 827 void 828 vdsp_ldc_start(struct ldc_conn *lc) 829 { 830 /* The vDisk client is supposed to initiate the handshake. */ 831 } 832 833 void 834 vdsp_sendmsg(struct vdsp_softc *sc, void *msg, size_t len) 835 { 836 struct ldc_conn *lc = &sc->sc_lc; 837 struct ldc_pkt *lp; 838 uint64_t tx_head, tx_tail, tx_state; 839 uint8_t *p = msg; 840 int err; 841 842 err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); 843 if (err != H_EOK) 844 return; 845 846 while (len > 0) { 847 lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail); 848 bzero(lp, sizeof(struct ldc_pkt)); 849 lp->type = LDC_DATA; 850 lp->stype = LDC_INFO; 851 lp->env = min(len, LDC_PKT_PAYLOAD); 852 if (p == msg) 853 lp->env |= LDC_FRAG_START; 854 if (len <= LDC_PKT_PAYLOAD) 855 lp->env |= LDC_FRAG_STOP; 856 lp->seqid = lc->lc_tx_seqid++; 857 bcopy(p, &lp->major, min(len, LDC_PKT_PAYLOAD)); 858 859 tx_tail += sizeof(*lp); 860 tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1); 861 err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail); 862 if (err != H_EOK) 863 printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err); 864 p += min(len, LDC_PKT_PAYLOAD); 865 len -= min(len, LDC_PKT_PAYLOAD); 866 } 867 } 868 869 void 870 vdsp_mountroot(void *arg) 871 { 872 struct vdsp_softc *sc = arg; 873 struct ldc_conn *lc = &sc->sc_lc; 874 int err; 875 876 err = hv_ldc_tx_qconf(lc->lc_id, 877 lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries); 878 if (err != H_EOK) 879 printf("%s: hv_ldc_tx_qconf %d\n", __func__, err); 880 881 err = hv_ldc_rx_qconf(lc->lc_id, 882 lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries); 883 if (err != H_EOK) 884 printf("%s: hv_ldc_rx_qconf %d\n", err, __func__); 885 886 cbus_intr_setenabled(sc->sc_tx_sysino, INTR_ENABLED); 887 cbus_intr_setenabled(sc->sc_rx_sysino, INTR_ENABLED); 888 } 889 890 void 891 vdsp_open(void *arg1, void *arg2) 892 { 893 struct vdsp_softc *sc = arg1; 894 struct proc *p = curproc; 895 struct vd_attr_info ai; 896 897 if (sc->sc_vp == NULL) { 898 struct nameidata nd; 899 struct vattr va; 900 const char *name; 901 int error; 902 903 name = mdesc_get_prop_str(sc->sc_idx, "vds-block-device"); 904 if (name == NULL) 905 return; 906 907 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p); 908 error = vn_open(&nd, FREAD, 0); 909 if (error) { 910 printf("VOP_OPEN: %s, %d\n", name, error); 911 return; 912 } 913 914 error = VOP_GETATTR(nd.ni_vp, &va, p->p_ucred, p); 915 if (error) 916 printf("VOP_GETATTR: %s, %d\n", name, error); 917 sc->sc_vdisk_block_size = DEV_BSIZE; 918 sc->sc_vdisk_size = va.va_size / DEV_BSIZE; 919 920 VOP_UNLOCK(nd.ni_vp, 0, p); 921 sc->sc_vp = nd.ni_vp; 922 923 vdsp_readlabel(sc); 924 } 925 926 bzero(&ai, sizeof(ai)); 927 ai.tag.type = VIO_TYPE_CTRL; 928 ai.tag.stype = VIO_SUBTYPE_ACK; 929 ai.tag.stype_env = VIO_ATTR_INFO; 930 ai.tag.sid = sc->sc_local_sid; 931 ai.xfer_mode = sc->sc_xfer_mode; 932 ai.vd_type = VD_DISK_TYPE_DISK; 933 if (sc->sc_major > 1 || sc->sc_minor >= 1) { 934 if (vdsp_is_iso(sc)) 935 ai.vd_mtype = VD_MEDIA_TYPE_CD; 936 else 937 ai.vd_mtype = VD_MEDIA_TYPE_FIXED; 938 } 939 ai.vdisk_block_size = sc->sc_vdisk_block_size; 940 ai.operations = VD_OP_MASK; 941 ai.vdisk_size = sc->sc_vdisk_size; 942 ai.max_xfer_sz = MAXPHYS / sc->sc_vdisk_block_size; 943 vdsp_sendmsg(sc, &ai, sizeof(ai)); 944 } 945 946 void 947 vdsp_readlabel(struct vdsp_softc *sc) 948 { 949 struct proc *p = curproc; 950 struct iovec iov; 951 struct uio uio; 952 int err; 953 954 if (sc->sc_vp == NULL) 955 return; 956 957 sc->sc_label = malloc(sizeof(*sc->sc_label), M_DEVBUF, M_WAITOK); 958 959 iov.iov_base = sc->sc_label; 960 iov.iov_len = sizeof(*sc->sc_label); 961 uio.uio_iov = &iov; 962 uio.uio_iovcnt = 1; 963 uio.uio_offset = 0; 964 uio.uio_resid = sizeof(*sc->sc_label); 965 uio.uio_segflg = UIO_SYSSPACE; 966 uio.uio_rw = UIO_READ; 967 uio.uio_procp = p; 968 969 vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p); 970 err = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred); 971 VOP_UNLOCK(sc->sc_vp, 0, p); 972 if (err) { 973 free(sc->sc_label, M_DEVBUF); 974 sc->sc_label = NULL; 975 } 976 } 977 978 int 979 vdsp_writelabel(struct vdsp_softc *sc) 980 { 981 struct proc *p = curproc; 982 struct iovec iov; 983 struct uio uio; 984 int err; 985 986 if (sc->sc_vp == NULL || sc->sc_label == NULL) 987 return (EINVAL); 988 989 iov.iov_base = sc->sc_label; 990 iov.iov_len = sizeof(*sc->sc_label); 991 uio.uio_iov = &iov; 992 uio.uio_iovcnt = 1; 993 uio.uio_offset = 0; 994 uio.uio_resid = sizeof(*sc->sc_label); 995 uio.uio_segflg = UIO_SYSSPACE; 996 uio.uio_rw = UIO_WRITE; 997 uio.uio_procp = p; 998 999 vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p); 1000 err = VOP_WRITE(sc->sc_vp, &uio, 0, p->p_ucred); 1001 VOP_UNLOCK(sc->sc_vp, 0, p); 1002 1003 return (err); 1004 } 1005 1006 int 1007 vdsp_is_iso(struct vdsp_softc *sc) 1008 { 1009 struct proc *p = curproc; 1010 struct iovec iov; 1011 struct uio uio; 1012 struct iso_volume_descriptor *vdp; 1013 int err; 1014 1015 if (sc->sc_vp == NULL) 1016 return (0); 1017 1018 vdp = malloc(sizeof(*vdp), M_DEVBUF, M_WAITOK); 1019 1020 iov.iov_base = vdp; 1021 iov.iov_len = sizeof(*vdp); 1022 uio.uio_iov = &iov; 1023 uio.uio_iovcnt = 1; 1024 uio.uio_offset = 16 * ISO_DEFAULT_BLOCK_SIZE; 1025 uio.uio_resid = sizeof(*vdp); 1026 uio.uio_segflg = UIO_SYSSPACE; 1027 uio.uio_rw = UIO_READ; 1028 uio.uio_procp = p; 1029 1030 vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p); 1031 err = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred); 1032 VOP_UNLOCK(sc->sc_vp, 0, p); 1033 1034 if (err == 0 && memcmp(vdp->id, ISO_STANDARD_ID, sizeof(vdp->id))) 1035 err = ENOENT; 1036 1037 free(vdp, M_DEVBUF); 1038 return (err == 0); 1039 } 1040 1041 void 1042 vdsp_alloc(void *arg1, void *arg2) 1043 { 1044 struct vdsp_softc *sc = arg1; 1045 struct vio_dring_reg dr; 1046 1047 KASSERT(sc->sc_num_descriptors <= VDSK_MAX_DESCRIPTORS); 1048 KASSERT(sc->sc_descriptor_size <= VDSK_MAX_DESCRIPTOR_SIZE); 1049 sc->sc_vd = malloc(sc->sc_num_descriptors * sc->sc_descriptor_size, 1050 M_DEVBUF, M_WAITOK); 1051 1052 bzero(&dr, sizeof(dr)); 1053 dr.tag.type = VIO_TYPE_CTRL; 1054 dr.tag.stype = VIO_SUBTYPE_ACK; 1055 dr.tag.stype_env = VIO_DRING_REG; 1056 dr.tag.sid = sc->sc_local_sid; 1057 dr.dring_ident = ++sc->sc_dring_ident; 1058 vdsp_sendmsg(sc, &dr, sizeof(dr)); 1059 } 1060 1061 void 1062 vdsp_read(void *arg1, void *arg2) 1063 { 1064 struct vdsp_softc *sc = arg1; 1065 struct ldc_conn *lc = &sc->sc_lc; 1066 struct vdsk_desc_msg *dm = arg2; 1067 struct proc *p = curproc; 1068 struct iovec iov; 1069 struct uio uio; 1070 caddr_t buf; 1071 vaddr_t va; 1072 paddr_t pa; 1073 uint64_t size, off; 1074 psize_t nbytes; 1075 int err, i; 1076 1077 if (sc->sc_vp == NULL) 1078 return; 1079 1080 buf = malloc(dm->size, M_DEVBUF, M_WAITOK); 1081 1082 iov.iov_base = buf; 1083 iov.iov_len = dm->size; 1084 uio.uio_iov = &iov; 1085 uio.uio_iovcnt = 1; 1086 uio.uio_offset = dm->offset * DEV_BSIZE; 1087 uio.uio_resid = dm->size; 1088 uio.uio_segflg = UIO_SYSSPACE; 1089 uio.uio_rw = UIO_READ; 1090 uio.uio_procp = p; 1091 1092 vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p); 1093 dm->status = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred); 1094 VOP_UNLOCK(sc->sc_vp, 0, p); 1095 1096 if (dm->status == 0) { 1097 i = 0; 1098 va = (vaddr_t)buf; 1099 size = dm->size; 1100 off = 0; 1101 while (size > 0 && i < dm->ncookies) { 1102 pmap_extract(pmap_kernel(), va, &pa); 1103 nbytes = min(size, dm->cookie[i].size - off); 1104 nbytes = min(nbytes, PAGE_SIZE - (off & PAGE_MASK)); 1105 err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT, 1106 dm->cookie[i].addr + off, pa, nbytes, &nbytes); 1107 if (err != H_EOK) 1108 printf("%s: hv_ldc_copy: %d\n", __func__, err); 1109 va += nbytes; 1110 size -= nbytes; 1111 off += nbytes; 1112 if (off >= dm->cookie[i].size) { 1113 off = 0; 1114 i++; 1115 } 1116 } 1117 } 1118 1119 free(buf, M_DEVBUF); 1120 1121 /* ACK the descriptor. */ 1122 dm->tag.stype = VIO_SUBTYPE_ACK; 1123 dm->tag.sid = sc->sc_local_sid; 1124 vdsp_sendmsg(sc, dm, sizeof(*dm) + 1125 (dm->ncookies - 1) * sizeof(struct ldc_cookie)); 1126 } 1127 1128 void 1129 vdsp_read_dring(void *arg1, void *arg2) 1130 { 1131 struct vdsp_softc *sc = arg1; 1132 struct ldc_conn *lc = &sc->sc_lc; 1133 struct vd_desc *vd = arg2; 1134 struct proc *p = curproc; 1135 struct iovec iov; 1136 struct uio uio; 1137 caddr_t buf; 1138 vaddr_t va; 1139 paddr_t pa; 1140 uint64_t size, off; 1141 psize_t nbytes; 1142 int err, i; 1143 1144 if (sc->sc_vp == NULL) 1145 return; 1146 1147 buf = malloc(vd->size, M_DEVBUF, M_WAITOK); 1148 1149 iov.iov_base = buf; 1150 iov.iov_len = vd->size; 1151 uio.uio_iov = &iov; 1152 uio.uio_iovcnt = 1; 1153 uio.uio_offset = vd->offset * DEV_BSIZE; 1154 uio.uio_resid = vd->size; 1155 uio.uio_segflg = UIO_SYSSPACE; 1156 uio.uio_rw = UIO_READ; 1157 uio.uio_procp = p; 1158 1159 vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p); 1160 vd->status = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred); 1161 VOP_UNLOCK(sc->sc_vp, 0, p); 1162 1163 if (vd->status == 0) { 1164 i = 0; 1165 va = (vaddr_t)buf; 1166 size = vd->size; 1167 off = 0; 1168 while (size > 0 && i < vd->ncookies) { 1169 pmap_extract(pmap_kernel(), va, &pa); 1170 nbytes = min(size, vd->cookie[i].size - off); 1171 nbytes = min(nbytes, PAGE_SIZE - (off & PAGE_MASK)); 1172 err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT, 1173 vd->cookie[i].addr + off, pa, nbytes, &nbytes); 1174 if (err != H_EOK) 1175 printf("%s: hv_ldc_copy: %d\n", __func__, err); 1176 va += nbytes; 1177 size -= nbytes; 1178 off += nbytes; 1179 if (off >= vd->cookie[i].size) { 1180 off = 0; 1181 i++; 1182 } 1183 } 1184 } 1185 1186 free(buf, M_DEVBUF); 1187 1188 /* ACK the descriptor. */ 1189 vd->hdr.dstate = VIO_DESC_DONE; 1190 vdsp_ack_desc(sc, vd); 1191 } 1192 1193 void 1194 vdsp_write_dring(void *arg1, void *arg2) 1195 { 1196 struct vdsp_softc *sc = arg1; 1197 struct ldc_conn *lc = &sc->sc_lc; 1198 struct vd_desc *vd = arg2; 1199 struct proc *p = curproc; 1200 struct iovec iov; 1201 struct uio uio; 1202 caddr_t buf; 1203 vaddr_t va; 1204 paddr_t pa; 1205 uint64_t size, off; 1206 psize_t nbytes; 1207 int err, i; 1208 1209 if (sc->sc_vp == NULL) 1210 return; 1211 1212 buf = malloc(vd->size, M_DEVBUF, M_WAITOK); 1213 1214 i = 0; 1215 va = (vaddr_t)buf; 1216 size = vd->size; 1217 off = 0; 1218 while (size > 0 && i < vd->ncookies) { 1219 pmap_extract(pmap_kernel(), va, &pa); 1220 nbytes = min(size, vd->cookie[i].size - off); 1221 nbytes = min(nbytes, PAGE_SIZE - (off & PAGE_MASK)); 1222 err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN, 1223 vd->cookie[i].addr + off, pa, nbytes, &nbytes); 1224 if (err != H_EOK) 1225 printf("%s: hv_ldc_copy: %d\n", __func__, err); 1226 va += nbytes; 1227 size -= nbytes; 1228 off += nbytes; 1229 if (off >= vd->cookie[i].size) { 1230 off = 0; 1231 i++; 1232 } 1233 } 1234 1235 iov.iov_base = buf; 1236 iov.iov_len = vd->size; 1237 uio.uio_iov = &iov; 1238 uio.uio_iovcnt = 1; 1239 uio.uio_offset = vd->offset * DEV_BSIZE; 1240 uio.uio_resid = vd->size; 1241 uio.uio_segflg = UIO_SYSSPACE; 1242 uio.uio_rw = UIO_WRITE; 1243 uio.uio_procp = p; 1244 1245 vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p); 1246 vd->status = VOP_WRITE(sc->sc_vp, &uio, 0, p->p_ucred); 1247 VOP_UNLOCK(sc->sc_vp, 0, p); 1248 1249 free(buf, M_DEVBUF); 1250 1251 /* ACK the descriptor. */ 1252 vd->hdr.dstate = VIO_DESC_DONE; 1253 vdsp_ack_desc(sc, vd); 1254 } 1255 1256 void 1257 vdsp_flush_dring(void *arg1, void *arg2) 1258 { 1259 struct vdsp_softc *sc = arg1; 1260 struct vd_desc *vd = arg2; 1261 1262 if (sc->sc_vp == NULL) 1263 return; 1264 1265 /* ACK the descriptor. */ 1266 vd->status = 0; 1267 vd->hdr.dstate = VIO_DESC_DONE; 1268 vdsp_ack_desc(sc, vd); 1269 } 1270 1271 void 1272 vdsp_get_vtoc(void *arg1, void *arg2) 1273 { 1274 struct vdsp_softc *sc = arg1; 1275 struct ldc_conn *lc = &sc->sc_lc; 1276 struct vd_desc *vd = arg2; 1277 struct sun_vtoc_preamble *sl; 1278 struct vd_vtoc *vt; 1279 vaddr_t va; 1280 paddr_t pa; 1281 uint64_t size, off; 1282 psize_t nbytes; 1283 int err, i; 1284 1285 vt = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO); 1286 1287 if (sc->sc_label == NULL) 1288 vdsp_readlabel(sc); 1289 1290 if (sc->sc_label && sc->sc_label->sl_magic == SUN_DKMAGIC) { 1291 sl = (struct sun_vtoc_preamble *)sc->sc_label; 1292 1293 memcpy(vt->ascii_label, sl->sl_text, sizeof(sl->sl_text)); 1294 memcpy(vt->volume_name, sl->sl_volume, sizeof(sl->sl_volume)); 1295 vt->sector_size = DEV_BSIZE; 1296 vt->num_partitions = sl->sl_nparts; 1297 for (i = 0; i < vt->num_partitions; i++) { 1298 vt->partition[i].id_tag = sl->sl_part[i].spi_tag; 1299 vt->partition[i].perm = sl->sl_part[i].spi_flag; 1300 vt->partition[i].start = 1301 sc->sc_label->sl_part[i].sdkp_cyloffset * 1302 sc->sc_label->sl_ntracks * 1303 sc->sc_label->sl_nsectors; 1304 vt->partition[i].nblocks = 1305 sc->sc_label->sl_part[i].sdkp_nsectors; 1306 } 1307 } else { 1308 uint64_t disk_size; 1309 int unit; 1310 1311 /* Human-readable disk size. */ 1312 disk_size = sc->sc_vdisk_size * sc->sc_vdisk_block_size; 1313 disk_size >>= 10; 1314 unit = 'K'; 1315 if (disk_size > (2 << 10)) { 1316 disk_size >>= 10; 1317 unit = 'M'; 1318 } 1319 if (disk_size > (2 << 10)) { 1320 disk_size >>= 10; 1321 unit = 'G'; 1322 } 1323 1324 snprintf(vt->ascii_label, sizeof(vt->ascii_label), 1325 "OpenBSD-DiskImage-%lld%cB cyl %d alt %d hd %d sec %d", 1326 disk_size, unit, sc->sc_ncyl, sc->sc_acyl, 1327 sc->sc_nhead, sc->sc_nsect); 1328 vt->sector_size = sc->sc_vdisk_block_size; 1329 vt->num_partitions = 8; 1330 vt->partition[2].id_tag = SPTAG_WHOLE_DISK; 1331 vt->partition[2].nblocks = 1332 sc->sc_ncyl * sc->sc_nhead * sc->sc_nsect; 1333 } 1334 1335 i = 0; 1336 va = (vaddr_t)vt; 1337 size = roundup(sizeof(*vt), 64); 1338 off = 0; 1339 while (size > 0 && i < vd->ncookies) { 1340 pmap_extract(pmap_kernel(), va, &pa); 1341 nbytes = min(size, vd->cookie[i].size - off); 1342 nbytes = min(nbytes, PAGE_SIZE - (off & PAGE_MASK)); 1343 err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT, 1344 vd->cookie[i].addr + off, pa, nbytes, &nbytes); 1345 if (err != H_EOK) 1346 printf("%s: hv_ldc_copy: %d\n", __func__, err); 1347 va += nbytes; 1348 size -= nbytes; 1349 off += nbytes; 1350 if (off >= vd->cookie[i].size) { 1351 off = 0; 1352 i++; 1353 } 1354 } 1355 1356 free(vt, M_DEVBUF); 1357 1358 /* ACK the descriptor. */ 1359 vd->status = 0; 1360 vd->hdr.dstate = VIO_DESC_DONE; 1361 vdsp_ack_desc(sc, vd); 1362 } 1363 1364 void 1365 vdsp_set_vtoc(void *arg1, void *arg2) 1366 { 1367 struct vdsp_softc *sc = arg1; 1368 struct ldc_conn *lc = &sc->sc_lc; 1369 struct vd_desc *vd = arg2; 1370 struct sun_vtoc_preamble *sl; 1371 struct vd_vtoc *vt; 1372 u_short cksum = 0, *sp1, *sp2; 1373 vaddr_t va; 1374 paddr_t pa; 1375 uint64_t size, off; 1376 psize_t nbytes; 1377 int err, i; 1378 1379 vt = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO); 1380 1381 i = 0; 1382 va = (vaddr_t)vt; 1383 size = sizeof(*vt); 1384 off = 0; 1385 while (size > 0 && i < vd->ncookies) { 1386 pmap_extract(pmap_kernel(), va, &pa); 1387 nbytes = min(size, vd->cookie[i].size - off); 1388 nbytes = min(nbytes, PAGE_SIZE - (off & PAGE_MASK)); 1389 err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN, 1390 vd->cookie[i].addr + off, pa, nbytes, &nbytes); 1391 if (err != H_EOK) 1392 printf("%s: hv_ldc_copy: %d\n", __func__, err); 1393 va += nbytes; 1394 size -= nbytes; 1395 off += nbytes; 1396 if (off >= vd->cookie[i].size) { 1397 off = 0; 1398 i++; 1399 } 1400 } 1401 1402 if (vt->num_partitions > nitems(sc->sc_label->sl_part)) { 1403 vd->status = EINVAL; 1404 goto fail; 1405 } 1406 1407 if (sc->sc_label == NULL || sc->sc_label->sl_magic != SUN_DKMAGIC) { 1408 sc->sc_label = malloc(sizeof(*sc->sc_label), 1409 M_DEVBUF, M_WAITOK | M_ZERO); 1410 1411 sc->sc_label->sl_ntracks = sc->sc_nhead; 1412 sc->sc_label->sl_nsectors = sc->sc_nsect; 1413 sc->sc_label->sl_ncylinders = sc->sc_ncyl; 1414 sc->sc_label->sl_acylinders = sc->sc_acyl; 1415 sc->sc_label->sl_pcylinders = sc->sc_ncyl + sc->sc_acyl; 1416 sc->sc_label->sl_rpm = 3600; 1417 1418 sc->sc_label->sl_magic = SUN_DKMAGIC; 1419 } 1420 1421 sl = (struct sun_vtoc_preamble *)sc->sc_label; 1422 memcpy(sl->sl_text, vt->ascii_label, sizeof(sl->sl_text)); 1423 sl->sl_version = 0x01; 1424 memcpy(sl->sl_volume, sl->sl_volume, sizeof(sl->sl_volume)); 1425 sl->sl_nparts = vt->num_partitions; 1426 for (i = 0; i < vt->num_partitions; i++) { 1427 sl->sl_part[i].spi_tag = vt->partition[i].id_tag; 1428 sl->sl_part[i].spi_flag = vt->partition[i].perm; 1429 sc->sc_label->sl_part[i].sdkp_cyloffset = 1430 vt->partition[i].start / (sc->sc_nhead * sc->sc_nsect); 1431 sc->sc_label->sl_part[i].sdkp_nsectors = 1432 vt->partition[i].nblocks; 1433 } 1434 sl->sl_sanity = 0x600ddeee; 1435 1436 /* Compute the checksum. */ 1437 sp1 = (u_short *)sc->sc_label; 1438 sp2 = (u_short *)(sc->sc_label + 1); 1439 while (sp1 < sp2) 1440 cksum ^= *sp1++; 1441 sc->sc_label->sl_cksum = cksum; 1442 1443 vd->status = vdsp_writelabel(sc); 1444 1445 fail: 1446 free(vt, M_DEVBUF); 1447 1448 /* ACK the descriptor. */ 1449 vd->hdr.dstate = VIO_DESC_DONE; 1450 vdsp_ack_desc(sc, vd); 1451 } 1452 1453 void 1454 vdsp_get_diskgeom(void *arg1, void *arg2) 1455 { 1456 struct vdsp_softc *sc = arg1; 1457 struct ldc_conn *lc = &sc->sc_lc; 1458 struct vd_desc *vd = arg2; 1459 struct vd_diskgeom *vg; 1460 vaddr_t va; 1461 paddr_t pa; 1462 uint64_t size, off; 1463 psize_t nbytes; 1464 int err, i; 1465 1466 vg = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO); 1467 1468 if (sc->sc_label == NULL) 1469 vdsp_readlabel(sc); 1470 1471 if (sc->sc_label && sc->sc_label->sl_magic == SUN_DKMAGIC) { 1472 vg->ncyl = sc->sc_label->sl_ncylinders; 1473 vg->acyl = sc->sc_label->sl_acylinders; 1474 vg->nhead = sc->sc_label->sl_ntracks; 1475 vg->nsect = sc->sc_label->sl_nsectors; 1476 vg->intrlv = sc->sc_label->sl_interleave; 1477 vg->apc = sc->sc_label->sl_sparespercyl; 1478 vg->rpm = sc->sc_label->sl_rpm; 1479 vg->pcyl = sc->sc_label->sl_pcylinders; 1480 } else { 1481 uint64_t disk_size, block_size; 1482 1483 disk_size = sc->sc_vdisk_size * sc->sc_vdisk_block_size; 1484 block_size = sc->sc_vdisk_block_size; 1485 1486 if (disk_size >= 8L * 1024 * 1024 * 1024) { 1487 vg->nhead = 96; 1488 vg->nsect = 768; 1489 } else if (disk_size >= 2 *1024 * 1024) { 1490 vg->nhead = 1; 1491 vg->nsect = 600; 1492 } else { 1493 vg->nhead = 1; 1494 vg->nsect = 200; 1495 } 1496 1497 vg->pcyl = disk_size / (block_size * vg->nhead * vg->nsect); 1498 if (vg->pcyl == 0) 1499 vg->pcyl = 1; 1500 if (vg->pcyl > 2) 1501 vg->acyl = 2; 1502 vg->ncyl = vg->pcyl - vg->acyl; 1503 1504 vg->rpm = 3600; 1505 } 1506 1507 sc->sc_ncyl = vg->ncyl; 1508 sc->sc_acyl = vg->acyl; 1509 sc->sc_nhead = vg->nhead; 1510 sc->sc_nsect = vg->nsect; 1511 1512 i = 0; 1513 va = (vaddr_t)vg; 1514 size = roundup(sizeof(*vg), 64); 1515 off = 0; 1516 while (size > 0 && i < vd->ncookies) { 1517 pmap_extract(pmap_kernel(), va, &pa); 1518 nbytes = min(size, vd->cookie[i].size - off); 1519 nbytes = min(nbytes, PAGE_SIZE - (off & PAGE_MASK)); 1520 err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT, 1521 vd->cookie[i].addr + off, pa, nbytes, &nbytes); 1522 if (err != H_EOK) 1523 printf("%s: hv_ldc_copy: %d\n", __func__, err); 1524 va += nbytes; 1525 size -= nbytes; 1526 off += nbytes; 1527 if (off >= vd->cookie[i].size) { 1528 off = 0; 1529 i++; 1530 } 1531 } 1532 1533 /* ACK the descriptor. */ 1534 vd->status = 0; 1535 vd->hdr.dstate = VIO_DESC_DONE; 1536 vdsp_ack_desc(sc, vd); 1537 } 1538 1539 void 1540 vdsp_unimp(void *arg1, void *arg2) 1541 { 1542 struct vdsp_softc *sc = arg1; 1543 struct vd_desc *vd = arg2; 1544 1545 /* ACK the descriptor. */ 1546 vd->status = ENOTSUP; 1547 vd->hdr.dstate = VIO_DESC_DONE; 1548 vdsp_ack_desc(sc, vd); 1549 } 1550 1551 void 1552 vdsp_ack_desc(struct vdsp_softc *sc, struct vd_desc *vd) 1553 { 1554 struct vio_dring_msg dm; 1555 vaddr_t va; 1556 paddr_t pa; 1557 uint64_t size, off; 1558 psize_t nbytes; 1559 int err; 1560 1561 va = (vaddr_t)vd; 1562 off = (caddr_t)vd - sc->sc_vd; 1563 size = sc->sc_descriptor_size; 1564 while (size > 0) { 1565 pmap_extract(pmap_kernel(), va, &pa); 1566 nbytes = min(size, PAGE_SIZE - (off & PAGE_MASK)); 1567 err = hv_ldc_copy(sc->sc_lc.lc_id, LDC_COPY_OUT, 1568 sc->sc_dring_cookie.addr | off, pa, nbytes, &nbytes); 1569 va += nbytes; 1570 size -= nbytes; 1571 off += nbytes; 1572 } 1573 if (err != H_EOK) { 1574 printf("%s: hv_ldc_copy %d\n", __func__, err); 1575 return; 1576 } 1577 1578 /* ACK the descriptor. */ 1579 bzero(&dm, sizeof(dm)); 1580 dm.tag.type = VIO_TYPE_DATA; 1581 dm.tag.stype = VIO_SUBTYPE_ACK; 1582 dm.tag.stype_env = VIO_DRING_DATA; 1583 dm.tag.sid = sc->sc_local_sid; 1584 dm.seq_no = ++sc->sc_seq_no; 1585 dm.dring_ident = sc->sc_dring_ident; 1586 off = (caddr_t)vd - sc->sc_vd; 1587 dm.start_idx = off / sc->sc_descriptor_size; 1588 dm.end_idx = off / sc->sc_descriptor_size; 1589 vdsp_sendmsg(sc, &dm, sizeof(dm)); 1590 } 1591