Annotation of Gnu-Mach/device/ds_routines.c, revision 1.1

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, &notify);
        !           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:                                                 &copy, 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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.