|
|
1.1 ! root 1: /* device server routines for oskit block devices ! 2: * ! 3: * Some code here stolen from linux/dev/glue/block.c by Shantanu Goel ! 4: * ! 5: * Copyright (C) 1996, 1999 The University of Utah and the Computer Systems ! 6: * Laboratory at the University of Utah (CSL) ! 7: * ! 8: * This program is free software; you can redistribute it and/or modify ! 9: * it under the terms of the GNU General Public License as published by ! 10: * the Free Software Foundation; either version 2, or (at your option) ! 11: * any later version. ! 12: * ! 13: * This program is distributed in the hope that it will be useful, ! 14: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 16: * GNU General Public License for more details. ! 17: * ! 18: * You should have received a copy of the GNU General Public License ! 19: * along with this program; if not, write to the Free Software ! 20: * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ! 21: */ ! 22: ! 23: #include "ds_oskit.h" ! 24: ! 25: #include <vm/vm_map.h> ! 26: #include <vm/vm_kern.h> ! 27: #include <vm/vm_page.h> ! 28: ! 29: #include <string.h> ! 30: ! 31: #include <oskit/io/blkio.h> ! 32: ! 33: ! 34: #define MAX_COPY (VM_MAP_COPY_PAGE_LIST_MAX << PAGE_SHIFT) ! 35: ! 36: #if 0 ! 37: /* XXX no point in getting fancy since the oskit (linux/dev) code ! 38: will allocate its own wired memory and copy the data we pass into it ! 39: regardless. ! 40: */ ! 41: io_return_t ! 42: ds_blkio_write (device_t dev, ipc_port_t reply_port, ! 43: mach_msg_type_name_t reply_port_type, dev_mode_t mode, ! 44: recnum_t recnum, io_buf_ptr_t data, unsigned int count, ! 45: int *bytes_written) ! 46: { ! 47: io_return_t err; ! 48: oskit_error_t rc; ! 49: vm_map_copy_t copy = (vm_map_copy_t) data; ! 50: oskit_size_t resid, amt, i; ! 51: vm_offset_t addr, uaddr; ! 52: vm_size_t len, size; ! 53: ! 54: if (count % dev->com.blk.size) ! 55: INVALSZ; ! 56: ! 57: resid = count; ! 58: uaddr = copy->offset; ! 59: ! 60: /* Allocate a kernel buffer. */ ! 61: size = round_page (uaddr + count) - trunc_page (uaddr); ! 62: if (size > MAX_COPY) ! 63: size = MAX_COPY; ! 64: addr = vm_map_min (device_io_map); ! 65: err = vm_map_enter (device_io_map, &addr, size, 0, TRUE, ! 66: 0, 0, FALSE, VM_PROT_READ|VM_PROT_WRITE, ! 67: VM_PROT_READ|VM_PROT_WRITE, VM_INHERIT_NONE); ! 68: if (err) ! 69: { ! 70: vm_map_copy_discard (copy); ! 71: return err; ! 72: } ! 73: ! 74: /* Determine size of I/O this time around. */ ! 75: len = size - (uaddr & PAGE_MASK); ! 76: if (len > resid) ! 77: len = resid; ! 78: ! 79: offset = (oskit_off_t)recnum * dev->com.blk.size; ! 80: ! 81: do ! 82: { ! 83: /* Map user pages. */ ! 84: for (i = 0; i < copy->cpy_npages; i++) ! 85: pmap_enter (vm_map_pmap (device_io_map), ! 86: addr + (i << PAGE_SHIFT), ! 87: copy->cpy_page_list[i]->phys_addr, ! 88: VM_PROT_READ /* |VM_PROT_WRITE ? */, TRUE); ! 89: ! 90: /* Do the write. */ ! 91: rc = oskit_blkio_write (dev->com.blk.io, ! 92: (const char *) addr + (uaddr & PAGE_MASK), ! 93: offset, len, &amt); ! 94: ! 95: /* Unmap pages and deallocate copy. */ ! 96: pmap_remove (vm_map_pmap (device_io_map), ! 97: addr, addr + (copy->cpy_npages << PAGE_SHIFT)); ! 98: vm_map_copy_discard (copy); ! 99: ! 100: /* Check result of write. */ ! 101: if (rc) ! 102: { ! 103: err = oskit_to_mach_error (rc); ! 104: break; ! 105: } ! 106: else ! 107: { ! 108: resid -= amt; ! 109: if (resid == 0) ! 110: break; ! 111: uaddr += amt; ! 112: offset += amt; ! 113: } ! 114: ! 115: /* Determine size of I/O this time around and copy in pages. */ ! 116: len = round_page (uaddr + resid) - trunc_page (uaddr); ! 117: if (len > MAX_COPY) ! 118: len = MAX_COPY; ! 119: len -= uaddr & PAGE_MASK; ! 120: if (len > resid) ! 121: len = resid; ! 122: err = vm_map_copyin_page_list (current_map (), uaddr, len, ! 123: FALSE, FALSE, ©, FALSE); ! 124: } while (!err); ! 125: ! 126: /* Delete kernel buffer. */ ! 127: vm_map_remove (device_io_map, addr, addr + size); ! 128: ! 129: return err; ! 130: } ! 131: #endif ! 132: ! 133: io_return_t ! 134: ds_blkio_write_inband (device_t dev, ipc_port_t reply_port, ! 135: mach_msg_type_name_t reply_port_type, dev_mode_t mode, ! 136: recnum_t recnum, io_buf_ptr_t data, unsigned int count, ! 137: int *bytes_written) ! 138: { ! 139: oskit_error_t rc; ! 140: ! 141: /* Note that IO_INBAND_MAX is 128, so it is impossible to pass this ! 142: test for usual block sizes (>= 512) with any device_write_inband RPC. ! 143: But this function gets called by the generic ds_routines.c code for ! 144: out-of-band device_write too. */ ! 145: ! 146: if (count % dev->com.blk.size) ! 147: INVALSZ; ! 148: ! 149: rc = oskit_blkio_write (dev->com.blk.io, data, ! 150: (oskit_off_t)recnum * dev->com.blk.size, ! 151: count, (oskit_size_t *) bytes_written); ! 152: ! 153: return oskit_to_mach_error (rc); ! 154: } ! 155: ! 156: ! 157: io_return_t ! 158: ds_blkio_read (device_t dev, ipc_port_t reply_port, ! 159: mach_msg_type_name_t reply_port_type, dev_mode_t mode, ! 160: recnum_t recnum, int count, io_buf_ptr_t *data, ! 161: unsigned *bytes_read) ! 162: { ! 163: io_return_t err; ! 164: oskit_error_t rc; ! 165: boolean_t dirty; ! 166: oskit_size_t resid, amt; ! 167: queue_head_t pages; ! 168: vm_map_copy_t copy; ! 169: vm_offset_t addr, offset, alloc_offset, o; ! 170: vm_object_t object; ! 171: vm_page_t m; ! 172: vm_size_t len, size; ! 173: oskit_off_t readloc; ! 174: ! 175: if (count % dev->com.blk.size) ! 176: INVALSZ; ! 177: ! 178: *data = 0; ! 179: *bytes_read = 0; ! 180: ! 181: /* Allocate an object to hold the data. */ ! 182: size = round_page (count); ! 183: object = vm_object_allocate (size); ! 184: if (! object) ! 185: return D_NO_MEMORY; ! 186: ! 187: alloc_offset = offset = 0; ! 188: resid = count; ! 189: ! 190: /* Allocate a kernel buffer. */ ! 191: addr = vm_map_min (device_io_map); ! 192: if (size > MAX_COPY) ! 193: size = MAX_COPY; ! 194: err = vm_map_enter (device_io_map, &addr, size, 0, TRUE, 0, ! 195: 0, FALSE, VM_PROT_READ|VM_PROT_WRITE, ! 196: VM_PROT_READ|VM_PROT_WRITE, VM_INHERIT_NONE); ! 197: if (err) ! 198: goto out; ! 199: ! 200: queue_init (&pages); ! 201: ! 202: readloc = (oskit_off_t)recnum * dev->com.blk.size; ! 203: ! 204: while (resid) ! 205: { ! 206: /* Determine size of I/O this time around. */ ! 207: len = round_page (offset + resid) - trunc_page (offset); ! 208: if (len > MAX_COPY) ! 209: len = MAX_COPY; ! 210: ! 211: /* Map any pages left from previous operation. */ ! 212: o = trunc_page (offset); ! 213: queue_iterate (&pages, m, vm_page_t, pageq) ! 214: { ! 215: pmap_enter (vm_map_pmap (device_io_map), ! 216: addr + o - trunc_page (offset), ! 217: m->phys_addr, VM_PROT_READ|VM_PROT_WRITE, TRUE); ! 218: o += PAGE_SIZE; ! 219: } ! 220: assert (o == alloc_offset); ! 221: ! 222: /* Allocate and map pages. */ ! 223: while (alloc_offset < trunc_page (offset) + len) ! 224: { ! 225: while ((m = vm_page_grab (FALSE)) == 0) ! 226: VM_PAGE_WAIT (0); ! 227: assert (! m->active && ! m->inactive); ! 228: m->busy = TRUE; ! 229: queue_enter (&pages, m, vm_page_t, pageq); ! 230: pmap_enter (vm_map_pmap (device_io_map), ! 231: addr + alloc_offset - trunc_page (offset), ! 232: m->phys_addr, VM_PROT_READ|VM_PROT_WRITE, TRUE); ! 233: alloc_offset += PAGE_SIZE; ! 234: } ! 235: ! 236: /* Do the read. */ ! 237: amt = len - (offset & PAGE_MASK); ! 238: if (amt > resid) ! 239: amt = resid; ! 240: rc = oskit_blkio_read (dev->com.blk.io, ! 241: (char *) addr + (offset & PAGE_MASK), ! 242: readloc, amt, &amt); ! 243: ! 244: /* Compute number of pages to insert in object. */ ! 245: o = trunc_page (offset); ! 246: if (rc == 0) ! 247: { ! 248: dirty = TRUE; ! 249: resid -= amt; ! 250: if (resid == 0) ! 251: { ! 252: /* Zero any unused space. */ ! 253: if (offset + amt < o + len) ! 254: memset ((void *) (addr + offset - o + amt), ! 255: 0, o + len - offset - amt); ! 256: offset = o + len; ! 257: } ! 258: else ! 259: offset += amt; ! 260: } ! 261: else ! 262: { ! 263: dirty = FALSE; ! 264: offset = o + len; ! 265: } ! 266: ! 267: /* Unmap pages and add them to the object. */ ! 268: pmap_remove (vm_map_pmap (device_io_map), addr, addr + len); ! 269: vm_object_lock (object); ! 270: while (o < trunc_page (offset)) ! 271: { ! 272: m = (vm_page_t) queue_first (&pages); ! 273: assert (! queue_end (&pages, (queue_entry_t) m)); ! 274: queue_remove (&pages, m, vm_page_t, pageq); ! 275: assert (m->busy); ! 276: vm_page_lock_queues (); ! 277: if (dirty) ! 278: { ! 279: PAGE_WAKEUP_DONE (m); ! 280: m->dirty = TRUE; ! 281: vm_page_insert (m, object, o); ! 282: } ! 283: else ! 284: vm_page_free (m); ! 285: vm_page_unlock_queues (); ! 286: o += PAGE_SIZE; ! 287: } ! 288: vm_object_unlock (object); ! 289: ! 290: if (rc) ! 291: { ! 292: err = oskit_to_mach_error (rc); ! 293: break; ! 294: } ! 295: else if (amt == 0) /* XXX ? */ ! 296: break; ! 297: else ! 298: readloc += amt; ! 299: } ! 300: ! 301: /* Delete kernel buffer. */ ! 302: vm_map_remove (device_io_map, addr, addr + size); ! 303: ! 304: assert (queue_empty (&pages)); ! 305: ! 306: out: ! 307: if (! err) ! 308: err = vm_map_copyin_object (object, 0, round_page (count), ©); ! 309: if (! err) ! 310: { ! 311: *data = (io_buf_ptr_t) copy; ! 312: *bytes_read = count - resid; ! 313: } ! 314: else ! 315: vm_object_deallocate (object); ! 316: ! 317: return err; ! 318: } ! 319: ! 320: io_return_t ! 321: ds_blkio_get_status (device_t dev, dev_flavor_t flavor, dev_status_t status, ! 322: mach_msg_type_number_t *status_count) ! 323: { ! 324: oskit_error_t rc; ! 325: switch (flavor) ! 326: { ! 327: case DEV_GET_SIZE: ! 328: { ! 329: oskit_off_t size; ! 330: ! 331: /* DEV->com.blk.size was initialized on open. */ ! 332: status[DEV_GET_SIZE_RECORD_SIZE] = dev->com.blk.size; ! 333: ! 334: rc = oskit_blkio_getsize (dev->com.blk.io, &size); ! 335: if (rc == OSKIT_E_NOTIMPL) ! 336: status[DEV_GET_SIZE_DEVICE_SIZE] = 0; ! 337: else if (rc) ! 338: return oskit_to_mach_error (rc); ! 339: else ! 340: status[DEV_GET_SIZE_DEVICE_SIZE] = size; ! 341: ! 342: *status_count = 2; ! 343: return D_SUCCESS; ! 344: } ! 345: case DEV_GET_RECORDS: ! 346: { ! 347: oskit_off_t size; ! 348: ! 349: /* DEV->com.blk.size was initialized on open. */ ! 350: status[DEV_GET_RECORDS_RECORD_SIZE] = dev->com.blk.size; ! 351: assert (dev->com.blk.size > 0); ! 352: ! 353: rc = oskit_blkio_getsize (dev->com.blk.io, &size); ! 354: if (rc == OSKIT_E_NOTIMPL) ! 355: size = 0; ! 356: else if (rc) ! 357: return oskit_to_mach_error (rc); ! 358: ! 359: status[DEV_GET_RECORDS_DEVICE_RECORDS] ! 360: = (recnum_t) (size / (oskit_off_t) dev->com.blk.size); ! 361: ! 362: /* Always return DEV_GET_RECORDS_COUNT. This is what all native ! 363: Mach drivers do, and makes it possible to detect the absence ! 364: of the call by setting it to a different value on input. MiG ! 365: makes sure that we will never return more integers than the ! 366: user asked for. */ ! 367: *status_count = DEV_GET_RECORDS_COUNT; ! 368: return D_SUCCESS; ! 369: } ! 370: } ! 371: INVALOP; ! 372: } ! 373: ! 374: void ! 375: ds_blkio_close (device_t dev) ! 376: { ! 377: /* Free any partition info we cached about this disk. */ ! 378: if (dev->com.blk.parts) ! 379: kfree ((vm_offset_t) dev->com.blk.parts, ! 380: MAX_PARTS * sizeof dev->com.blk.parts[0]); ! 381: } ! 382: ! 383: const struct device_ops block_device_ops = ! 384: { ! 385: write_inband: ds_blkio_write_inband, ! 386: read: ds_blkio_read, ! 387: get_status: ds_blkio_get_status, ! 388: close: ds_blkio_close ! 389: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.