Annotation of OSKit-Mach/oskit/ds_block.c, revision 1.1.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.