Annotation of OSKit-Mach/oskit/ds_block.c, revision 1.1

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

unix.superglobalmegacorp.com

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