|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1993,1991,1990,1989 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * Author: David B. Golub, Carnegie Mellon University ! 28: * Date: 3/89 ! 29: */ ! 30: ! 31: #include <norma_device.h> ! 32: ! 33: #include <mach/boolean.h> ! 34: #include <mach/kern_return.h> ! 35: #include <mach/mig_errors.h> ! 36: #include <mach/port.h> ! 37: #include <mach/vm_param.h> ! 38: #include <mach/notify.h> ! 39: #include <machine/machspl.h> /* spl definitions */ ! 40: ! 41: #include <ipc/ipc_port.h> ! 42: #include <ipc/ipc_space.h> ! 43: ! 44: #include <kern/ast.h> ! 45: #include <kern/counters.h> ! 46: #include <kern/queue.h> ! 47: #include <kern/zalloc.h> ! 48: #include <kern/thread.h> ! 49: #include <kern/task.h> ! 50: #include <kern/sched_prim.h> ! 51: ! 52: #include <vm/memory_object.h> ! 53: #include <vm/vm_map.h> ! 54: #include <vm/vm_kern.h> ! 55: ! 56: #include <device/device_types.h> ! 57: #include <device/dev_hdr.h> ! 58: #include <device/conf.h> ! 59: #include <device/io_req.h> ! 60: #include <device/ds_routines.h> ! 61: #include <device/net_status.h> ! 62: #include <device/device_port.h> ! 63: #include "device_reply.h" ! 64: ! 65: #include <machine/machspl.h> ! 66: ! 67: #ifdef i386 ! 68: #include <i386at/device_emul.h> ! 69: #include <i386/device-drivers.h> ! 70: #endif ! 71: ! 72: #ifdef i386 ! 73: ipc_port_t ! 74: mach_convert_device_to_port (void *d) ! 75: { ! 76: ipc_port_t port; ! 77: mach_device_t device = d; ! 78: ! 79: if (! device) ! 80: return IP_NULL; ! 81: device_lock(device); ! 82: if (device->state == DEV_STATE_OPEN) ! 83: port = ipc_port_make_send(device->port); ! 84: else ! 85: port = IP_NULL; ! 86: device_unlock(device); ! 87: mach_device_deallocate(device); ! 88: return port; ! 89: } ! 90: #endif /* i386 */ ! 91: ! 92: #ifdef i386 ! 93: static io_return_t ! 94: device_open(reply_port, reply_port_type, mode, name, device_p) ! 95: #else ! 96: io_return_t ! 97: ds_device_open(open_port, reply_port, reply_port_type, ! 98: mode, name, device_p) ! 99: ipc_port_t open_port; ! 100: #endif ! 101: ipc_port_t reply_port; ! 102: mach_msg_type_name_t reply_port_type; ! 103: dev_mode_t mode; ! 104: char * name; ! 105: device_t *device_p; /* out */ ! 106: { ! 107: register mach_device_t device; ! 108: register kern_return_t result; ! 109: register io_req_t ior; ! 110: char namebuf[64]; ! 111: ipc_port_t notify; ! 112: ! 113: #ifndef i386 ! 114: /* ! 115: * Open must be called on the master device port. ! 116: */ ! 117: if (open_port != master_device_port) ! 118: return (D_INVALID_OPERATION); ! 119: ! 120: /* ! 121: * There must be a reply port. ! 122: */ ! 123: if (!IP_VALID(reply_port)) { ! 124: printf("ds_* invalid reply port\n"); ! 125: Debugger("ds_* reply_port"); ! 126: return (MIG_NO_REPLY); /* no sense in doing anything */ ! 127: } ! 128: ! 129: #if NORMA_DEVICE ! 130: /* ! 131: * Map global device name to <node> + local device name. ! 132: */ ! 133: if (name[0] != '<') { ! 134: extern char *dev_forward_name(); ! 135: ! 136: name = dev_forward_name(name, namebuf, sizeof(namebuf)); ! 137: } ! 138: /* ! 139: * Look for explicit node specifier, e.g., <2>sd0a. ! 140: * If found, then forward request to correct device server. ! 141: * If not found, then remove '<n>' and process locally. ! 142: * ! 143: * XXX should handle send-right reply_port as well as send-once XXX ! 144: */ ! 145: if (name[0] == '<') { ! 146: char *n; ! 147: int node = 0; ! 148: ! 149: for (n = &name[1]; *n != '>'; n++) { ! 150: if (*n >= '0' && *n <= '9') { ! 151: node = 10 * node + (*n - '0'); ! 152: } else { ! 153: return (D_NO_SUCH_DEVICE); ! 154: } ! 155: } ! 156: if (node == node_self()) { ! 157: name = &n[1]; /* skip trailing '>' */ ! 158: } else { ! 159: forward_device_open_send(remote_device(node), ! 160: reply_port, mode, name); ! 161: return (MIG_NO_REPLY); ! 162: } ! 163: } ! 164: #endif NORMA_DEVICE ! 165: #endif /* ! i386 */ ! 166: ! 167: /* ! 168: * Find the device. ! 169: */ ! 170: device = device_lookup(name); ! 171: if (device == MACH_DEVICE_NULL) ! 172: return (D_NO_SUCH_DEVICE); ! 173: ! 174: /* ! 175: * If the device is being opened or closed, ! 176: * wait for that operation to finish. ! 177: */ ! 178: device_lock(device); ! 179: while (device->state == DEV_STATE_OPENING || ! 180: device->state == DEV_STATE_CLOSING) { ! 181: device->io_wait = TRUE; ! 182: thread_sleep((event_t)device, simple_lock_addr(device->lock), TRUE); ! 183: device_lock(device); ! 184: } ! 185: ! 186: /* ! 187: * If the device is already open, increment the open count ! 188: * and return. ! 189: */ ! 190: if (device->state == DEV_STATE_OPEN) { ! 191: ! 192: if (device->flag & D_EXCL_OPEN) { ! 193: /* ! 194: * Cannot open a second time. ! 195: */ ! 196: device_unlock(device); ! 197: mach_device_deallocate(device); ! 198: return (D_ALREADY_OPEN); ! 199: } ! 200: ! 201: device->open_count++; ! 202: device_unlock(device); ! 203: #ifdef i386 ! 204: *device_p = &device->dev; ! 205: #else ! 206: *device_p = device; ! 207: #endif ! 208: return (D_SUCCESS); ! 209: /* ! 210: * Return deallocates device reference while acquiring ! 211: * port. ! 212: */ ! 213: } ! 214: ! 215: /* ! 216: * Allocate the device port and register the device before ! 217: * opening it. ! 218: */ ! 219: device->state = DEV_STATE_OPENING; ! 220: device_unlock(device); ! 221: ! 222: /* ! 223: * Allocate port, keeping a reference for it. ! 224: */ ! 225: device->port = ipc_port_alloc_kernel(); ! 226: if (device->port == IP_NULL) { ! 227: device_lock(device); ! 228: device->state = DEV_STATE_INIT; ! 229: device->port = IP_NULL; ! 230: if (device->io_wait) { ! 231: device->io_wait = FALSE; ! 232: thread_wakeup((event_t)device); ! 233: } ! 234: device_unlock(device); ! 235: mach_device_deallocate(device); ! 236: return (KERN_RESOURCE_SHORTAGE); ! 237: } ! 238: ! 239: dev_port_enter(device); ! 240: ! 241: /* ! 242: * Request no-senders notifications on device port. ! 243: */ ! 244: notify = ipc_port_make_sonce(device->port); ! 245: ip_lock(device->port); ! 246: ipc_port_nsrequest(device->port, 1, notify, ¬ify); ! 247: assert(notify == IP_NULL); ! 248: ! 249: /* ! 250: * Open the device. ! 251: */ ! 252: io_req_alloc(ior, 0); ! 253: ! 254: ior->io_device = device; ! 255: ior->io_unit = device->dev_number; ! 256: ior->io_op = IO_OPEN | IO_CALL; ! 257: ior->io_mode = mode; ! 258: ior->io_error = 0; ! 259: ior->io_done = ds_open_done; ! 260: ior->io_reply_port = reply_port; ! 261: ior->io_reply_port_type = reply_port_type; ! 262: ! 263: result = (*device->dev_ops->d_open)(device->dev_number, (int)mode, ior); ! 264: if (result == D_IO_QUEUED) ! 265: return (MIG_NO_REPLY); ! 266: ! 267: /* ! 268: * Return result via ds_open_done. ! 269: */ ! 270: ior->io_error = result; ! 271: (void) ds_open_done(ior); ! 272: ! 273: io_req_free(ior); ! 274: ! 275: return (MIG_NO_REPLY); /* reply already sent */ ! 276: } ! 277: ! 278: boolean_t ! 279: ds_open_done(ior) ! 280: register io_req_t ior; ! 281: { ! 282: kern_return_t result; ! 283: register mach_device_t device; ! 284: ! 285: device = ior->io_device; ! 286: result = ior->io_error; ! 287: ! 288: if (result != D_SUCCESS) { ! 289: /* ! 290: * Open failed. Deallocate port and device. ! 291: */ ! 292: dev_port_remove(device); ! 293: ipc_port_dealloc_kernel(device->port); ! 294: device->port = IP_NULL; ! 295: ! 296: device_lock(device); ! 297: device->state = DEV_STATE_INIT; ! 298: if (device->io_wait) { ! 299: device->io_wait = FALSE; ! 300: thread_wakeup((event_t)device); ! 301: } ! 302: device_unlock(device); ! 303: ! 304: mach_device_deallocate(device); ! 305: device = MACH_DEVICE_NULL; ! 306: } ! 307: else { ! 308: /* ! 309: * Open succeeded. ! 310: */ ! 311: device_lock(device); ! 312: device->state = DEV_STATE_OPEN; ! 313: device->open_count = 1; ! 314: if (device->io_wait) { ! 315: device->io_wait = FALSE; ! 316: thread_wakeup((event_t)device); ! 317: } ! 318: device_unlock(device); ! 319: ! 320: /* donate device reference to get port */ ! 321: } ! 322: /* ! 323: * Must explicitly convert device to port, since ! 324: * device_reply interface is built as 'user' side ! 325: * (thus cannot get translation). ! 326: */ ! 327: if (IP_VALID(ior->io_reply_port)) { ! 328: (void) ds_device_open_reply(ior->io_reply_port, ! 329: ior->io_reply_port_type, ! 330: result, ! 331: #ifdef i386 ! 332: (mach_convert_device_to_port ! 333: (device))); ! 334: #else ! 335: convert_device_to_port(device)); ! 336: #endif ! 337: } else ! 338: mach_device_deallocate(device); ! 339: ! 340: return (TRUE); ! 341: } ! 342: ! 343: #ifdef i386 ! 344: static io_return_t ! 345: device_close(device) ! 346: #else ! 347: io_return_t ! 348: ds_device_close(device) ! 349: #endif ! 350: register mach_device_t device; ! 351: { ! 352: #ifndef i386 ! 353: if (device == DEVICE_NULL) ! 354: return (D_NO_SUCH_DEVICE); ! 355: #endif ! 356: ! 357: device_lock(device); ! 358: ! 359: /* ! 360: * If device will remain open, do nothing. ! 361: */ ! 362: if (--device->open_count > 0) { ! 363: device_unlock(device); ! 364: return (D_SUCCESS); ! 365: } ! 366: ! 367: /* ! 368: * If device is being closed, do nothing. ! 369: */ ! 370: if (device->state == DEV_STATE_CLOSING) { ! 371: device_unlock(device); ! 372: return (D_SUCCESS); ! 373: } ! 374: ! 375: /* ! 376: * Mark device as closing, to prevent new IO. ! 377: * Outstanding IO will still be in progress. ! 378: */ ! 379: device->state = DEV_STATE_CLOSING; ! 380: device_unlock(device); ! 381: ! 382: /* ! 383: * ? wait for IO to end ? ! 384: * only if device wants to ! 385: */ ! 386: ! 387: /* ! 388: * Remove the device-port association. ! 389: */ ! 390: dev_port_remove(device); ! 391: ipc_port_dealloc_kernel(device->port); ! 392: ! 393: /* ! 394: * Close the device ! 395: */ ! 396: (*device->dev_ops->d_close)(device->dev_number); ! 397: ! 398: /* ! 399: * Finally mark it closed. If someone else is trying ! 400: * to open it, the open can now proceed. ! 401: */ ! 402: device_lock(device); ! 403: device->state = DEV_STATE_INIT; ! 404: if (device->io_wait) { ! 405: device->io_wait = FALSE; ! 406: thread_wakeup((event_t)device); ! 407: } ! 408: device_unlock(device); ! 409: ! 410: return (D_SUCCESS); ! 411: } ! 412: ! 413: /* ! 414: * Write to a device. ! 415: */ ! 416: #ifdef i386 ! 417: static io_return_t ! 418: device_write(d, reply_port, reply_port_type, mode, recnum, ! 419: data, data_count, bytes_written) ! 420: void *d; ! 421: #else ! 422: io_return_t ! 423: ds_device_write(device, reply_port, reply_port_type, mode, recnum, ! 424: data, data_count, bytes_written) ! 425: register mach_device_t device; ! 426: #endif ! 427: ipc_port_t reply_port; ! 428: mach_msg_type_name_t reply_port_type; ! 429: dev_mode_t mode; ! 430: recnum_t recnum; ! 431: io_buf_ptr_t data; ! 432: unsigned int data_count; ! 433: int *bytes_written; /* out */ ! 434: { ! 435: #ifdef i386 ! 436: register mach_device_t device = d; ! 437: #endif ! 438: register io_req_t ior; ! 439: register io_return_t result; ! 440: ! 441: #ifndef i386 ! 442: /* ! 443: * Refuse if device is dead or not completely open. ! 444: */ ! 445: if (device == DEVICE_NULL) ! 446: return (D_NO_SUCH_DEVICE); ! 447: #endif ! 448: ! 449: if (device->state != DEV_STATE_OPEN) ! 450: return (D_NO_SUCH_DEVICE); ! 451: ! 452: #ifndef i386 ! 453: if (data == 0) ! 454: return (D_INVALID_SIZE); ! 455: #endif ! 456: ! 457: /* ! 458: * XXX Need logic to reject ridiculously big requests. ! 459: */ ! 460: ! 461: /* XXX note that a CLOSE may proceed at any point */ ! 462: ! 463: /* ! 464: * Package the write request for the device driver ! 465: */ ! 466: io_req_alloc(ior, data_count); ! 467: ! 468: ior->io_device = device; ! 469: ior->io_unit = device->dev_number; ! 470: ior->io_op = IO_WRITE | IO_CALL; ! 471: ior->io_mode = mode; ! 472: ior->io_recnum = recnum; ! 473: ior->io_data = data; ! 474: ior->io_count = data_count; ! 475: ior->io_total = data_count; ! 476: ior->io_alloc_size = 0; ! 477: ior->io_residual = 0; ! 478: ior->io_error = 0; ! 479: ior->io_done = ds_write_done; ! 480: ior->io_reply_port = reply_port; ! 481: ior->io_reply_port_type = reply_port_type; ! 482: ior->io_copy = VM_MAP_COPY_NULL; ! 483: ! 484: /* ! 485: * The ior keeps an extra reference for the device. ! 486: */ ! 487: mach_device_reference(device); ! 488: ! 489: /* ! 490: * And do the write ... ! 491: * ! 492: * device_write_dealoc returns false if there's more ! 493: * to do; it has updated the ior appropriately and expects ! 494: * its caller to reinvoke it on the device. ! 495: */ ! 496: ! 497: do { ! 498: ! 499: result = (*device->dev_ops->d_write)(device->dev_number, ior); ! 500: ! 501: /* ! 502: * If the IO was queued, delay reply until it is finished. ! 503: */ ! 504: if (result == D_IO_QUEUED) ! 505: return (MIG_NO_REPLY); ! 506: ! 507: /* ! 508: * Discard the local mapping of the data. ! 509: */ ! 510: ! 511: } while (!device_write_dealloc(ior)); ! 512: ! 513: /* ! 514: * Return the number of bytes actually written. ! 515: */ ! 516: *bytes_written = ior->io_total - ior->io_residual; ! 517: ! 518: /* ! 519: * Remove the extra reference. ! 520: */ ! 521: mach_device_deallocate(device); ! 522: ! 523: io_req_free(ior); ! 524: return (result); ! 525: } ! 526: ! 527: /* ! 528: * Write to a device, but memory is in message. ! 529: */ ! 530: #ifdef i386 ! 531: static io_return_t ! 532: device_write_inband(d, reply_port, reply_port_type, mode, recnum, ! 533: data, data_count, bytes_written) ! 534: void *d; ! 535: #else ! 536: io_return_t ! 537: ds_device_write_inband(device, reply_port, reply_port_type, mode, recnum, ! 538: data, data_count, bytes_written) ! 539: register mach_device_t device; ! 540: #endif ! 541: ipc_port_t reply_port; ! 542: mach_msg_type_name_t reply_port_type; ! 543: dev_mode_t mode; ! 544: recnum_t recnum; ! 545: io_buf_ptr_inband_t data; ! 546: unsigned int data_count; ! 547: int *bytes_written; /* out */ ! 548: { ! 549: #ifdef i386 ! 550: register mach_device_t device = d; ! 551: #endif ! 552: register io_req_t ior; ! 553: register io_return_t result; ! 554: ! 555: #ifndef i386 ! 556: /* ! 557: * Refuse if device is dead or not completely open. ! 558: */ ! 559: if (device == DEVICE_NULL) ! 560: return (D_NO_SUCH_DEVICE); ! 561: #endif ! 562: ! 563: if (device->state != DEV_STATE_OPEN) ! 564: return (D_NO_SUCH_DEVICE); ! 565: ! 566: #ifndef i386 ! 567: if (data == 0) ! 568: return (D_INVALID_SIZE); ! 569: #endif ! 570: ! 571: /* XXX note that a CLOSE may proceed at any point */ ! 572: ! 573: /* ! 574: * Package the write request for the device driver. ! 575: */ ! 576: io_req_alloc(ior, 0); ! 577: ! 578: ior->io_device = device; ! 579: ior->io_unit = device->dev_number; ! 580: ior->io_op = IO_WRITE | IO_CALL | IO_INBAND; ! 581: ior->io_mode = mode; ! 582: ior->io_recnum = recnum; ! 583: ior->io_data = data; ! 584: ior->io_count = data_count; ! 585: ior->io_total = data_count; ! 586: ior->io_alloc_size = 0; ! 587: ior->io_residual = 0; ! 588: ior->io_error = 0; ! 589: ior->io_done = ds_write_done; ! 590: ior->io_reply_port = reply_port; ! 591: ior->io_reply_port_type = reply_port_type; ! 592: ! 593: /* ! 594: * The ior keeps an extra reference for the device. ! 595: */ ! 596: mach_device_reference(device); ! 597: ! 598: /* ! 599: * And do the write. ! 600: */ ! 601: result = (*device->dev_ops->d_write)(device->dev_number, ior); ! 602: ! 603: /* ! 604: * If the IO was queued, delay reply until it is finished. ! 605: */ ! 606: if (result == D_IO_QUEUED) ! 607: return (MIG_NO_REPLY); ! 608: ! 609: /* ! 610: * Return the number of bytes actually written. ! 611: */ ! 612: *bytes_written = ior->io_total - ior->io_residual; ! 613: ! 614: /* ! 615: * Remove the extra reference. ! 616: */ ! 617: mach_device_deallocate(device); ! 618: ! 619: io_req_free(ior); ! 620: return (result); ! 621: } ! 622: ! 623: /* ! 624: * Wire down incoming memory to give to device. ! 625: */ ! 626: kern_return_t ! 627: device_write_get(ior, wait) ! 628: register io_req_t ior; ! 629: boolean_t *wait; ! 630: { ! 631: vm_map_copy_t io_copy; ! 632: vm_offset_t new_addr; ! 633: register kern_return_t result; ! 634: int bsize; ! 635: vm_size_t min_size; ! 636: ! 637: /* ! 638: * By default, caller does not have to wait. ! 639: */ ! 640: *wait = FALSE; ! 641: ! 642: /* ! 643: * Nothing to do if no data. ! 644: */ ! 645: if (ior->io_count == 0) ! 646: return (KERN_SUCCESS); ! 647: ! 648: /* ! 649: * Loaned iors already have valid data. ! 650: */ ! 651: if (ior->io_op & IO_LOANED) ! 652: return (KERN_SUCCESS); ! 653: ! 654: /* ! 655: * Inband case. ! 656: */ ! 657: if (ior->io_op & IO_INBAND) { ! 658: assert(ior->io_count <= sizeof (io_buf_ptr_inband_t)); ! 659: new_addr = zalloc(io_inband_zone); ! 660: bcopy((void*)ior->io_data, (void*)new_addr, ior->io_count); ! 661: ior->io_data = (io_buf_ptr_t)new_addr; ! 662: ior->io_alloc_size = sizeof (io_buf_ptr_inband_t); ! 663: ! 664: return (KERN_SUCCESS); ! 665: } ! 666: ! 667: /* ! 668: * Figure out how much data to move this time. If the device ! 669: * won't return a block size, then we have to do the whole ! 670: * request in one shot (ditto if this is a block fragment), ! 671: * otherwise, move at least one block's worth. ! 672: */ ! 673: result = (*ior->io_device->dev_ops->d_dev_info)( ! 674: ior->io_device->dev_number, ! 675: D_INFO_BLOCK_SIZE, ! 676: &bsize); ! 677: ! 678: if (result != KERN_SUCCESS || ior->io_count < (vm_size_t) bsize) ! 679: min_size = (vm_size_t) ior->io_count; ! 680: else ! 681: min_size = (vm_size_t) bsize; ! 682: ! 683: /* ! 684: * Map the pages from this page list into memory. ! 685: * io_data records location of data. ! 686: * io_alloc_size is the vm size of the region to deallocate. ! 687: */ ! 688: io_copy = (vm_map_copy_t) ior->io_data; ! 689: result = kmem_io_map_copyout(device_io_map, ! 690: (vm_offset_t*)&ior->io_data, &new_addr, ! 691: &ior->io_alloc_size, io_copy, min_size); ! 692: if (result != KERN_SUCCESS) ! 693: return (result); ! 694: ! 695: if ((ior->io_data + ior->io_count) > ! 696: (((char *)new_addr) + ior->io_alloc_size)) { ! 697: ! 698: /* ! 699: * Operation has to be split. Reset io_count for how ! 700: * much we can do this time. ! 701: */ ! 702: assert(vm_map_copy_has_cont(io_copy)); ! 703: assert(ior->io_count == io_copy->size); ! 704: ior->io_count = ior->io_alloc_size - ! 705: (ior->io_data - ((char *)new_addr)); ! 706: ! 707: /* ! 708: * Caller must wait synchronously. ! 709: */ ! 710: ior->io_op &= ~IO_CALL; ! 711: *wait = TRUE; ! 712: } ! 713: ! 714: ior->io_copy = io_copy; /* vm_map_copy to discard */ ! 715: return (KERN_SUCCESS); ! 716: } ! 717: ! 718: /* ! 719: * Clean up memory allocated for IO. ! 720: */ ! 721: boolean_t ! 722: device_write_dealloc(ior) ! 723: register io_req_t ior; ! 724: { ! 725: vm_map_copy_t new_copy = VM_MAP_COPY_NULL; ! 726: register ! 727: vm_map_copy_t io_copy; ! 728: kern_return_t result; ! 729: vm_offset_t size_to_do; ! 730: int bsize; ! 731: ! 732: if (ior->io_alloc_size == 0) ! 733: return (TRUE); ! 734: ! 735: /* ! 736: * Inband case. ! 737: */ ! 738: if (ior->io_op & IO_INBAND) { ! 739: zfree(io_inband_zone, (vm_offset_t)ior->io_data); ! 740: ! 741: return (TRUE); ! 742: } ! 743: ! 744: if ((io_copy = ior->io_copy) == VM_MAP_COPY_NULL) ! 745: return (TRUE); ! 746: ! 747: /* ! 748: * To prevent a possible deadlock with the default pager, ! 749: * we have to release space in the device_io_map before ! 750: * we allocate any memory. (Which vm_map_copy_invoke_cont ! 751: * might do.) See the discussion in ds_init. ! 752: */ ! 753: ! 754: kmem_io_map_deallocate(device_io_map, ! 755: trunc_page(ior->io_data), ! 756: (vm_size_t) ior->io_alloc_size); ! 757: ! 758: if (vm_map_copy_has_cont(io_copy)) { ! 759: ! 760: /* ! 761: * Remember how much is left, then ! 762: * invoke or abort the continuation. ! 763: */ ! 764: size_to_do = io_copy->size - ior->io_count; ! 765: if (ior->io_error == 0) { ! 766: vm_map_copy_invoke_cont(io_copy, &new_copy, &result); ! 767: } ! 768: else { ! 769: vm_map_copy_abort_cont(io_copy); ! 770: result = KERN_FAILURE; ! 771: } ! 772: ! 773: if (result == KERN_SUCCESS && new_copy != VM_MAP_COPY_NULL) { ! 774: register int res; ! 775: ! 776: /* ! 777: * We have a new continuation, reset the ior to ! 778: * represent the remainder of the request. Must ! 779: * adjust the recnum because drivers assume ! 780: * that the residual is zero. ! 781: */ ! 782: ior->io_op &= ~IO_DONE; ! 783: ior->io_op |= IO_CALL; ! 784: ! 785: res = (*ior->io_device->dev_ops->d_dev_info)( ! 786: ior->io_device->dev_number, ! 787: D_INFO_BLOCK_SIZE, ! 788: &bsize); ! 789: ! 790: if (res != D_SUCCESS) ! 791: panic("device_write_dealloc: No block size"); ! 792: ! 793: ior->io_recnum += ior->io_count/bsize; ! 794: ior->io_count = new_copy->size; ! 795: } ! 796: else { ! 797: ! 798: /* ! 799: * No continuation. Add amount we didn't get ! 800: * to into residual. ! 801: */ ! 802: ior->io_residual += size_to_do; ! 803: } ! 804: } ! 805: ! 806: /* ! 807: * Clean up the state for the IO that just completed. ! 808: */ ! 809: vm_map_copy_discard(ior->io_copy); ! 810: ior->io_copy = VM_MAP_COPY_NULL; ! 811: ior->io_data = (char *) new_copy; ! 812: ! 813: /* ! 814: * Return FALSE if there's more IO to do. ! 815: */ ! 816: ! 817: return(new_copy == VM_MAP_COPY_NULL); ! 818: } ! 819: ! 820: /* ! 821: * Send write completion message to client, and discard the data. ! 822: */ ! 823: boolean_t ! 824: ds_write_done(ior) ! 825: register io_req_t ior; ! 826: { ! 827: /* ! 828: * device_write_dealloc discards the data that has been ! 829: * written, but may decide that there is more to write. ! 830: */ ! 831: while (!device_write_dealloc(ior)) { ! 832: register io_return_t result; ! 833: register mach_device_t device; ! 834: ! 835: /* ! 836: * More IO to do -- invoke it. ! 837: */ ! 838: device = ior->io_device; ! 839: result = (*device->dev_ops->d_write)(device->dev_number, ior); ! 840: ! 841: /* ! 842: * If the IO was queued, return FALSE -- not done yet. ! 843: */ ! 844: if (result == D_IO_QUEUED) ! 845: return (FALSE); ! 846: } ! 847: ! 848: /* ! 849: * Now the write is really complete. Send reply. ! 850: */ ! 851: ! 852: if (IP_VALID(ior->io_reply_port)) { ! 853: (void) (*((ior->io_op & IO_INBAND) ? ! 854: ds_device_write_reply_inband : ! 855: ds_device_write_reply))(ior->io_reply_port, ! 856: ior->io_reply_port_type, ! 857: ior->io_error, ! 858: (int) (ior->io_total - ! 859: ior->io_residual)); ! 860: } ! 861: mach_device_deallocate(ior->io_device); ! 862: ! 863: return (TRUE); ! 864: } ! 865: ! 866: /* ! 867: * Read from a device. ! 868: */ ! 869: #ifdef i386 ! 870: static io_return_t ! 871: device_read(d, reply_port, reply_port_type, mode, recnum, ! 872: bytes_wanted, data, data_count) ! 873: void *d; ! 874: #else ! 875: io_return_t ! 876: ds_device_read(device, reply_port, reply_port_type, mode, recnum, ! 877: bytes_wanted, data, data_count) ! 878: register mach_device_t device; ! 879: #endif ! 880: ipc_port_t reply_port; ! 881: mach_msg_type_name_t reply_port_type; ! 882: dev_mode_t mode; ! 883: recnum_t recnum; ! 884: int bytes_wanted; ! 885: io_buf_ptr_t *data; /* out */ ! 886: unsigned int *data_count; /* out */ ! 887: { ! 888: #ifdef i386 ! 889: register mach_device_t device = d; ! 890: #endif ! 891: register io_req_t ior; ! 892: register io_return_t result; ! 893: ! 894: #ifdef lint ! 895: *data = *data; ! 896: *data_count = *data_count; ! 897: #endif lint ! 898: ! 899: #ifndef i386 ! 900: /* ! 901: * Refuse if device is dead or not completely open. ! 902: */ ! 903: if (device == DEVICE_NULL) ! 904: return (D_NO_SUCH_DEVICE); ! 905: #endif ! 906: ! 907: if (device->state != DEV_STATE_OPEN) ! 908: return (D_NO_SUCH_DEVICE); ! 909: ! 910: /* XXX note that a CLOSE may proceed at any point */ ! 911: ! 912: /* ! 913: * There must be a reply port. ! 914: */ ! 915: if (!IP_VALID(reply_port)) { ! 916: printf("ds_* invalid reply port\n"); ! 917: Debugger("ds_* reply_port"); ! 918: return (MIG_NO_REPLY); /* no sense in doing anything */ ! 919: } ! 920: ! 921: /* ! 922: * Package the read request for the device driver ! 923: */ ! 924: io_req_alloc(ior, 0); ! 925: ! 926: ior->io_device = device; ! 927: ior->io_unit = device->dev_number; ! 928: ior->io_op = IO_READ | IO_CALL; ! 929: ior->io_mode = mode; ! 930: ior->io_recnum = recnum; ! 931: ior->io_data = 0; /* driver must allocate data */ ! 932: ior->io_count = bytes_wanted; ! 933: ior->io_alloc_size = 0; /* no data allocated yet */ ! 934: ior->io_residual = 0; ! 935: ior->io_error = 0; ! 936: ior->io_done = ds_read_done; ! 937: ior->io_reply_port = reply_port; ! 938: ior->io_reply_port_type = reply_port_type; ! 939: ! 940: /* ! 941: * The ior keeps an extra reference for the device. ! 942: */ ! 943: mach_device_reference(device); ! 944: ! 945: /* ! 946: * And do the read. ! 947: */ ! 948: result = (*device->dev_ops->d_read)(device->dev_number, ior); ! 949: ! 950: /* ! 951: * If the IO was queued, delay reply until it is finished. ! 952: */ ! 953: if (result == D_IO_QUEUED) ! 954: return (MIG_NO_REPLY); ! 955: ! 956: /* ! 957: * Return result via ds_read_done. ! 958: */ ! 959: ior->io_error = result; ! 960: (void) ds_read_done(ior); ! 961: io_req_free(ior); ! 962: ! 963: return (MIG_NO_REPLY); /* reply has already been sent. */ ! 964: } ! 965: ! 966: /* ! 967: * Read from a device, but return the data 'inband.' ! 968: */ ! 969: #ifdef i386 ! 970: static io_return_t ! 971: device_read_inband(d, reply_port, reply_port_type, mode, recnum, ! 972: bytes_wanted, data, data_count) ! 973: void *d; ! 974: #else ! 975: io_return_t ! 976: ds_device_read_inband(device, reply_port, reply_port_type, mode, recnum, ! 977: bytes_wanted, data, data_count) ! 978: register mach_device_t device; ! 979: #endif ! 980: ipc_port_t reply_port; ! 981: mach_msg_type_name_t reply_port_type; ! 982: dev_mode_t mode; ! 983: recnum_t recnum; ! 984: int bytes_wanted; ! 985: char *data; /* pointer to OUT array */ ! 986: unsigned int *data_count; /* out */ ! 987: { ! 988: #ifdef i386 ! 989: register mach_device_t device = d; ! 990: #endif ! 991: register io_req_t ior; ! 992: register io_return_t result; ! 993: ! 994: #ifdef lint ! 995: *data = *data; ! 996: *data_count = *data_count; ! 997: #endif lint ! 998: ! 999: #ifndef i386 ! 1000: /* ! 1001: * Refuse if device is dead or not completely open. ! 1002: */ ! 1003: if (device == DEVICE_NULL) ! 1004: return (D_NO_SUCH_DEVICE); ! 1005: #endif ! 1006: ! 1007: if (device->state != DEV_STATE_OPEN) ! 1008: return (D_NO_SUCH_DEVICE); ! 1009: ! 1010: /* XXX note that a CLOSE may proceed at any point */ ! 1011: ! 1012: /* ! 1013: * There must be a reply port. ! 1014: */ ! 1015: if (!IP_VALID(reply_port)) { ! 1016: printf("ds_* invalid reply port\n"); ! 1017: Debugger("ds_* reply_port"); ! 1018: return (MIG_NO_REPLY); /* no sense in doing anything */ ! 1019: } ! 1020: ! 1021: /* ! 1022: * Package the read for the device driver ! 1023: */ ! 1024: io_req_alloc(ior, 0); ! 1025: ! 1026: ior->io_device = device; ! 1027: ior->io_unit = device->dev_number; ! 1028: ior->io_op = IO_READ | IO_CALL | IO_INBAND; ! 1029: ior->io_mode = mode; ! 1030: ior->io_recnum = recnum; ! 1031: ior->io_data = 0; /* driver must allocate data */ ! 1032: ior->io_count = ! 1033: ((bytes_wanted < sizeof(io_buf_ptr_inband_t)) ? ! 1034: bytes_wanted : sizeof(io_buf_ptr_inband_t)); ! 1035: ior->io_alloc_size = 0; /* no data allocated yet */ ! 1036: ior->io_residual = 0; ! 1037: ior->io_error = 0; ! 1038: ior->io_done = ds_read_done; ! 1039: ior->io_reply_port = reply_port; ! 1040: ior->io_reply_port_type = reply_port_type; ! 1041: ! 1042: /* ! 1043: * The ior keeps an extra reference for the device. ! 1044: */ ! 1045: mach_device_reference(device); ! 1046: ! 1047: /* ! 1048: * Do the read. ! 1049: */ ! 1050: result = (*device->dev_ops->d_read)(device->dev_number, ior); ! 1051: ! 1052: /* ! 1053: * If the io was queued, delay reply until it is finished. ! 1054: */ ! 1055: if (result == D_IO_QUEUED) ! 1056: return (MIG_NO_REPLY); ! 1057: ! 1058: /* ! 1059: * Return result, via ds_read_done. ! 1060: */ ! 1061: ior->io_error = result; ! 1062: (void) ds_read_done(ior); ! 1063: io_req_free(ior); ! 1064: ! 1065: return (MIG_NO_REPLY); /* reply has already been sent. */ ! 1066: } ! 1067: ! 1068: ! 1069: /* ! 1070: * Allocate wired-down memory for device read. ! 1071: */ ! 1072: kern_return_t device_read_alloc(ior, size) ! 1073: register io_req_t ior; ! 1074: register vm_size_t size; ! 1075: { ! 1076: vm_offset_t addr; ! 1077: kern_return_t kr; ! 1078: ! 1079: /* ! 1080: * Nothing to do if no data. ! 1081: */ ! 1082: if (ior->io_count == 0) ! 1083: return (KERN_SUCCESS); ! 1084: ! 1085: if (ior->io_op & IO_INBAND) { ! 1086: ior->io_data = (io_buf_ptr_t) zalloc(io_inband_zone); ! 1087: ior->io_alloc_size = sizeof(io_buf_ptr_inband_t); ! 1088: } else { ! 1089: size = round_page(size); ! 1090: kr = kmem_alloc(kernel_map, &addr, size); ! 1091: if (kr != KERN_SUCCESS) ! 1092: return (kr); ! 1093: ! 1094: ior->io_data = (io_buf_ptr_t) addr; ! 1095: ior->io_alloc_size = size; ! 1096: } ! 1097: ! 1098: return (KERN_SUCCESS); ! 1099: } ! 1100: ! 1101: boolean_t ds_read_done(ior) ! 1102: io_req_t ior; ! 1103: { ! 1104: vm_offset_t start_data, end_data; ! 1105: vm_offset_t start_sent, end_sent; ! 1106: register vm_size_t size_read; ! 1107: ! 1108: if (ior->io_error) ! 1109: size_read = 0; ! 1110: else ! 1111: size_read = ior->io_count - ior->io_residual; ! 1112: ! 1113: start_data = (vm_offset_t)ior->io_data; ! 1114: end_data = start_data + size_read; ! 1115: ! 1116: start_sent = (ior->io_op & IO_INBAND) ? start_data : ! 1117: trunc_page(start_data); ! 1118: end_sent = (ior->io_op & IO_INBAND) ? ! 1119: start_data + ior->io_alloc_size : round_page(end_data); ! 1120: ! 1121: /* ! 1122: * Zero memory that the device did not fill. ! 1123: */ ! 1124: if (start_sent < start_data) ! 1125: bzero((char *)start_sent, start_data - start_sent); ! 1126: if (end_sent > end_data) ! 1127: bzero((char *)end_data, end_sent - end_data); ! 1128: ! 1129: ! 1130: /* ! 1131: * Touch the data being returned, to mark it dirty. ! 1132: * If the pages were filled by DMA, the pmap module ! 1133: * may think that they are clean. ! 1134: */ ! 1135: { ! 1136: register vm_offset_t touch; ! 1137: register int c; ! 1138: ! 1139: for (touch = start_sent; touch < end_sent; touch += PAGE_SIZE) { ! 1140: c = *(char *)touch; ! 1141: *(char *)touch = c; ! 1142: } ! 1143: } ! 1144: ! 1145: /* ! 1146: * Send the data to the reply port - this ! 1147: * unwires and deallocates it. ! 1148: */ ! 1149: if (ior->io_op & IO_INBAND) { ! 1150: (void)ds_device_read_reply_inband(ior->io_reply_port, ! 1151: ior->io_reply_port_type, ! 1152: ior->io_error, ! 1153: (char *) start_data, ! 1154: size_read); ! 1155: } else { ! 1156: vm_map_copy_t copy; ! 1157: kern_return_t kr; ! 1158: ! 1159: kr = vm_map_copyin_page_list(kernel_map, start_data, ! 1160: size_read, TRUE, TRUE, ! 1161: ©, FALSE); ! 1162: ! 1163: if (kr != KERN_SUCCESS) ! 1164: panic("read_done: vm_map_copyin_page_list failed"); ! 1165: ! 1166: (void)ds_device_read_reply(ior->io_reply_port, ! 1167: ior->io_reply_port_type, ! 1168: ior->io_error, ! 1169: (char *) copy, ! 1170: size_read); ! 1171: } ! 1172: ! 1173: /* ! 1174: * Free any memory that was allocated but not sent. ! 1175: */ ! 1176: if (ior->io_count != 0) { ! 1177: if (ior->io_op & IO_INBAND) { ! 1178: if (ior->io_alloc_size > 0) ! 1179: zfree(io_inband_zone, (vm_offset_t)ior->io_data); ! 1180: } else { ! 1181: register vm_offset_t end_alloc; ! 1182: ! 1183: end_alloc = start_sent + round_page(ior->io_alloc_size); ! 1184: if (end_alloc > end_sent) ! 1185: (void) vm_deallocate(kernel_map, ! 1186: end_sent, ! 1187: end_alloc - end_sent); ! 1188: } ! 1189: } ! 1190: ! 1191: mach_device_deallocate(ior->io_device); ! 1192: ! 1193: return (TRUE); ! 1194: } ! 1195: ! 1196: #ifdef i386 ! 1197: static io_return_t ! 1198: device_set_status(d, flavor, status, status_count) ! 1199: void *d; ! 1200: #else ! 1201: io_return_t ! 1202: ds_device_set_status(device, flavor, status, status_count) ! 1203: register mach_device_t device; ! 1204: #endif ! 1205: dev_flavor_t flavor; ! 1206: dev_status_t status; ! 1207: mach_msg_type_number_t status_count; ! 1208: { ! 1209: #ifdef i386 ! 1210: register mach_device_t device = d; ! 1211: #endif ! 1212: ! 1213: #ifndef i386 ! 1214: /* ! 1215: * Refuse if device is dead or not completely open. ! 1216: */ ! 1217: if (device == DEVICE_NULL) ! 1218: return (D_NO_SUCH_DEVICE); ! 1219: #endif ! 1220: ! 1221: if (device->state != DEV_STATE_OPEN) ! 1222: return (D_NO_SUCH_DEVICE); ! 1223: ! 1224: /* XXX note that a CLOSE may proceed at any point */ ! 1225: ! 1226: return ((*device->dev_ops->d_setstat)(device->dev_number, ! 1227: flavor, ! 1228: status, ! 1229: status_count)); ! 1230: } ! 1231: ! 1232: #ifdef i386 ! 1233: io_return_t ! 1234: mach_device_get_status(d, flavor, status, status_count) ! 1235: void *d; ! 1236: #else ! 1237: io_return_t ! 1238: ds_device_get_status(device, flavor, status, status_count) ! 1239: register mach_device_t device; ! 1240: #endif ! 1241: dev_flavor_t flavor; ! 1242: dev_status_t status; /* pointer to OUT array */ ! 1243: mach_msg_type_number_t *status_count; /* out */ ! 1244: { ! 1245: #ifdef i386 ! 1246: register mach_device_t device = d; ! 1247: #endif ! 1248: ! 1249: #ifndef i386 ! 1250: /* ! 1251: * Refuse if device is dead or not completely open. ! 1252: */ ! 1253: if (device == DEVICE_NULL) ! 1254: return (D_NO_SUCH_DEVICE); ! 1255: #endif ! 1256: ! 1257: if (device->state != DEV_STATE_OPEN) ! 1258: return (D_NO_SUCH_DEVICE); ! 1259: ! 1260: /* XXX note that a CLOSE may proceed at any point */ ! 1261: ! 1262: return ((*device->dev_ops->d_getstat)(device->dev_number, ! 1263: flavor, ! 1264: status, ! 1265: status_count)); ! 1266: } ! 1267: ! 1268: #ifdef i386 ! 1269: static io_return_t ! 1270: device_set_filter(d, receive_port, priority, filter, filter_count) ! 1271: void *d; ! 1272: #else ! 1273: io_return_t ! 1274: ds_device_set_filter(device, receive_port, priority, filter, filter_count) ! 1275: register mach_device_t device; ! 1276: #endif ! 1277: ipc_port_t receive_port; ! 1278: int priority; ! 1279: filter_t filter[]; /* pointer to IN array */ ! 1280: unsigned int filter_count; ! 1281: { ! 1282: #ifdef i386 ! 1283: register mach_device_t device = d; ! 1284: #endif ! 1285: ! 1286: #ifndef i386 ! 1287: /* ! 1288: * Refuse if device is dead or not completely open. ! 1289: */ ! 1290: if (device == DEVICE_NULL) ! 1291: return (D_NO_SUCH_DEVICE); ! 1292: #endif ! 1293: ! 1294: if (device->state != DEV_STATE_OPEN) ! 1295: return (D_NO_SUCH_DEVICE); ! 1296: ! 1297: /* XXX note that a CLOSE may proceed at any point */ ! 1298: ! 1299: /* ! 1300: * Request is absurd if no receive port is specified. ! 1301: */ ! 1302: if (!IP_VALID(receive_port)) ! 1303: return (D_INVALID_OPERATION); ! 1304: ! 1305: return ((*device->dev_ops->d_async_in)(device->dev_number, ! 1306: receive_port, ! 1307: priority, ! 1308: filter, ! 1309: filter_count)); ! 1310: } ! 1311: ! 1312: #ifdef i386 ! 1313: static io_return_t ! 1314: device_map(d, protection, offset, size, pager, unmap) ! 1315: void *d; ! 1316: #else ! 1317: io_return_t ! 1318: ds_device_map(device, protection, offset, size, pager, unmap) ! 1319: register mach_device_t device; ! 1320: #endif ! 1321: vm_prot_t protection; ! 1322: vm_offset_t offset; ! 1323: vm_size_t size; ! 1324: ipc_port_t *pager; /* out */ ! 1325: boolean_t unmap; /* ? */ ! 1326: { ! 1327: #ifdef i386 ! 1328: register mach_device_t device = d; ! 1329: #endif ! 1330: ! 1331: #ifdef lint ! 1332: unmap = unmap; ! 1333: #endif lint ! 1334: if (protection & ~VM_PROT_ALL) ! 1335: return (KERN_INVALID_ARGUMENT); ! 1336: ! 1337: #ifndef i386 ! 1338: /* ! 1339: * Refuse if device is dead or not completely open. ! 1340: */ ! 1341: if (device == DEVICE_NULL) ! 1342: return (D_NO_SUCH_DEVICE); ! 1343: #endif ! 1344: ! 1345: if (device->state != DEV_STATE_OPEN) ! 1346: return (D_NO_SUCH_DEVICE); ! 1347: ! 1348: /* XXX note that a CLOSE may proceed at any point */ ! 1349: ! 1350: return (device_pager_setup(device, protection, offset, size, ! 1351: (mach_port_t*)pager)); ! 1352: } ! 1353: ! 1354: /* ! 1355: * Doesn't do anything (yet). ! 1356: */ ! 1357: #ifdef i386 ! 1358: static void ! 1359: #else ! 1360: void ! 1361: #endif ! 1362: ds_no_senders(notification) ! 1363: mach_no_senders_notification_t *notification; ! 1364: { ! 1365: printf("ds_no_senders called! device_port=0x%x count=%d\n", ! 1366: notification->not_header.msgh_remote_port, ! 1367: notification->not_count); ! 1368: } ! 1369: ! 1370: #ifndef i386 ! 1371: boolean_t ! 1372: ds_notify(msg) ! 1373: mach_msg_header_t *msg; ! 1374: { ! 1375: switch (msg->msgh_id) { ! 1376: case MACH_NOTIFY_NO_SENDERS: ! 1377: ds_no_senders((mach_no_senders_notification_t *) msg); ! 1378: return TRUE; ! 1379: ! 1380: default: ! 1381: printf("ds_notify: strange notification %d\n", msg->msgh_id); ! 1382: return FALSE; ! 1383: } ! 1384: } ! 1385: #endif ! 1386: ! 1387: queue_head_t io_done_list; ! 1388: decl_simple_lock_data(, io_done_list_lock) ! 1389: ! 1390: #define splio splsched /* XXX must block ALL io devices */ ! 1391: ! 1392: void iodone(ior) ! 1393: register io_req_t ior; ! 1394: { ! 1395: register spl_t s; ! 1396: ! 1397: /* ! 1398: * If this ior was loaned to us, return it directly. ! 1399: */ ! 1400: if (ior->io_op & IO_LOANED) { ! 1401: (*ior->io_done)(ior); ! 1402: return; ! 1403: } ! 1404: /* ! 1405: * If !IO_CALL, some thread is waiting for this. Must lock ! 1406: * structure to interlock correctly with iowait(). Else can ! 1407: * toss on queue for io_done thread to call completion. ! 1408: */ ! 1409: s = splio(); ! 1410: if ((ior->io_op & IO_CALL) == 0) { ! 1411: ior_lock(ior); ! 1412: ior->io_op |= IO_DONE; ! 1413: ior->io_op &= ~IO_WANTED; ! 1414: ior_unlock(ior); ! 1415: thread_wakeup((event_t)ior); ! 1416: } else { ! 1417: ior->io_op |= IO_DONE; ! 1418: simple_lock(&io_done_list_lock); ! 1419: enqueue_tail(&io_done_list, (queue_entry_t)ior); ! 1420: thread_wakeup((event_t)&io_done_list); ! 1421: simple_unlock(&io_done_list_lock); ! 1422: } ! 1423: splx(s); ! 1424: } ! 1425: ! 1426: void io_done_thread_continue() ! 1427: { ! 1428: for (;;) { ! 1429: register spl_t s; ! 1430: register io_req_t ior; ! 1431: ! 1432: #if defined (i386) && defined (LINUX_DEV) && defined (CONFIG_INET) ! 1433: free_skbuffs (); ! 1434: #endif ! 1435: s = splio(); ! 1436: simple_lock(&io_done_list_lock); ! 1437: while ((ior = (io_req_t)dequeue_head(&io_done_list)) != 0) { ! 1438: simple_unlock(&io_done_list_lock); ! 1439: (void) splx(s); ! 1440: ! 1441: if ((*ior->io_done)(ior)) { ! 1442: /* ! 1443: * IO done - free io_req_elt ! 1444: */ ! 1445: io_req_free(ior); ! 1446: } ! 1447: /* else routine has re-queued it somewhere */ ! 1448: ! 1449: s = splio(); ! 1450: simple_lock(&io_done_list_lock); ! 1451: } ! 1452: ! 1453: assert_wait(&io_done_list, FALSE); ! 1454: simple_unlock(&io_done_list_lock); ! 1455: (void) splx(s); ! 1456: counter(c_io_done_thread_block++); ! 1457: thread_block(io_done_thread_continue); ! 1458: } ! 1459: } ! 1460: ! 1461: void io_done_thread() ! 1462: { ! 1463: /* ! 1464: * Set thread privileges and highest priority. ! 1465: */ ! 1466: current_thread()->vm_privilege = TRUE; ! 1467: stack_privilege(current_thread()); ! 1468: thread_set_own_priority(0); ! 1469: ! 1470: io_done_thread_continue(); ! 1471: /*NOTREACHED*/ ! 1472: } ! 1473: ! 1474: #define DEVICE_IO_MAP_SIZE (2 * 1024 * 1024) ! 1475: ! 1476: extern void ds_trap_init(void); /* forward */ ! 1477: ! 1478: void ds_init() ! 1479: { ! 1480: vm_offset_t device_io_min, device_io_max; ! 1481: ! 1482: queue_init(&io_done_list); ! 1483: simple_lock_init(&io_done_list_lock); ! 1484: ! 1485: device_io_map = kmem_suballoc(kernel_map, ! 1486: &device_io_min, ! 1487: &device_io_max, ! 1488: DEVICE_IO_MAP_SIZE, ! 1489: FALSE); ! 1490: /* ! 1491: * If the kernel receives many device_write requests, the ! 1492: * device_io_map might run out of space. To prevent ! 1493: * device_write_get from failing in this case, we enable ! 1494: * wait_for_space on the map. This causes kmem_io_map_copyout ! 1495: * to block until there is sufficient space. ! 1496: * (XXX Large writes may be starved by small writes.) ! 1497: * ! 1498: * There is a potential deadlock problem with this solution, ! 1499: * if a device_write from the default pager has to wait ! 1500: * for the completion of a device_write which needs to wait ! 1501: * for memory allocation. Hence, once device_write_get ! 1502: * allocates space in device_io_map, no blocking memory ! 1503: * allocations should happen until device_write_dealloc ! 1504: * frees the space. (XXX A large write might starve ! 1505: * a small write from the default pager.) ! 1506: */ ! 1507: device_io_map->wait_for_space = TRUE; ! 1508: ! 1509: io_inband_zone = zinit(sizeof(io_buf_ptr_inband_t), ! 1510: 1000 * sizeof(io_buf_ptr_inband_t), ! 1511: 10 * sizeof(io_buf_ptr_inband_t), ! 1512: FALSE, ! 1513: "io inband read buffers"); ! 1514: ! 1515: ds_trap_init(); ! 1516: } ! 1517: ! 1518: void iowait(ior) ! 1519: io_req_t ior; ! 1520: { ! 1521: spl_t s; ! 1522: ! 1523: s = splio(); ! 1524: ior_lock(ior); ! 1525: while ((ior->io_op&IO_DONE)==0) { ! 1526: assert_wait((event_t)ior, FALSE); ! 1527: ior_unlock(ior); ! 1528: thread_block((void (*)()) 0); ! 1529: ior_lock(ior); ! 1530: } ! 1531: ior_unlock(ior); ! 1532: splx(s); ! 1533: } ! 1534: ! 1535: ! 1536: /* ! 1537: * Device trap support. ! 1538: */ ! 1539: ! 1540: /* ! 1541: * Memory Management ! 1542: * ! 1543: * This currently has a single pool of 2k wired buffers ! 1544: * since we only handle writes to an ethernet device. ! 1545: * Should be more general. ! 1546: */ ! 1547: #define IOTRAP_REQSIZE 2048 ! 1548: ! 1549: zone_t io_trap_zone; ! 1550: ! 1551: /* ! 1552: * Initialization. Called from ds_init(). ! 1553: */ ! 1554: void ! 1555: ds_trap_init(void) ! 1556: { ! 1557: io_trap_zone = zinit(IOTRAP_REQSIZE, ! 1558: 256 * IOTRAP_REQSIZE, ! 1559: 16 * IOTRAP_REQSIZE, ! 1560: FALSE, ! 1561: "wired device trap buffers"); ! 1562: } ! 1563: ! 1564: /* ! 1565: * Allocate an io_req_t. ! 1566: * Currently zalloc's from io_trap_zone. ! 1567: * ! 1568: * Could have lists of different size zones. ! 1569: * Could call a device-specific routine. ! 1570: */ ! 1571: io_req_t ! 1572: ds_trap_req_alloc(mach_device_t device, vm_size_t data_size) ! 1573: { ! 1574: return (io_req_t) zalloc(io_trap_zone); ! 1575: } ! 1576: ! 1577: /* ! 1578: * Called by iodone to release ior. ! 1579: */ ! 1580: boolean_t ! 1581: ds_trap_write_done(io_req_t ior) ! 1582: { ! 1583: register mach_device_t dev; ! 1584: ! 1585: dev = ior->io_device; ! 1586: ! 1587: /* ! 1588: * Should look at reply port and maybe send a message. ! 1589: */ ! 1590: zfree(io_trap_zone, ior); ! 1591: ! 1592: /* ! 1593: * Give up device reference from ds_write_trap. ! 1594: */ ! 1595: mach_device_deallocate(dev); ! 1596: return TRUE; ! 1597: } ! 1598: ! 1599: /* ! 1600: * Like device_write except that data is in user space. ! 1601: */ ! 1602: #ifdef i386 ! 1603: static io_return_t ! 1604: device_write_trap (void *d, dev_mode_t mode, ! 1605: recnum_t recnum, vm_offset_t data, vm_size_t data_count) ! 1606: #else ! 1607: io_return_t ! 1608: ds_device_write_trap(device_t device, ! 1609: dev_mode_t mode, ! 1610: recnum_t recnum, ! 1611: vm_offset_t data, ! 1612: vm_size_t data_count) ! 1613: #endif ! 1614: { ! 1615: #ifdef i386 ! 1616: mach_device_t device = d; ! 1617: #endif ! 1618: io_req_t ior; ! 1619: io_return_t result; ! 1620: ! 1621: #ifndef i386 ! 1622: /* ! 1623: * Refuse if device is dead or not completely open. ! 1624: */ ! 1625: if (device == DEVICE_NULL) ! 1626: return (D_NO_SUCH_DEVICE); ! 1627: #endif ! 1628: ! 1629: if (device->state != DEV_STATE_OPEN) ! 1630: return (D_NO_SUCH_DEVICE); ! 1631: ! 1632: /* XXX note that a CLOSE may proceed at any point */ ! 1633: ! 1634: /* ! 1635: * Get a buffer to hold the ioreq. ! 1636: */ ! 1637: ior = ds_trap_req_alloc(device, data_count); ! 1638: ! 1639: /* ! 1640: * Package the write request for the device driver. ! 1641: */ ! 1642: ! 1643: ior->io_device = device; ! 1644: ior->io_unit = device->dev_number; ! 1645: ior->io_op = IO_WRITE | IO_CALL | IO_LOANED; ! 1646: ior->io_mode = mode; ! 1647: ior->io_recnum = recnum; ! 1648: ior->io_data = (io_buf_ptr_t) ! 1649: (vm_offset_t)ior + sizeof(struct io_req); ! 1650: ior->io_count = data_count; ! 1651: ior->io_total = data_count; ! 1652: ior->io_alloc_size = 0; ! 1653: ior->io_residual = 0; ! 1654: ior->io_error = 0; ! 1655: ior->io_done = ds_trap_write_done; ! 1656: ior->io_reply_port = IP_NULL; /* XXX */ ! 1657: ior->io_reply_port_type = 0; /* XXX */ ! 1658: ! 1659: /* ! 1660: * Copy the data from user space. ! 1661: */ ! 1662: if (data_count > 0) ! 1663: copyin((char *)data, (char *)ior->io_data, data_count); ! 1664: ! 1665: /* ! 1666: * The ior keeps an extra reference for the device. ! 1667: */ ! 1668: mach_device_reference(device); ! 1669: ! 1670: /* ! 1671: * And do the write. ! 1672: */ ! 1673: result = (*device->dev_ops->d_write)(device->dev_number, ior); ! 1674: ! 1675: /* ! 1676: * If the IO was queued, delay reply until it is finished. ! 1677: */ ! 1678: if (result == D_IO_QUEUED) ! 1679: return (MIG_NO_REPLY); ! 1680: ! 1681: /* ! 1682: * Remove the extra reference. ! 1683: */ ! 1684: mach_device_deallocate(device); ! 1685: ! 1686: zfree(io_trap_zone, ior); ! 1687: return (result); ! 1688: } ! 1689: ! 1690: #ifdef i386 ! 1691: static io_return_t ! 1692: device_writev_trap (void *d, dev_mode_t mode, ! 1693: recnum_t recnum, io_buf_vec_t *iovec, vm_size_t iocount) ! 1694: #else ! 1695: io_return_t ! 1696: ds_device_writev_trap(device_t device, ! 1697: dev_mode_t mode, ! 1698: recnum_t recnum, ! 1699: io_buf_vec_t *iovec, ! 1700: vm_size_t iocount) ! 1701: #endif ! 1702: { ! 1703: #ifdef i386 ! 1704: mach_device_t device = d; ! 1705: #endif ! 1706: io_req_t ior; ! 1707: io_return_t result; ! 1708: io_buf_vec_t stack_iovec[16]; /* XXX */ ! 1709: vm_size_t data_count; ! 1710: int i; ! 1711: ! 1712: #ifndef i386 ! 1713: /* ! 1714: * Refuse if device is dead or not completely open. ! 1715: */ ! 1716: if (device == DEVICE_NULL) ! 1717: return (D_NO_SUCH_DEVICE); ! 1718: #endif ! 1719: ! 1720: if (device->state != DEV_STATE_OPEN) ! 1721: return (D_NO_SUCH_DEVICE); ! 1722: ! 1723: /* XXX note that a CLOSE may proceed at any point */ ! 1724: ! 1725: /* ! 1726: * Copyin user addresses. ! 1727: */ ! 1728: if (iocount > 16) ! 1729: return KERN_INVALID_VALUE; /* lame */ ! 1730: copyin((char *)iovec, ! 1731: (char *)stack_iovec, ! 1732: iocount * sizeof(io_buf_vec_t)); ! 1733: for (data_count = 0, i = 0; i < iocount; i++) ! 1734: data_count += stack_iovec[i].count; ! 1735: ! 1736: /* ! 1737: * Get a buffer to hold the ioreq. ! 1738: */ ! 1739: ior = ds_trap_req_alloc(device, data_count); ! 1740: ! 1741: /* ! 1742: * Package the write request for the device driver. ! 1743: */ ! 1744: ! 1745: ior->io_device = device; ! 1746: ior->io_unit = device->dev_number; ! 1747: ior->io_op = IO_WRITE | IO_CALL | IO_LOANED; ! 1748: ior->io_mode = mode; ! 1749: ior->io_recnum = recnum; ! 1750: ior->io_data = (io_buf_ptr_t) ! 1751: (vm_offset_t)ior + sizeof(struct io_req); ! 1752: ior->io_count = data_count; ! 1753: ior->io_total = data_count; ! 1754: ior->io_alloc_size = 0; ! 1755: ior->io_residual = 0; ! 1756: ior->io_error = 0; ! 1757: ior->io_done = ds_trap_write_done; ! 1758: ior->io_reply_port = IP_NULL; /* XXX */ ! 1759: ior->io_reply_port_type = 0; /* XXX */ ! 1760: ! 1761: /* ! 1762: * Copy the data from user space. ! 1763: */ ! 1764: if (data_count > 0) { ! 1765: vm_offset_t p; ! 1766: ! 1767: p = (vm_offset_t) ior->io_data; ! 1768: for (i = 0; i < iocount; i++) { ! 1769: copyin((char *) stack_iovec[i].data, ! 1770: (char *) p, ! 1771: stack_iovec[i].count); ! 1772: p += stack_iovec[i].count; ! 1773: } ! 1774: } ! 1775: ! 1776: /* ! 1777: * The ior keeps an extra reference for the device. ! 1778: */ ! 1779: mach_device_reference(device); ! 1780: ! 1781: /* ! 1782: * And do the write. ! 1783: */ ! 1784: result = (*device->dev_ops->d_write)(device->dev_number, ior); ! 1785: ! 1786: /* ! 1787: * If the IO was queued, delay reply until it is finished. ! 1788: */ ! 1789: if (result == D_IO_QUEUED) ! 1790: return (MIG_NO_REPLY); ! 1791: ! 1792: /* ! 1793: * Remove the extra reference. ! 1794: */ ! 1795: mach_device_deallocate(device); ! 1796: ! 1797: zfree(io_trap_zone, ior); ! 1798: return (result); ! 1799: } ! 1800: ! 1801: #ifdef i386 ! 1802: struct device_emulation_ops mach_device_emulation_ops = ! 1803: { ! 1804: mach_device_reference, ! 1805: mach_device_deallocate, ! 1806: mach_convert_device_to_port, ! 1807: device_open, ! 1808: device_close, ! 1809: device_write, ! 1810: device_write_inband, ! 1811: device_read, ! 1812: device_read_inband, ! 1813: device_set_status, ! 1814: mach_device_get_status, ! 1815: device_set_filter, ! 1816: device_map, ! 1817: ds_no_senders, ! 1818: device_write_trap, ! 1819: device_writev_trap ! 1820: }; ! 1821: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.