123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731 |
- /*
- * Copyright (C) 2006-2009, 2011 Free Software Foundation
- *
- * This program is free software ; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation ; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY ; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the program ; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- #include <sys/types.h>
- #include <mach/mig_errors.h>
- #include <kern/kalloc.h>
- #include <ipc/ipc_port.h>
- #include <ipc/ipc_space.h>
- #include <vm/vm_kern.h>
- #include <vm/vm_user.h>
- #include <device/device_types.h>
- #include <device/device_port.h>
- #include <device/disk_status.h>
- #include <device/device_reply.user.h>
- #include <device/device_emul.h>
- #include <device/ds_routines.h>
- #include <xen/public/io/blkif.h>
- #include <xen/evt.h>
- #include <string.h>
- #include <util/atoi.h>
- #include "store.h"
- #include "block.h"
- #include "grant.h"
- #include "ring.h"
- #include "xen.h"
- /* Hypervisor part */
- struct block_data {
- struct device device;
- char *name;
- int open_count;
- char *backend;
- domid_t domid;
- char *vbd;
- int handle;
- unsigned info;
- dev_mode_t mode;
- unsigned sector_size;
- unsigned long nr_sectors;
- ipc_port_t port;
- blkif_front_ring_t ring;
- evtchn_port_t evt;
- simple_lock_data_t lock;
- simple_lock_data_t pushlock;
- };
- static int n_vbds;
- static struct block_data *vbd_data;
- struct device_emulation_ops hyp_block_emulation_ops;
- static void hyp_block_intr(int unit) {
- struct block_data *bd = &vbd_data[unit];
- blkif_response_t *rsp;
- int more;
- io_return_t *err;
- simple_lock(&bd->lock);
- more = RING_HAS_UNCONSUMED_RESPONSES(&bd->ring);
- while (more) {
- rmb(); /* make sure we see responses */
- rsp = RING_GET_RESPONSE(&bd->ring, bd->ring.rsp_cons++);
- err = (void *) (unsigned long) rsp->id;
- switch (rsp->status) {
- case BLKIF_RSP_ERROR:
- *err = D_IO_ERROR;
- break;
- case BLKIF_RSP_OKAY:
- break;
- default:
- printf("Unrecognized blkif status %d\n", rsp->status);
- goto drop;
- }
- thread_wakeup(err);
- drop:
- thread_wakeup_one(bd);
- RING_FINAL_CHECK_FOR_RESPONSES(&bd->ring, more);
- }
- simple_unlock(&bd->lock);
- }
- #define VBD_PATH "device/vbd"
- void hyp_block_init(void) {
- char **vbds, **vbd;
- char *c;
- int i, disk, partition;
- int n;
- int grant;
- char port_name[10];
- char *prefix;
- char device_name[32];
- domid_t domid;
- evtchn_port_t evt;
- hyp_store_transaction_t t;
- vm_offset_t addr;
- struct block_data *bd;
- blkif_sring_t *ring;
- vbds = hyp_store_ls(0, 1, VBD_PATH);
- if (!vbds) {
- printf("hd: No block device (%s). Hoping you don't need any\n", hyp_store_error);
- n_vbds = 0;
- return;
- }
- n = 0;
- for (vbd = vbds; *vbd; vbd++)
- n++;
- vbd_data = (void*) kalloc(n * sizeof(*vbd_data));
- if (!vbd_data) {
- printf("hd: No memory room for VBD\n");
- n_vbds = 0;
- return;
- }
- n_vbds = n;
- for (n = 0; n < n_vbds; n++) {
- bd = &vbd_data[n];
- mach_atoi((u_char *) vbds[n], &bd->handle);
- if (bd->handle == MACH_ATOI_DEFAULT)
- continue;
- bd->open_count = -2;
- bd->vbd = vbds[n];
- /* Get virtual number. */
- i = hyp_store_read_int(0, 5, VBD_PATH, "/", vbds[n], "/", "virtual-device");
- if (i == -1)
- panic("hd: couldn't virtual device of VBD %s\n",vbds[n]);
- if ((i >> 28) == 1) {
- /* xvd, new format */
- prefix = "xvd";
- disk = (i >> 8) & ((1 << 20) - 1);
- partition = i & ((1 << 8) - 1);
- } else if ((i >> 8) == 202) {
- /* xvd, old format */
- prefix = "xvd";
- disk = (i >> 4) & ((1 << 4) - 1);
- partition = i & ((1 << 4) - 1);
- } else if ((i >> 8) == 8) {
- /* SCSI */
- prefix = "sd";
- disk = (i >> 4) & ((1 << 4) - 1);
- partition = i & ((1 << 4) - 1);
- } else if ((i >> 8) == 3) {
- /* IDE primary */
- prefix = "hd";
- disk = (i >> 6) & ((1 << 2) - 1);
- partition = i & ((1 << 6) - 1);
- } else if ((i >> 8) == 22) {
- /* IDE secondary */
- prefix = "hd";
- disk = ((i >> 6) & ((1 << 2) - 1)) + 2;
- partition = i & ((1 << 6) - 1);
- } else if ((i >> 8) == 33) {
- /* IDE 3 */
- prefix = "hd";
- disk = ((i >> 6) & ((1 << 2) - 1)) + 4;
- partition = i & ((1 << 6) - 1);
- } else if ((i >> 8) == 34) {
- /* IDE 4 */
- prefix = "hd";
- disk = ((i >> 6) & ((1 << 2) - 1)) + 6;
- partition = i & ((1 << 6) - 1);
- } else if ((i >> 8) == 56) {
- /* IDE 5 */
- prefix = "hd";
- disk = ((i >> 6) & ((1 << 2) - 1)) + 8;
- partition = i & ((1 << 6) - 1);
- } else if ((i >> 8) == 57) {
- /* IDE 6 */
- prefix = "hd";
- disk = ((i >> 6) & ((1 << 2) - 1)) + 10;
- partition = i & ((1 << 6) - 1);
- } else if ((i >> 8) == 88) {
- /* IDE 7 */
- prefix = "hd";
- disk = ((i >> 6) & ((1 << 2) - 1)) + 12;
- partition = i & ((1 << 6) - 1);
- } else if ((i >> 8) == 89) {
- /* IDE 8 */
- prefix = "hd";
- disk = ((i >> 6) & ((1 << 2) - 1)) + 14;
- partition = i & ((1 << 6) - 1);
- } else if ((i >> 8) == 90) {
- /* IDE 9 */
- prefix = "hd";
- disk = ((i >> 6) & ((1 << 2) - 1)) + 16;
- partition = i & ((1 << 6) - 1);
- } else if ((i >> 8) == 91) {
- /* IDE 10 */
- prefix = "hd";
- disk = ((i >> 6) & ((1 << 2) - 1)) + 18;
- partition = i & ((1 << 6) - 1);
- } else {
- printf("unsupported VBD number %d\n", i);
- continue;
- }
- if (partition)
- sprintf(device_name, "%s%ds%d", prefix, disk, partition);
- else
- sprintf(device_name, "%s%d", prefix, disk);
- bd->name = (char*) kalloc(strlen(device_name) + 1);
- strcpy(bd->name, device_name);
- /* Get domain id of backend driver. */
- i = hyp_store_read_int(0, 5, VBD_PATH, "/", vbds[n], "/", "backend-id");
- if (i == -1)
- panic("%s: couldn't read backend domid (%s)", device_name, hyp_store_error);
- bd->domid = domid = i;
- do {
- t = hyp_store_transaction_start();
- /* Get a page for ring */
- if ((addr = vm_page_grab_phys_addr()) == -1)
- panic("%s: couldn't allocate space for store ring\n", device_name);
- ring = (void*) phystokv(addr);
- SHARED_RING_INIT(ring);
- FRONT_RING_INIT(&bd->ring, ring, PAGE_SIZE);
- grant = hyp_grant_give(domid, atop(addr), 0);
- /* and give it to backend. */
- i = sprintf(port_name, "%d", grant);
- c = hyp_store_write(t, port_name, 5, VBD_PATH, "/", vbds[n], "/", "ring-ref");
- if (!c)
- panic("%s: couldn't store ring reference (%s)", device_name, hyp_store_error);
- kfree((vm_offset_t) c, strlen(c)+1);
- /* Allocate an event channel and give it to backend. */
- bd->evt = evt = hyp_event_channel_alloc(domid);
- hyp_evt_handler(evt, hyp_block_intr, n, SPL7);
- i = sprintf(port_name, "%u", evt);
- c = hyp_store_write(t, port_name, 5, VBD_PATH, "/", vbds[n], "/", "event-channel");
- if (!c)
- panic("%s: couldn't store event channel (%s)", device_name, hyp_store_error);
- kfree((vm_offset_t) c, strlen(c)+1);
- c = hyp_store_write(t, hyp_store_state_initialized, 5, VBD_PATH, "/", vbds[n], "/", "state");
- if (!c)
- panic("%s: couldn't store state (%s)", device_name, hyp_store_error);
- kfree((vm_offset_t) c, strlen(c)+1);
- } while (!hyp_store_transaction_stop(t));
- /* TODO randomly wait? */
- c = hyp_store_read(0, 5, VBD_PATH, "/", vbds[n], "/", "backend");
- if (!c)
- panic("%s: couldn't get path to backend (%s)", device_name, hyp_store_error);
- bd->backend = c;
- while(1) {
- i = hyp_store_read_int(0, 3, bd->backend, "/", "state");
- if (i == MACH_ATOI_DEFAULT)
- panic("can't read state from %s", bd->backend);
- if (i == XenbusStateConnected)
- break;
- hyp_yield();
- }
- i = hyp_store_read_int(0, 3, bd->backend, "/", "sectors");
- if (i == -1)
- panic("%s: couldn't get number of sectors (%s)", device_name, hyp_store_error);
- bd->nr_sectors = i;
-
- i = hyp_store_read_int(0, 3, bd->backend, "/", "sector-size");
- if (i == -1)
- panic("%s: couldn't get sector size (%s)", device_name, hyp_store_error);
- if (i & ~(2*(i-1)+1))
- panic("sector size %d is not a power of 2\n", i);
- if (i > PAGE_SIZE || PAGE_SIZE % i != 0)
- panic("%s: couldn't handle sector size %d with pages of size %d\n", device_name, i, PAGE_SIZE);
- bd->sector_size = i;
- i = hyp_store_read_int(0, 3, bd->backend, "/", "info");
- if (i == -1)
- panic("%s: couldn't get info (%s)", device_name, hyp_store_error);
- bd->info = i;
-
- c = hyp_store_read(0, 3, bd->backend, "/", "mode");
- if (!c)
- panic("%s: couldn't get backend's mode (%s)", device_name, hyp_store_error);
- if ((c[0] == 'w') && !(bd->info & VDISK_READONLY))
- bd->mode = D_READ|D_WRITE;
- else
- bd->mode = D_READ;
- c = hyp_store_read(0, 3, bd->backend, "/", "params");
- if (!c)
- panic("%s: couldn't get backend's real device (%s)", device_name, hyp_store_error);
- /* TODO: change suffix */
- printf("%s: dom%d's VBD %s (%s,%c%s) %ldMB\n", device_name, domid,
- vbds[n], c, bd->mode & D_WRITE ? 'w' : 'r',
- bd->info & VDISK_CDROM ? ", cdrom" : "",
- bd->nr_sectors / ((1<<20) / 512));
- kfree((vm_offset_t) c, strlen(c)+1);
- c = hyp_store_write(0, hyp_store_state_connected, 5, VBD_PATH, "/", bd->vbd, "/", "state");
- if (!c)
- panic("couldn't store state for %s (%s)", device_name, hyp_store_error);
- kfree((vm_offset_t) c, strlen(c)+1);
- bd->open_count = -1;
- bd->device.emul_ops = &hyp_block_emulation_ops;
- bd->device.emul_data = bd;
- simple_lock_init(&bd->lock);
- simple_lock_init(&bd->pushlock);
- }
- }
- static ipc_port_t
- dev_to_port(void *d)
- {
- struct block_data *b = d;
- if (!d)
- return IP_NULL;
- return ipc_port_make_send(b->port);
- }
- static int
- device_close(void *devp)
- {
- struct block_data *bd = devp;
- if (--bd->open_count < 0)
- panic("too many closes on %s", bd->name);
- printf("close, %s count %d\n", bd->name, bd->open_count);
- if (bd->open_count)
- return 0;
- ipc_kobject_set(bd->port, IKO_NULL, IKOT_NONE);
- ipc_port_dealloc_kernel(bd->port);
- return 0;
- }
- static io_return_t
- device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
- dev_mode_t mode, char *name, device_t *devp /* out */)
- {
- int i;
- ipc_port_t port, notify;
- struct block_data *bd;
- for (i = 0; i < n_vbds; i++)
- if (!strcmp(name, vbd_data[i].name))
- break;
- if (i == n_vbds)
- return D_NO_SUCH_DEVICE;
- bd = &vbd_data[i];
- if (bd->open_count == -2)
- /* couldn't be initialized */
- return D_NO_SUCH_DEVICE;
- if ((mode & D_WRITE) && !(bd->mode & D_WRITE))
- return D_READ_ONLY;
- if (bd->open_count >= 0) {
- *devp = &bd->device ;
- bd->open_count++ ;
- printf("re-open, %s count %d\n", bd->name, bd->open_count);
- return D_SUCCESS;
- }
- bd->open_count = 1;
- printf("%s count %d\n", bd->name, bd->open_count);
- port = ipc_port_alloc_kernel();
- if (port == IP_NULL) {
- device_close(bd);
- return KERN_RESOURCE_SHORTAGE;
- }
- bd->port = port;
- *devp = &bd->device;
- ipc_kobject_set (port, (ipc_kobject_t) &bd->device, IKOT_DEVICE);
- notify = ipc_port_make_sonce (bd->port);
- ip_lock (bd->port);
- ipc_port_nsrequest (bd->port, 1, notify, ¬ify);
- assert (notify == IP_NULL);
- if (IP_VALID (reply_port))
- ds_device_open_reply (reply_port, reply_port_type, D_SUCCESS, port);
- else
- device_close(bd);
- return MIG_NO_REPLY;
- }
- static io_return_t
- device_read (void *d, ipc_port_t reply_port,
- mach_msg_type_name_t reply_port_type, dev_mode_t mode,
- recnum_t bn, int count, io_buf_ptr_t *data,
- unsigned *bytes_read)
- {
- int resid, amt;
- io_return_t err = 0;
- vm_page_t pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- grant_ref_t gref[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- int nbpages;
- vm_map_copy_t copy;
- vm_offset_t offset, alloc_offset, o;
- vm_object_t object;
- vm_page_t m;
- vm_size_t len, size;
- struct block_data *bd = d;
- struct blkif_request *req;
- *data = 0;
- *bytes_read = 0;
- if (count < 0)
- return D_INVALID_SIZE;
- if (count == 0)
- return 0;
- /* Allocate an object to hold the data. */
- size = round_page (count);
- object = vm_object_allocate (size);
- if (! object)
- {
- err = D_NO_MEMORY;
- goto out;
- }
- alloc_offset = offset = 0;
- resid = count;
- while (resid && !err)
- {
- unsigned reqn;
- int i;
- int last_sect;
- nbpages = 0;
- /* Determine size of I/O this time around. */
- len = round_page(offset + resid) - offset;
- if (len > PAGE_SIZE * BLKIF_MAX_SEGMENTS_PER_REQUEST)
- len = PAGE_SIZE * BLKIF_MAX_SEGMENTS_PER_REQUEST;
- /* Allocate pages. */
- while (alloc_offset < offset + len)
- {
- while ((m = vm_page_grab ()) == 0)
- VM_PAGE_WAIT (0);
- assert (! m->active && ! m->inactive);
- m->busy = TRUE;
- assert(nbpages < BLKIF_MAX_SEGMENTS_PER_REQUEST);
- pages[nbpages++] = m;
- alloc_offset += PAGE_SIZE;
- }
- /* Do the read. */
- amt = len;
- if (amt > resid)
- amt = resid;
- /* allocate a request */
- spl_t spl = splsched();
- while(1) {
- simple_lock(&bd->lock);
- if (!RING_FULL(&bd->ring))
- break;
- thread_sleep(bd, &bd->lock, FALSE);
- }
- mb();
- reqn = bd->ring.req_prod_pvt++;;
- simple_lock(&bd->pushlock);
- simple_unlock(&bd->lock);
- (void) splx(spl);
- req = RING_GET_REQUEST(&bd->ring, reqn);
- req->operation = BLKIF_OP_READ;
- req->nr_segments = nbpages;
- req->handle = bd->handle;
- req->id = (uint64_t) (unsigned long) &err; /* pointer on the stack */
- req->sector_number = bn + offset / 512;
- for (i = 0; i < nbpages; i++) {
- req->seg[i].gref = gref[i] = hyp_grant_give(bd->domid, atop(pages[i]->phys_addr), 0);
- req->seg[i].first_sect = 0;
- req->seg[i].last_sect = PAGE_SIZE/512 - 1;
- }
- last_sect = ((amt - 1) & PAGE_MASK) / 512;
- req->seg[nbpages-1].last_sect = last_sect;
- memset((void*) phystokv(pages[nbpages-1]->phys_addr
- + (last_sect + 1) * 512),
- 0, PAGE_SIZE - (last_sect + 1) * 512);
- /* no need for a lock: as long as the request is not pushed, the event won't be triggered */
- assert_wait((event_t) &err, FALSE);
- int notify;
- wmb(); /* make sure it sees requests */
- RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bd->ring, notify);
- if (notify)
- hyp_event_channel_send(bd->evt);
- simple_unlock(&bd->pushlock);
- thread_block(NULL);
- if (err)
- printf("error reading %d bytes at sector %ld\n", amt,
- bn + offset / 512);
- for (i = 0; i < nbpages; i++)
- hyp_grant_takeback(gref[i]);
- /* Compute number of pages to insert in object. */
- o = offset;
- resid -= amt;
- if (resid == 0)
- offset = o + len;
- else
- offset += amt;
- /* Add pages to the object. */
- vm_object_lock (object);
- for (i = 0; i < nbpages; i++)
- {
- m = pages[i];
- assert (m->busy);
- vm_page_lock_queues ();
- PAGE_WAKEUP_DONE (m);
- m->dirty = TRUE;
- vm_page_insert (m, object, o);
- vm_page_unlock_queues ();
- o += PAGE_SIZE;
- }
- vm_object_unlock (object);
- }
- out:
- if (! err)
- err = vm_map_copyin_object (object, 0, round_page (count), ©);
- if (! err)
- {
- *data = (io_buf_ptr_t) copy;
- *bytes_read = count - resid;
- }
- else
- vm_object_deallocate (object);
- return err;
- }
- static io_return_t
- device_write(void *d, ipc_port_t reply_port,
- mach_msg_type_name_t reply_port_type, dev_mode_t mode,
- recnum_t bn, io_buf_ptr_t data, unsigned int count,
- int *bytes_written)
- {
- io_return_t err = 0;
- vm_map_copy_t copy = (vm_map_copy_t) data;
- vm_offset_t buffer = 0;
- char *map_data;
- vm_offset_t map_addr;
- vm_size_t map_size;
- unsigned copy_npages = atop(round_page(count));
- vm_offset_t phys_addrs[copy_npages];
- struct block_data *bd = d;
- blkif_request_t *req;
- grant_ref_t gref[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- unsigned reqn, size;
- unsigned i, nbpages, j;
- kern_return_t kr;
- if (!(bd->mode & D_WRITE))
- return D_READ_ONLY;
- if (count == 0) {
- vm_map_copy_discard(copy);
- return 0;
- }
- if (count % bd->sector_size)
- return D_INVALID_SIZE;
- if (count > copy->size)
- return D_INVALID_SIZE;
- /* XXX The underlying physical pages of the mapping could be highmem,
- for which drivers require the use of a bounce buffer. */
- kr = kmem_alloc(device_io_map, &buffer, count);
- if (kr != KERN_SUCCESS)
- return kr;
- kr = kmem_io_map_copyout(device_io_map, (vm_offset_t *)&map_data,
- &map_addr, &map_size, copy, count);
- if (kr != KERN_SUCCESS) {
- kmem_free(device_io_map, buffer, count);
- return kr;
- }
- memcpy((void *)buffer, map_data, count);
- kmem_io_map_deallocate(device_io_map, map_addr, map_size);
- for (i = 0; i < copy_npages; i++)
- phys_addrs[i] = kvtophys(buffer + ptoa(i));
- for (i=0; i<copy_npages; i+=nbpages) {
- nbpages = BLKIF_MAX_SEGMENTS_PER_REQUEST;
- if (nbpages > copy_npages-i)
- nbpages = copy_npages-i;
- /* allocate a request */
- spl_t spl = splsched();
- while(1) {
- simple_lock(&bd->lock);
- if (!RING_FULL(&bd->ring))
- break;
- thread_sleep(bd, &bd->lock, FALSE);
- }
- mb();
- reqn = bd->ring.req_prod_pvt++;;
- simple_lock(&bd->pushlock);
- simple_unlock(&bd->lock);
- (void) splx(spl);
- req = RING_GET_REQUEST(&bd->ring, reqn);
- req->operation = BLKIF_OP_WRITE;
- req->nr_segments = nbpages;
- req->handle = bd->handle;
- req->id = (uint64_t) (unsigned long) &err; /* pointer on the stack */
- req->sector_number = bn + i*PAGE_SIZE / 512;
- for (j = 0; j < nbpages; j++) {
- req->seg[j].gref = gref[j] = hyp_grant_give(bd->domid, atop(phys_addrs[i + j]), 1);
- req->seg[j].first_sect = 0;
- size = PAGE_SIZE;
- if ((i + j + 1) * PAGE_SIZE > count)
- size = count - (i + j) * PAGE_SIZE;
- req->seg[j].last_sect = size/512 - 1;
- }
- /* no need for a lock: as long as the request is not pushed, the event won't be triggered */
- assert_wait((event_t) &err, FALSE);
- int notify;
- wmb(); /* make sure it sees requests */
- RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bd->ring, notify);
- if (notify)
- hyp_event_channel_send(bd->evt);
- simple_unlock(&bd->pushlock);
- thread_block(NULL);
- for (j = 0; j < nbpages; j++)
- hyp_grant_takeback(gref[j]);
- if (err) {
- printf("error writing %u bytes at sector %d\n", count, bn);
- break;
- }
- }
- if (buffer)
- kmem_free(device_io_map, buffer, count);
- vm_map_copy_discard (copy);
- if (!err)
- *bytes_written = count;
- if (IP_VALID(reply_port))
- ds_device_write_reply (reply_port, reply_port_type, err, count);
- return MIG_NO_REPLY;
- }
- static io_return_t
- device_get_status(void *d, dev_flavor_t flavor, dev_status_t status,
- mach_msg_type_number_t *status_count)
- {
- struct block_data *bd = d;
- switch (flavor)
- {
- case DEV_GET_SIZE:
- status[DEV_GET_SIZE_DEVICE_SIZE] = (unsigned long long) bd->nr_sectors * 512;
- status[DEV_GET_SIZE_RECORD_SIZE] = bd->sector_size;
- *status_count = DEV_GET_SIZE_COUNT;
- break;
- case DEV_GET_RECORDS:
- status[DEV_GET_RECORDS_DEVICE_RECORDS] = ((unsigned long long) bd->nr_sectors * 512) / bd->sector_size;
- status[DEV_GET_RECORDS_RECORD_SIZE] = bd->sector_size;
- *status_count = DEV_GET_RECORDS_COUNT;
- break;
- default:
- printf("TODO: block_%s(%d)\n", __func__, flavor);
- return D_INVALID_OPERATION;
- }
- return D_SUCCESS;
- }
- struct device_emulation_ops hyp_block_emulation_ops = {
- NULL, /* dereference */
- NULL, /* deallocate */
- dev_to_port,
- device_open,
- device_close,
- device_write,
- NULL, /* write_inband */
- device_read,
- NULL, /* read_inband */
- NULL, /* set_status */
- device_get_status,
- NULL, /* set_filter */
- NULL, /* map */
- NULL, /* no_senders */
- NULL, /* write_trap */
- NULL, /* writev_trap */
- };
|