Annotation of Gnu-Mach/linux/dev/glue/block.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Linux block driver support.
        !             3:  *
        !             4:  * Copyright (C) 1996 The University of Utah and the Computer Systems
        !             5:  * Laboratory at the University of Utah (CSL)
        !             6:  *
        !             7:  * This program is free software; you can redistribute it and/or modify
        !             8:  * it under the terms of the GNU General Public License as published by
        !             9:  * the Free Software Foundation; either version 2, or (at your option)
        !            10:  * any later version.
        !            11:  *
        !            12:  * This program is distributed in the hope that it will be useful,
        !            13:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            15:  * GNU General Public License for more details.
        !            16:  *
        !            17:  * You should have received a copy of the GNU General Public License
        !            18:  * along with this program; if not, write to the Free Software
        !            19:  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
        !            20:  *
        !            21:  *     Author: Shantanu Goel, University of Utah CSL
        !            22:  */
        !            23: 
        !            24: /*
        !            25:  *  linux/drivers/block/ll_rw_blk.c
        !            26:  *
        !            27:  * Copyright (C) 1991, 1992 Linus Torvalds
        !            28:  * Copyright (C) 1994,      Karl Keyte: Added support for disk statistics
        !            29:  */
        !            30: 
        !            31: /*
        !            32:  *  linux/fs/block_dev.c
        !            33:  *
        !            34:  *  Copyright (C) 1991, 1992  Linus Torvalds
        !            35:  */
        !            36: 
        !            37: /*
        !            38:  *  linux/fs/buffer.c
        !            39:  *
        !            40:  *  Copyright (C) 1991, 1992  Linus Torvalds
        !            41:  */
        !            42: 
        !            43: #include <sys/types.h>
        !            44: #include <machine/spl.h>
        !            45: #include <mach/mach_types.h>
        !            46: #include <mach/kern_return.h>
        !            47: #include <mach/mig_errors.h>
        !            48: #include <mach/port.h>
        !            49: #include <mach/vm_param.h>
        !            50: #include <mach/notify.h>
        !            51: 
        !            52: #include <ipc/ipc_port.h>
        !            53: #include <ipc/ipc_space.h>
        !            54: 
        !            55: #include <vm/vm_map.h>
        !            56: #include <vm/vm_kern.h>
        !            57: #include <vm/vm_page.h>
        !            58: 
        !            59: #include <device/device_types.h>
        !            60: #include <device/device_port.h>
        !            61: #include <device/disk_status.h>
        !            62: #include "device_reply.h"
        !            63: 
        !            64: #include <linux_emul.h>
        !            65: 
        !            66: #define MACH_INCLUDE
        !            67: #include <linux/fs.h>
        !            68: #include <linux/blk.h>
        !            69: #include <linux/string.h>
        !            70: #include <linux/errno.h>
        !            71: #include <linux/fcntl.h>
        !            72: #include <linux/major.h>
        !            73: #include <linux/kdev_t.h>
        !            74: #include <linux/delay.h>
        !            75: #include <linux/malloc.h>
        !            76: #include <linux/hdreg.h>
        !            77: #include <asm/io.h>
        !            78: 
        !            79: extern int linux_auto_config;
        !            80: extern int linux_intr_pri;
        !            81: extern int linux_to_mach_error (int);
        !            82: 
        !            83: /* This task queue is not used in Mach: just for fixing undefined symbols. */
        !            84: DECLARE_TASK_QUEUE (tq_disk);
        !            85: 
        !            86: /* Location of VTOC in units for sectors (512 bytes).  */
        !            87: #define PDLOCATION 29
        !            88: 
        !            89: /* Linux kernel variables.  */
        !            90: 
        !            91: /* Temporary data allocated on the stack.  */
        !            92: struct temp_data
        !            93: {
        !            94:   struct inode inode;
        !            95:   struct file file;
        !            96:   struct request req;
        !            97:   queue_head_t pages;
        !            98: };
        !            99: 
        !           100: /* One of these exists for each
        !           101:    driver associated with a major number.  */
        !           102: struct device_struct
        !           103: {
        !           104:   const char *name;            /* device name */
        !           105:   struct file_operations *fops;        /* operations vector */
        !           106:   int busy:1;                  /* driver is being opened/closed */
        !           107:   int want:1;                  /* someone wants to open/close driver */
        !           108:   struct gendisk *gd;          /* DOS partition information */
        !           109:   int default_slice;           /* what slice to use when none is given */
        !           110:   struct disklabel **labels;   /* disklabels for each DOS partition */
        !           111: };
        !           112: 
        !           113: /* An entry in the Mach name to Linux major number conversion table.  */
        !           114: struct name_map
        !           115: {
        !           116:   const char *name;    /* Mach name for device */
        !           117:   unsigned major;      /* Linux major number */
        !           118:   unsigned unit;       /* Linux unit number */
        !           119:   int read_only;       /* 1 if device is read only */
        !           120: };
        !           121: 
        !           122: /* Driver operation table.  */
        !           123: static struct device_struct blkdevs[MAX_BLKDEV];
        !           124: 
        !           125: /* Driver request function table.  */
        !           126: struct blk_dev_struct blk_dev[MAX_BLKDEV] =
        !           127: {
        !           128:   { NULL, NULL },              /* 0 no_dev */
        !           129:   { NULL, NULL },              /* 1 dev mem */
        !           130:   { NULL, NULL },              /* 2 dev fd */
        !           131:   { NULL, NULL },              /* 3 dev ide0 or hd */
        !           132:   { NULL, NULL },              /* 4 dev ttyx */
        !           133:   { NULL, NULL },              /* 5 dev tty */
        !           134:   { NULL, NULL },              /* 6 dev lp */
        !           135:   { NULL, NULL },              /* 7 dev pipes */
        !           136:   { NULL, NULL },              /* 8 dev sd */
        !           137:   { NULL, NULL },              /* 9 dev st */
        !           138:   { NULL, NULL },              /* 10 */
        !           139:   { NULL, NULL },              /* 11 */
        !           140:   { NULL, NULL },              /* 12 */
        !           141:   { NULL, NULL },              /* 13 */
        !           142:   { NULL, NULL },              /* 14 */
        !           143:   { NULL, NULL },              /* 15 */
        !           144:   { NULL, NULL },              /* 16 */
        !           145:   { NULL, NULL },              /* 17 */
        !           146:   { NULL, NULL },              /* 18 */
        !           147:   { NULL, NULL },              /* 19 */
        !           148:   { NULL, NULL },              /* 20 */
        !           149:   { NULL, NULL },              /* 21 */
        !           150:   { NULL, NULL }               /* 22 dev ide1 */
        !           151: };
        !           152: 
        !           153: /*
        !           154:  * blk_size contains the size of all block-devices in units of 1024 byte
        !           155:  * sectors:
        !           156:  *
        !           157:  * blk_size[MAJOR][MINOR]
        !           158:  *
        !           159:  * if (!blk_size[MAJOR]) then no minor size checking is done.
        !           160:  */
        !           161: int *blk_size[MAX_BLKDEV] = { NULL, NULL, };
        !           162: 
        !           163: /*
        !           164:  * blksize_size contains the size of all block-devices:
        !           165:  *
        !           166:  * blksize_size[MAJOR][MINOR]
        !           167:  *
        !           168:  * if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
        !           169:  */
        !           170: int *blksize_size[MAX_BLKDEV] = { NULL, NULL, };
        !           171: 
        !           172: /*
        !           173:  * hardsect_size contains the size of the hardware sector of a device.
        !           174:  *
        !           175:  * hardsect_size[MAJOR][MINOR]
        !           176:  *
        !           177:  * if (!hardsect_size[MAJOR])
        !           178:  *             then 512 bytes is assumed.
        !           179:  * else
        !           180:  *             sector_size is hardsect_size[MAJOR][MINOR]
        !           181:  * This is currently set by some scsi device and read by the msdos fs driver
        !           182:  * This might be a some uses later.
        !           183:  */
        !           184: int *hardsect_size[MAX_BLKDEV] = { NULL, NULL, };
        !           185: 
        !           186: /* This specifies how many sectors to read ahead on the disk.
        !           187:    This is unused in Mach.  It is here to make drivers compile.  */
        !           188: int read_ahead[MAX_BLKDEV] = {0, };
        !           189: 
        !           190: /* Use to wait on when there are no free requests.
        !           191:    This is unused in Mach.  It is here to make drivers compile.  */
        !           192: struct wait_queue *wait_for_request = NULL;
        !           193: 
        !           194: /* Map for allocating device memory.  */
        !           195: extern vm_map_t device_io_map;
        !           196: 
        !           197: /* Initialize block drivers.  */
        !           198: int
        !           199: blk_dev_init ()
        !           200: {
        !           201: #ifdef CONFIG_BLK_DEV_IDE
        !           202:   ide_init ();
        !           203: #endif
        !           204: #ifdef CONFIG_BLK_DEV_FD
        !           205:   floppy_init ();
        !           206: #else
        !           207:   outb_p (0xc, 0x3f2);
        !           208: #endif
        !           209:   return 0;
        !           210: }
        !           211: 
        !           212: /* Return 1 if major number MAJOR corresponds to a disk device.  */
        !           213: static inline int
        !           214: disk_major (int major)
        !           215: {
        !           216:   return (major == IDE0_MAJOR
        !           217:          || major == IDE1_MAJOR
        !           218:          || major == IDE2_MAJOR
        !           219:          || major == IDE3_MAJOR
        !           220:          || major == SCSI_DISK_MAJOR);
        !           221: }
        !           222: 
        !           223: /* Linux kernel block support routines.  */
        !           224: 
        !           225: /* Register a driver for major number MAJOR,
        !           226:    with name NAME, and operations vector FOPS.  */
        !           227: int
        !           228: register_blkdev (unsigned major, const char *name,
        !           229:                 struct file_operations *fops)
        !           230: {
        !           231:   int err = 0;
        !           232: 
        !           233:   if (major == 0)
        !           234:     {
        !           235:       for (major = MAX_BLKDEV - 1; major > 0; major--)
        !           236:        if (blkdevs[major].fops == NULL)
        !           237:          goto out;
        !           238:       return -LINUX_EBUSY;
        !           239:     }
        !           240:   if (major >= MAX_BLKDEV)
        !           241:     return -LINUX_EINVAL;
        !           242:   if (blkdevs[major].fops && blkdevs[major].fops != fops)
        !           243:     return -LINUX_EBUSY;
        !           244: 
        !           245: out:
        !           246:   blkdevs[major].name = name;
        !           247:   blkdevs[major].fops = fops;
        !           248:   blkdevs[major].busy = 0;
        !           249:   blkdevs[major].want = 0;
        !           250:   blkdevs[major].gd = NULL;
        !           251:   blkdevs[major].default_slice = 0;
        !           252:   blkdevs[major].labels = NULL;
        !           253:   return 0;
        !           254: }
        !           255: 
        !           256: /* Unregister the driver associated with
        !           257:    major number MAJOR and having the name NAME.  */
        !           258: int
        !           259: unregister_blkdev (unsigned major, const char *name)
        !           260: {
        !           261:   int err;
        !           262: 
        !           263:   if (major >= MAX_BLKDEV)
        !           264:     return -LINUX_EINVAL;
        !           265:   if (! blkdevs[major].fops || strcmp (blkdevs[major].name, name))
        !           266:     return -LINUX_EINVAL;
        !           267:   blkdevs[major].fops = NULL;
        !           268:   if (blkdevs[major].labels)
        !           269:     {
        !           270:       assert (blkdevs[major].gd);
        !           271:       kfree ((vm_offset_t) blkdevs[major].labels,
        !           272:             (sizeof (struct disklabel *)
        !           273:              * blkdevs[major].gd->max_p * blkdevs[major].gd->max_nr));
        !           274:     }
        !           275:   return 0;
        !           276: }
        !           277: 
        !           278: void
        !           279: set_blocksize (kdev_t dev, int size)
        !           280: {
        !           281:   extern int *blksize_size[];
        !           282: 
        !           283:   if (! blksize_size[MAJOR (dev)])
        !           284:     return;
        !           285: 
        !           286:   switch (size)
        !           287:     {
        !           288:     case 512:
        !           289:     case 1024:
        !           290:     case 2048:
        !           291:     case 4096:
        !           292:       break;
        !           293:     default:
        !           294:       panic ("Invalid blocksize passed to set_blocksize");
        !           295:       break;
        !           296:     }
        !           297:   blksize_size[MAJOR (dev)][MINOR (dev)] = size;
        !           298: }
        !           299: 
        !           300: /* Allocate a buffer SIZE bytes long.  */
        !           301: static void *
        !           302: alloc_buffer (int size)
        !           303: {
        !           304:   vm_page_t m;
        !           305:   struct temp_data *d;
        !           306: 
        !           307:   assert (size <= PAGE_SIZE);
        !           308: 
        !           309:   if (! linux_auto_config)
        !           310:     {
        !           311:       while ((m = vm_page_grab ()) == 0)
        !           312:        VM_PAGE_WAIT (0);
        !           313:       d = current_thread ()->pcb->data;
        !           314:       assert (d);
        !           315:       queue_enter (&d->pages, m, vm_page_t, pageq);
        !           316:       return (void *) m->phys_addr;
        !           317:     }
        !           318:   return (void *) __get_free_pages (GFP_KERNEL, 0, ~0UL);
        !           319: }
        !           320: 
        !           321: /* Free buffer P which is SIZE bytes long.  */
        !           322: static void
        !           323: free_buffer (void *p, int size)
        !           324: {
        !           325:   int i;
        !           326:   struct temp_data *d;
        !           327:   vm_page_t m;
        !           328: 
        !           329:   assert (size <= PAGE_SIZE);
        !           330: 
        !           331:   if (! linux_auto_config)
        !           332:     {
        !           333:       d = current_thread ()->pcb->data;
        !           334:       assert (d);
        !           335:       queue_iterate (&d->pages, m, vm_page_t, pageq)
        !           336:        {      
        !           337:          if (m->phys_addr == (vm_offset_t) p)
        !           338:            {
        !           339:              queue_remove (&d->pages, m, vm_page_t, pageq);
        !           340:              vm_page_lock_queues ();
        !           341:              vm_page_free (m);
        !           342:              vm_page_lock_queues ();
        !           343:              return;
        !           344:            }
        !           345:        }
        !           346:       panic ("free_buffer");
        !           347:     }
        !           348:   free_pages ((unsigned long) p, 0);
        !           349: }
        !           350: 
        !           351: /* Allocate a buffer of SIZE bytes and
        !           352:    associate it with block number BLOCK of device DEV.  */
        !           353: struct buffer_head *
        !           354: getblk (kdev_t dev, int block, int size)
        !           355: {
        !           356:   struct buffer_head *bh;
        !           357:   static struct buffer_head bhead;
        !           358: 
        !           359:   assert (size <= PAGE_SIZE);
        !           360: 
        !           361:   if (! linux_auto_config)
        !           362:     bh = (struct buffer_head *) kalloc (sizeof (struct buffer_head));
        !           363:   else
        !           364:     bh = &bhead;
        !           365:   if (bh)
        !           366:     {
        !           367:       memset (bh, 0, sizeof (struct buffer_head));
        !           368:       bh->b_data = alloc_buffer (size);
        !           369:       if (! bh->b_data)
        !           370:        {
        !           371:          if (! linux_auto_config)
        !           372:            kfree ((vm_offset_t) bh, sizeof (struct buffer_head));
        !           373:          return NULL;
        !           374:        }
        !           375:       bh->b_dev = dev;
        !           376:       bh->b_size = size;
        !           377:       bh->b_state = 1 << BH_Lock;
        !           378:       bh->b_blocknr = block;
        !           379:     }
        !           380:   return bh;
        !           381: }
        !           382: 
        !           383: /* Release buffer BH previously allocated by getblk.  */
        !           384: void
        !           385: __brelse (struct buffer_head *bh)
        !           386: {
        !           387:   free_buffer (bh->b_data, bh->b_size);
        !           388:   if (! linux_auto_config)
        !           389:     kfree ((vm_offset_t) bh, sizeof (*bh));
        !           390: }
        !           391: 
        !           392: /* Allocate a buffer of SIZE bytes and fill it with data
        !           393:    from device DEV starting at block number BLOCK.  */
        !           394: struct buffer_head *
        !           395: bread (kdev_t dev, int block, int size)
        !           396: {
        !           397:   int err;
        !           398:   struct buffer_head *bh;
        !           399: 
        !           400:   bh = getblk (dev, block, size);
        !           401:   if (bh)
        !           402:     {
        !           403:       ll_rw_block (READ, 1, &bh);
        !           404:       wait_on_buffer (bh);
        !           405:       if (! buffer_uptodate (bh))
        !           406:        {
        !           407:          __brelse (bh);
        !           408:          return NULL;
        !           409:        }
        !           410:     }
        !           411:   return bh;
        !           412: }
        !           413: 
        !           414: /* Return the block size for device DEV in *BSIZE and
        !           415:    log2(block size) in *BSHIFT.  */
        !           416: static void
        !           417: get_block_size (kdev_t dev, int *bsize, int *bshift)
        !           418: {
        !           419:   int i;
        !           420: 
        !           421:   *bsize = BLOCK_SIZE;
        !           422:   if (blksize_size[MAJOR (dev)]
        !           423:       && blksize_size[MAJOR (dev)][MINOR (dev)])
        !           424:     *bsize = blksize_size[MAJOR (dev)][MINOR (dev)];
        !           425:   for (i = *bsize, *bshift = 0; i != 1; i >>= 1, (*bshift)++)
        !           426:     ;
        !           427: }
        !           428: 
        !           429: /* Enqueue request REQ on a driver's queue.  */
        !           430: static inline void
        !           431: enqueue_request (struct request *req)
        !           432: {
        !           433:   struct request *tmp;
        !           434:   struct blk_dev_struct *dev;
        !           435: 
        !           436:   dev = blk_dev + MAJOR (req->rq_dev);
        !           437:   cli ();
        !           438:   tmp = dev->current_request;
        !           439:   if (! tmp)
        !           440:     {
        !           441:       dev->current_request = req;
        !           442:       (*dev->request_fn) ();
        !           443:       sti ();
        !           444:       return;
        !           445:     }
        !           446:   while (tmp->next)
        !           447:     {
        !           448:       if ((IN_ORDER (tmp, req) || ! IN_ORDER (tmp, tmp->next))
        !           449:          && IN_ORDER (req, tmp->next))
        !           450:        break;
        !           451:       tmp = tmp->next;
        !           452:     }
        !           453:   req->next = tmp->next;
        !           454:   tmp->next = req;
        !           455:   if (scsi_blk_major (MAJOR (req->rq_dev)))
        !           456:     (*dev->request_fn) ();
        !           457:   sti ();
        !           458: }
        !           459: 
        !           460: /* Perform the I/O operation RW on the buffer list BH
        !           461:    containing NR buffers.  */
        !           462: void
        !           463: ll_rw_block (int rw, int nr, struct buffer_head **bh)
        !           464: {
        !           465:   int i, bshift, bsize;
        !           466:   unsigned major;
        !           467:   struct request *r;
        !           468:   static struct request req;
        !           469: 
        !           470:   major = MAJOR (bh[0]->b_dev);
        !           471:   assert (major < MAX_BLKDEV);
        !           472: 
        !           473:   get_block_size (bh[0]->b_dev, &bsize, &bshift);
        !           474: 
        !           475:   if (! linux_auto_config)
        !           476:     {
        !           477:       assert (current_thread ()->pcb->data);
        !           478:       r = &((struct temp_data *) current_thread ()->pcb->data)->req;
        !           479:     }
        !           480:   else
        !           481:     r = &req;
        !           482: 
        !           483:   for (i = 0, r->nr_sectors = 0; i < nr - 1; i++)
        !           484:     {
        !           485:       r->nr_sectors += bh[i]->b_size >> 9;
        !           486:       bh[i]->b_reqnext = bh[i + 1];
        !           487:     }
        !           488:   r->nr_sectors += bh[i]->b_size >> 9;
        !           489:   bh[i]->b_reqnext = NULL;
        !           490: 
        !           491:   r->rq_status = RQ_ACTIVE;
        !           492:   r->rq_dev = bh[0]->b_dev;
        !           493:   r->cmd = rw;
        !           494:   r->errors = 0;
        !           495:   r->sector = bh[0]->b_blocknr << (bshift - 9);
        !           496:   r->current_nr_sectors = bh[0]->b_size >> 9;
        !           497:   r->buffer = bh[0]->b_data;
        !           498:   r->bh = bh[0];
        !           499:   r->bhtail = bh[nr - 1];
        !           500:   r->sem = NULL;
        !           501:   r->next = NULL;
        !           502: 
        !           503:   enqueue_request (r);
        !           504: }
        !           505: 
        !           506: #define BSIZE  (1 << bshift)
        !           507: #define BMASK  (BSIZE - 1)
        !           508: 
        !           509: /* Perform read/write operation RW on device DEV
        !           510:    starting at *off to/from buffer *BUF of size *RESID.
        !           511:    The device block size is given by BSHIFT.  *OFF and
        !           512:    *RESID may be non-multiples of the block size.
        !           513:    *OFF, *BUF and *RESID are updated if the operation
        !           514:    completed successfully.  */
        !           515: static int
        !           516: rdwr_partial (int rw, kdev_t dev, loff_t *off,
        !           517:              char **buf, int *resid, int bshift)
        !           518: {
        !           519:   int c, err = 0, o;
        !           520:   long sect, nsect;
        !           521:   struct buffer_head bhead, *bh = &bhead;
        !           522:   struct gendisk *gd;
        !           523: 
        !           524:   memset (bh, 0, sizeof (struct buffer_head));
        !           525:   bh->b_state = 1 << BH_Lock;
        !           526:   bh->b_dev = dev;
        !           527:   bh->b_blocknr = *off >> bshift;
        !           528:   bh->b_size = BSIZE;
        !           529: 
        !           530:   /* Check if this device has non even number of blocks.  */
        !           531:   for (gd = gendisk_head, nsect = -1; gd; gd = gd->next)
        !           532:     if (gd->major == MAJOR (dev))
        !           533:       {
        !           534:        nsect = gd->part[MINOR (dev)].nr_sects;
        !           535:        break;
        !           536:       }
        !           537:   if (nsect > 0)
        !           538:     {
        !           539:       sect = bh->b_blocknr << (bshift - 9);
        !           540:       assert ((nsect - sect) > 0);
        !           541:       if (nsect - sect < (BSIZE >> 9))
        !           542:        bh->b_size = (nsect - sect) << 9;
        !           543:     }
        !           544:   bh->b_data = alloc_buffer (bh->b_size);
        !           545:   if (! bh->b_data)
        !           546:     return -LINUX_ENOMEM;
        !           547:   ll_rw_block (READ, 1, &bh);
        !           548:   wait_on_buffer (bh);
        !           549:   if (buffer_uptodate (bh))
        !           550:     {
        !           551:       o = *off & BMASK;
        !           552:       c = bh->b_size - o;
        !           553:       assert (*resid <= c);
        !           554:       if (c > *resid)
        !           555:        c = *resid;
        !           556:       if (rw == READ)
        !           557:        memcpy (*buf, bh->b_data + o, c);
        !           558:       else
        !           559:        {
        !           560:          memcpy (bh->b_data + o, *buf, c);
        !           561:          bh->b_state = (1 << BH_Dirty) | (1 << BH_Lock);
        !           562:          ll_rw_block (WRITE, 1, &bh);
        !           563:          wait_on_buffer (bh);
        !           564:          if (! buffer_uptodate (bh))
        !           565:            {
        !           566:              err = -LINUX_EIO;
        !           567:              goto out;
        !           568:            }
        !           569:        }
        !           570:       *buf += c;
        !           571:       *resid -= c;
        !           572:       *off += c;
        !           573:     }
        !           574:   else
        !           575:     err = -LINUX_EIO;
        !           576: out:
        !           577:   free_buffer (bh->b_data, bh->b_size);
        !           578:   return err;
        !           579: }
        !           580: 
        !           581: #define BH_Bounce      16
        !           582: #define MAX_BUF                VM_MAP_COPY_PAGE_LIST_MAX
        !           583: 
        !           584: /* Perform read/write operation RW on device DEV
        !           585:    starting at *off to/from buffer *BUF of size *RESID.
        !           586:    The device block size is given by BSHIFT.  *OFF and
        !           587:    *RESID must be multiples of the block size.
        !           588:    *OFF, *BUF and *RESID are updated if the operation
        !           589:    completed successfully.  */
        !           590: static int
        !           591: rdwr_full (int rw, kdev_t dev, loff_t *off, char **buf, int *resid, int bshift)
        !           592: {
        !           593:   int cc, err = 0, i, j, nb, nbuf;
        !           594:   long blk;
        !           595:   struct buffer_head bhead[MAX_BUF], *bh, *bhp[MAX_BUF];
        !           596: 
        !           597:   assert ((*off & BMASK) == 0);
        !           598:   assert (*resid >= bsize);
        !           599: 
        !           600:   nbuf = *resid >> bshift;
        !           601:   blk = *off >> bshift;
        !           602:   for (i = nb = 0, bh = bhead; nb < nbuf; bh++)
        !           603:     {
        !           604:       memset (bh, 0, sizeof (*bh));
        !           605:       bh->b_dev = dev;
        !           606:       bh->b_blocknr = blk;
        !           607:       set_bit (BH_Lock, &bh->b_state);
        !           608:       if (rw == WRITE)
        !           609:        set_bit (BH_Dirty, &bh->b_state);
        !           610:       cc = PAGE_SIZE - (((int) *buf) & PAGE_MASK);
        !           611:       if (cc >= BSIZE && ((int) *buf & 511) == 0)
        !           612:        cc &= ~BMASK;
        !           613:       else
        !           614:        {
        !           615:          cc = PAGE_SIZE;
        !           616:          set_bit (BH_Bounce, &bh->b_state);
        !           617:        }
        !           618:       if (cc > ((nbuf - nb) << bshift))
        !           619:        cc = (nbuf - nb) << bshift;
        !           620:       if (! test_bit (BH_Bounce, &bh->b_state))
        !           621:        bh->b_data = (char *) pmap_extract (vm_map_pmap (device_io_map),
        !           622:                                            (((vm_offset_t) *buf)
        !           623:                                             + (nb << bshift)));
        !           624:       else
        !           625:        {
        !           626:          bh->b_data = alloc_buffer (cc);
        !           627:          if (! bh->b_data)
        !           628:            {
        !           629:              err = -LINUX_ENOMEM;
        !           630:              break;
        !           631:            }
        !           632:          if (rw == WRITE)
        !           633:            memcpy (bh->b_data, *buf + (nb << bshift), cc);
        !           634:        }
        !           635:       bh->b_size = cc;
        !           636:       bhp[i] = bh;
        !           637:       nb += cc >> bshift;
        !           638:       blk += nb;
        !           639:       if (++i == MAX_BUF)
        !           640:        break;
        !           641:     }
        !           642:   if (! err)
        !           643:     {
        !           644:       ll_rw_block (rw, i, bhp);
        !           645:       wait_on_buffer (bhp[i - 1]);
        !           646:     }
        !           647:   for (bh = bhead, cc = 0, j = 0; j < i; cc += bh->b_size, bh++, j++)
        !           648:     {
        !           649:       if (! err && buffer_uptodate (bh)
        !           650:          && rw == READ && test_bit (BH_Bounce, &bh->b_state))
        !           651:        memcpy (*buf + cc, bh->b_data, bh->b_size);
        !           652:       else if (! err && ! buffer_uptodate (bh))
        !           653:          err = -LINUX_EIO;
        !           654:       if (test_bit (BH_Bounce, &bh->b_state))
        !           655:        free_buffer (bh->b_data, bh->b_size);
        !           656:     }
        !           657:   if (! err)
        !           658:     {
        !           659:       *buf += cc;
        !           660:       *resid -= cc;
        !           661:       *off += cc;
        !           662:     }
        !           663:   return err;
        !           664: }
        !           665: 
        !           666: /* Perform read/write operation RW on device DEV
        !           667:    starting at *off to/from buffer BUF of size COUNT.
        !           668:    *OFF is updated if the operation completed successfully.  */
        !           669: static int
        !           670: do_rdwr (int rw, kdev_t dev, loff_t *off, char *buf, int count)
        !           671: {
        !           672:   int bsize, bshift, err = 0, resid = count;
        !           673: 
        !           674:   get_block_size (dev, &bsize, &bshift);
        !           675:   if (*off & BMASK)
        !           676:     err = rdwr_partial (rw, dev, off, &buf, &resid, bshift);
        !           677:   while (resid >= bsize && ! err)
        !           678:     err = rdwr_full (rw, dev, off, &buf, &resid, bshift);
        !           679:   if (! err && resid)
        !           680:     err = rdwr_partial (rw, dev, off, &buf, &resid, bshift);
        !           681:   return err ? err : count - resid;
        !           682: }
        !           683: 
        !           684: int
        !           685: block_write (struct inode *inode, struct file *filp,
        !           686:             const char *buf, int count)
        !           687: {
        !           688:   return do_rdwr (WRITE, inode->i_rdev, &filp->f_pos, (char *) buf, count);
        !           689: }
        !           690: 
        !           691: int
        !           692: block_read (struct inode *inode, struct file *filp, char *buf, int count)
        !           693: {
        !           694:   return do_rdwr (READ, inode->i_rdev, &filp->f_pos, buf, count);
        !           695: }
        !           696: 
        !           697: /*
        !           698:  * This routine checks whether a removable media has been changed,
        !           699:  * and invalidates all buffer-cache-entries in that case. This
        !           700:  * is a relatively slow routine, so we have to try to minimize using
        !           701:  * it. Thus it is called only upon a 'mount' or 'open'. This
        !           702:  * is the best way of combining speed and utility, I think.
        !           703:  * People changing diskettes in the middle of an operation deserve
        !           704:  * to loose :-)
        !           705:  */
        !           706: int
        !           707: check_disk_change (kdev_t dev)
        !           708: {
        !           709:   unsigned i;
        !           710:   struct file_operations * fops;
        !           711: 
        !           712:   i = MAJOR(dev);
        !           713:   if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
        !           714:     return 0;
        !           715:   if (fops->check_media_change == NULL)
        !           716:     return 0;
        !           717:   if (! (*fops->check_media_change) (dev))
        !           718:     return 0;
        !           719: 
        !           720:   /*  printf ("Disk change detected on device %s\n", kdevname(dev));*/
        !           721: 
        !           722:   if (fops->revalidate)
        !           723:     (*fops->revalidate) (dev);
        !           724: 
        !           725:   return 1;
        !           726: }
        !           727: 
        !           728: /* Mach device interface routines.  */
        !           729: 
        !           730: /* Mach name to Linux major/minor number mapping table.  */
        !           731: static struct name_map name_to_major[] =
        !           732: {
        !           733:   /* IDE disks */
        !           734:   { "hd0", IDE0_MAJOR, 0, 0 },
        !           735:   { "hd1", IDE0_MAJOR, 1, 0 },
        !           736:   { "hd2", IDE1_MAJOR, 0, 0 },
        !           737:   { "hd3", IDE1_MAJOR, 1, 0 },
        !           738:   { "hd4", IDE2_MAJOR, 0, 0 },
        !           739:   { "hd5", IDE2_MAJOR, 1, 0 },
        !           740:   { "hd6", IDE3_MAJOR, 0, 0 },
        !           741:   { "hd7", IDE3_MAJOR, 1, 0 },
        !           742: 
        !           743:   /* IDE CDROMs */
        !           744:   { "wcd0", IDE0_MAJOR, 0, 1 },
        !           745:   { "wcd1", IDE0_MAJOR, 1, 1 },
        !           746:   { "wcd2", IDE1_MAJOR, 0, 1 },
        !           747:   { "wcd3", IDE1_MAJOR, 1, 1 },
        !           748:   { "wcd4", IDE2_MAJOR, 0, 1 },
        !           749:   { "wcd5", IDE2_MAJOR, 1, 1 },
        !           750:   { "wcd6", IDE3_MAJOR, 0, 1 },
        !           751:   { "wcd7", IDE3_MAJOR, 1, 1 },
        !           752: 
        !           753:   /* SCSI disks */
        !           754:   { "sd0", SCSI_DISK_MAJOR, 0, 0 },
        !           755:   { "sd1", SCSI_DISK_MAJOR, 1, 0 },
        !           756:   { "sd2", SCSI_DISK_MAJOR, 2, 0 },
        !           757:   { "sd3", SCSI_DISK_MAJOR, 3, 0 },
        !           758:   { "sd4", SCSI_DISK_MAJOR, 4, 0 },
        !           759:   { "sd5", SCSI_DISK_MAJOR, 5, 0 },
        !           760:   { "sd6", SCSI_DISK_MAJOR, 6, 0 },
        !           761:   { "sd7", SCSI_DISK_MAJOR, 7, 0 },
        !           762: 
        !           763:   /* SCSI CDROMs */
        !           764:   { "cd0", SCSI_CDROM_MAJOR, 0, 1 },
        !           765:   { "cd1", SCSI_CDROM_MAJOR, 1, 1 },
        !           766: 
        !           767:   /* Floppy disks */
        !           768:   { "fd0", FLOPPY_MAJOR, 0, 0 },
        !           769:   { "fd1", FLOPPY_MAJOR, 1, 0 },
        !           770: };
        !           771: 
        !           772: #define NUM_NAMES (sizeof (name_to_major) / sizeof (name_to_major[0]))
        !           773: 
        !           774: /* One of these is associated with each open instance of a device.  */
        !           775: struct block_data
        !           776: {
        !           777:   const char *name;            /* Mach name for device */
        !           778:   int want:1;                  /* someone is waiting for I/O to complete */
        !           779:   int open_count;              /* number of opens */
        !           780:   int iocount;                 /* number of pending I/O operations */
        !           781:   int part;                    /* BSD partition number (-1 if none) */
        !           782:   int flags;                   /* Linux file flags */
        !           783:   int mode;                    /* Linux file mode */
        !           784:   kdev_t dev;                  /* Linux device number */
        !           785:   ipc_port_t port;             /* port representing device */
        !           786:   struct device_struct *ds;    /* driver operation table entry */
        !           787:   struct device device;                /* generic device header */
        !           788:   struct name_map *np;         /* name to inode map */
        !           789:   struct block_data *next;     /* forward link */
        !           790: };
        !           791: 
        !           792: /* List of open devices.  */
        !           793: static struct block_data *open_list;
        !           794: 
        !           795: /* Forward declarations.  */
        !           796: 
        !           797: extern struct device_emulation_ops linux_block_emulation_ops;
        !           798: 
        !           799: static io_return_t device_close (void *);
        !           800: 
        !           801: /* Return a send right for block device BD.  */
        !           802: static ipc_port_t
        !           803: dev_to_port (void *bd)
        !           804: {
        !           805:   return (bd
        !           806:          ? ipc_port_make_send (((struct block_data *) bd)->port)
        !           807:          : IP_NULL);
        !           808: }
        !           809: 
        !           810: /* Return 1 if C is a letter of the alphabet.  */
        !           811: static inline int
        !           812: isalpha (int c)
        !           813: {
        !           814:   return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
        !           815: }
        !           816: 
        !           817: /* Return 1 if C is a digit.  */
        !           818: static inline int
        !           819: isdigit (int c)
        !           820: {
        !           821:   return c >= '0' && c <= '9';
        !           822: }
        !           823: 
        !           824: /* Find the name map entry for device NAME.
        !           825:    Set *SLICE to be the DOS partition and
        !           826:    *PART the BSD/Mach partition, if any.  */
        !           827: static struct name_map *
        !           828: find_name (char *name, int *slice, int *part)
        !           829: {
        !           830:   char *p, *q;
        !           831:   int i, len;
        !           832:   struct name_map *np;
        !           833: 
        !           834:   /* Parse name into name, unit, DOS partition (slice) and partition.  */
        !           835:   for (*slice = 0, *part = -1, p = name; isalpha (*p); p++)
        !           836:     ;
        !           837:   if (p == name || ! isdigit (*p))
        !           838:     return NULL;
        !           839:   do
        !           840:     p++;
        !           841:   while (isdigit (*p));
        !           842:   if (*p)
        !           843:     {
        !           844:       q = p;
        !           845:       if (*q == 's' && isdigit (*(q + 1)))
        !           846:        {
        !           847:          q++;
        !           848:          do
        !           849:            *slice = *slice * 10 + *q++ - '0';
        !           850:          while (isdigit (*q));
        !           851:          if (! *q)
        !           852:            goto find_major;
        !           853:        }
        !           854:       if (! isalpha (*q) || *(q + 1))
        !           855:        return NULL;
        !           856:       *part = *q - 'a';
        !           857:     }
        !           858: 
        !           859: find_major:
        !           860:   /* Convert name to major number.  */
        !           861:   for (i = 0, np = name_to_major; i < NUM_NAMES; i++, np++)
        !           862:     {
        !           863:       len = strlen (np->name);
        !           864:       if (len == (p - name) && ! strncmp (np->name, name, len))
        !           865:        return np;
        !           866:     }
        !           867:   return NULL;
        !           868: }
        !           869: 
        !           870: /* Attempt to read a BSD disklabel from device DEV.  */
        !           871: static struct disklabel *
        !           872: read_bsd_label (kdev_t dev)
        !           873: {
        !           874:   int bsize, bshift;
        !           875:   struct buffer_head *bh;
        !           876:   struct disklabel *dlp, *lp = NULL;
        !           877: 
        !           878:   get_block_size (dev, &bsize, &bshift);
        !           879:   bh = bread (dev, LBLLOC >> (bshift - 9), bsize);
        !           880:   if (bh)
        !           881:     {
        !           882:       dlp = (struct disklabel *) (bh->b_data + ((LBLLOC << 9) & (bsize - 1)));
        !           883:       if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC)
        !           884:        {
        !           885:          lp = (struct disklabel *) kalloc (sizeof (*lp));
        !           886:          assert (lp);
        !           887:          memcpy (lp, dlp, sizeof (*lp));
        !           888:        }
        !           889:       __brelse (bh);
        !           890:     }
        !           891:   return lp;
        !           892: }
        !           893: 
        !           894: /* Attempt to read a VTOC from device DEV.  */
        !           895: static struct disklabel *
        !           896: read_vtoc (kdev_t dev)
        !           897: {
        !           898:   int bshift, bsize, i;
        !           899:   struct buffer_head *bh;
        !           900:   struct evtoc *evp;
        !           901:   struct disklabel *lp = NULL;
        !           902: 
        !           903:   get_block_size (dev, &bsize, &bshift);
        !           904:   bh = bread (dev, PDLOCATION >> (bshift - 9), bsize);
        !           905:   if (bh)
        !           906:     {
        !           907:       evp = (struct evtoc *) (bh->b_data + ((PDLOCATION << 9) & (bsize - 1)));
        !           908:       if (evp->sanity == VTOC_SANE)
        !           909:        {
        !           910:          lp = (struct disklabel *) kalloc (sizeof (*lp));
        !           911:          assert (lp);
        !           912:          lp->d_npartitions = evp->nparts;
        !           913:          if (lp->d_npartitions > MAXPARTITIONS)
        !           914:            lp->d_npartitions = MAXPARTITIONS;
        !           915:          for (i = 0; i < lp->d_npartitions; i++)
        !           916:            {
        !           917:              lp->d_partitions[i].p_size = evp->part[i].p_size;
        !           918:              lp->d_partitions[i].p_offset = evp->part[i].p_start;
        !           919:              lp->d_partitions[i].p_fstype = FS_BSDFFS;
        !           920:            }
        !           921:        }
        !           922:       __brelse (bh);
        !           923:     }
        !           924:   return lp;
        !           925: }
        !           926: 
        !           927: /* Initialize BSD/Mach partition table for device
        !           928:    specified by NP, DS and *DEV.  Check SLICE and *PART for validity.  */
        !           929: static kern_return_t
        !           930: init_partition (struct name_map *np, kdev_t *dev,
        !           931:                struct device_struct *ds, int slice, int *part)
        !           932: {
        !           933:   int err, i, j;
        !           934:   struct disklabel *lp;
        !           935:   struct gendisk *gd = ds->gd;
        !           936:   struct partition *p;
        !           937:   struct temp_data *d = current_thread ()->pcb->data;
        !           938: 
        !           939:   if (! gd)
        !           940:     {
        !           941:       *part = -1;
        !           942:       return 0;
        !           943:     }
        !           944:   if (ds->labels)
        !           945:     goto check;
        !           946:   ds->labels = (struct disklabel **) kalloc (sizeof (struct disklabel *)
        !           947:                                             * gd->max_nr * gd->max_p);
        !           948:   if (! ds->labels)
        !           949:     return D_NO_MEMORY;
        !           950:   memset ((void *) ds->labels, 0,
        !           951:          sizeof (struct disklabel *) * gd->max_nr * gd->max_p);
        !           952:   for (i = 1; i < gd->max_p; i++)
        !           953:     {
        !           954:       d->inode.i_rdev = *dev | i;
        !           955:       if (gd->part[MINOR (d->inode.i_rdev)].nr_sects <= 0
        !           956:          || gd->part[MINOR (d->inode.i_rdev)].start_sect < 0)
        !           957:        continue;
        !           958:       linux_intr_pri = SPL5;
        !           959:       d->file.f_flags = 0;
        !           960:       d->file.f_mode = O_RDONLY;
        !           961:       if (ds->fops->open && (*ds->fops->open) (&d->inode, &d->file))
        !           962:        continue;
        !           963:       lp = read_bsd_label (d->inode.i_rdev);
        !           964:       if (! lp)
        !           965:        lp = read_vtoc (d->inode.i_rdev);
        !           966:       if (ds->fops->release)
        !           967:        (*ds->fops->release) (&d->inode, &d->file);
        !           968:       if (lp)
        !           969:        {
        !           970:          if (ds->default_slice == 0)
        !           971:            ds->default_slice = i;
        !           972:          for (j = 0, p = lp->d_partitions; j < lp->d_npartitions; j++, p++)
        !           973:            {
        !           974:              if (p->p_offset < 0 || p->p_size <= 0)
        !           975:                continue;
        !           976: 
        !           977:              /* Sanity check.  */
        !           978:              if (p->p_size > gd->part[MINOR (d->inode.i_rdev)].nr_sects)
        !           979:                p->p_size = gd->part[MINOR (d->inode.i_rdev)].nr_sects;
        !           980:            }
        !           981:        }
        !           982:       ds->labels[MINOR (d->inode.i_rdev)] = lp;
        !           983:     }
        !           984: 
        !           985: check:
        !           986:   if (*part >= 0 && slice == 0)
        !           987:     slice = ds->default_slice;
        !           988:   if (*part >= 0 && slice == 0)
        !           989:     return D_NO_SUCH_DEVICE;
        !           990:   *dev = MKDEV (MAJOR (*dev), MINOR (*dev) | slice);
        !           991:   if (slice >= gd->max_p
        !           992:       || gd->part[MINOR (*dev)].start_sect < 0
        !           993:       || gd->part[MINOR (*dev)].nr_sects <= 0)
        !           994:     return D_NO_SUCH_DEVICE;
        !           995:   if (*part >= 0)
        !           996:     {
        !           997:       lp = ds->labels[MINOR (*dev)];
        !           998:       if (! lp
        !           999:          || *part >= lp->d_npartitions
        !          1000:          || lp->d_partitions[*part].p_offset < 0
        !          1001:          || lp->d_partitions[*part].p_size <= 0)
        !          1002:        return D_NO_SUCH_DEVICE;
        !          1003:     }
        !          1004:   return 0;
        !          1005: }
        !          1006: 
        !          1007: #define DECL_DATA      struct temp_data td
        !          1008: #define INIT_DATA()                    \
        !          1009: {                                      \
        !          1010:   queue_init (&td.pages);              \
        !          1011:   td.inode.i_rdev = bd->dev;           \
        !          1012:   td.file.f_mode = bd->mode;           \
        !          1013:   td.file.f_flags = bd->flags;         \
        !          1014:   current_thread ()->pcb->data = &td;  \
        !          1015: }
        !          1016: 
        !          1017: static io_return_t
        !          1018: device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
        !          1019:             dev_mode_t mode, char *name, device_t *devp)
        !          1020: {
        !          1021:   int part, slice, err;
        !          1022:   unsigned major, minor;
        !          1023:   kdev_t dev;
        !          1024:   ipc_port_t notify;
        !          1025:   struct block_data *bd = NULL, *bdp;
        !          1026:   struct device_struct *ds;
        !          1027:   struct gendisk *gd;
        !          1028:   struct name_map *np;
        !          1029:   DECL_DATA;
        !          1030: 
        !          1031:   np = find_name (name, &slice, &part);
        !          1032:   if (! np)
        !          1033:     return D_NO_SUCH_DEVICE;
        !          1034:   major = np->major;
        !          1035:   ds = &blkdevs[major];
        !          1036: 
        !          1037:   /* Check that driver exists.  */
        !          1038:   if (! ds->fops)
        !          1039:     return D_NO_SUCH_DEVICE;
        !          1040: 
        !          1041:   /* Wait for any other open/close calls to finish.  */
        !          1042:   ds = &blkdevs[major];
        !          1043:   while (ds->busy)
        !          1044:     {
        !          1045:       ds->want = 1;
        !          1046:       assert_wait ((event_t) ds, FALSE);
        !          1047:       schedule ();
        !          1048:     }
        !          1049:   ds->busy = 1;
        !          1050: 
        !          1051:   /* Compute minor number.  */
        !          1052:   if (! ds->gd)
        !          1053:     {
        !          1054:       for (gd = gendisk_head; gd && gd->major != major; gd = gd->next)
        !          1055:        ;
        !          1056:       ds->gd = gd;
        !          1057:     }
        !          1058:   minor = np->unit;
        !          1059:   gd = ds->gd;
        !          1060:   if (gd)
        !          1061:     minor <<= gd->minor_shift;
        !          1062:   dev = MKDEV (major, minor);
        !          1063: 
        !          1064:   queue_init (&td.pages);
        !          1065:   current_thread ()->pcb->data = &td;
        !          1066: 
        !          1067:   /* Check partition.  */
        !          1068:   err = init_partition (np, &dev, ds, slice, &part);
        !          1069:   if (err)
        !          1070:     goto out;
        !          1071: 
        !          1072:   /* Initialize file structure.  */
        !          1073:   switch (mode & (D_READ|D_WRITE))
        !          1074:     {
        !          1075:     case D_WRITE:
        !          1076:       td.file.f_mode = O_WRONLY;
        !          1077:       break;
        !          1078: 
        !          1079:     case D_READ|D_WRITE:
        !          1080:       td.file.f_mode = O_RDWR;
        !          1081:       break;
        !          1082: 
        !          1083:     default:
        !          1084:       td.file.f_mode = O_RDONLY;
        !          1085:       break;
        !          1086:     }
        !          1087:   td.file.f_flags = (mode & D_NODELAY) ? O_NDELAY : 0;
        !          1088: 
        !          1089:   /* Check if the device is currently open.  */
        !          1090:   for (bdp = open_list; bdp; bdp = bdp->next)
        !          1091:     if (bdp->dev == dev
        !          1092:        && bdp->part == part
        !          1093:        && bdp->mode == td.file.f_mode
        !          1094:        && bdp->flags == td.file.f_flags)
        !          1095:       {
        !          1096:        bd = bdp;
        !          1097:        goto out;
        !          1098:       }
        !          1099: 
        !          1100:   /* Open the device.  */
        !          1101:   if (ds->fops->open)
        !          1102:     {
        !          1103:       td.inode.i_rdev = dev;
        !          1104:       linux_intr_pri = SPL5;
        !          1105:       err = (*ds->fops->open) (&td.inode, &td.file);
        !          1106:       if (err)
        !          1107:        {
        !          1108:          err = linux_to_mach_error (err);
        !          1109:          goto out;
        !          1110:        }
        !          1111:     }
        !          1112: 
        !          1113:   /* Allocate and initialize device data.  */
        !          1114:   bd = (struct block_data *) kalloc (sizeof (struct block_data));
        !          1115:   if (! bd)
        !          1116:     {
        !          1117:       err = D_NO_MEMORY;
        !          1118:       goto bad;
        !          1119:     }
        !          1120:   bd->want = 0;
        !          1121:   bd->open_count = 0;
        !          1122:   bd->iocount = 0;
        !          1123:   bd->part = part;
        !          1124:   bd->ds = ds;
        !          1125:   bd->device.emul_data = bd;
        !          1126:   bd->device.emul_ops = &linux_block_emulation_ops;
        !          1127:   bd->dev = dev;
        !          1128:   bd->mode = td.file.f_mode;
        !          1129:   bd->flags = td.file.f_flags;
        !          1130:   bd->port = ipc_port_alloc_kernel ();
        !          1131:   if (bd->port == IP_NULL)
        !          1132:     {
        !          1133:       err = KERN_RESOURCE_SHORTAGE;
        !          1134:       goto bad;
        !          1135:     }
        !          1136:   ipc_kobject_set (bd->port, (ipc_kobject_t) &bd->device, IKOT_DEVICE);
        !          1137:   notify = ipc_port_make_sonce (bd->port);
        !          1138:   ip_lock (bd->port);
        !          1139:   ipc_port_nsrequest (bd->port, 1, notify, &notify);
        !          1140:   assert (notify == IP_NULL);
        !          1141:   goto out;
        !          1142: 
        !          1143: bad:
        !          1144:   if (ds->fops->release)
        !          1145:     (*ds->fops->release) (&td.inode, &td.file);
        !          1146: 
        !          1147: out:
        !          1148:   ds->busy = 0;
        !          1149:   if (ds->want)
        !          1150:     {
        !          1151:       ds->want = 0;
        !          1152:       thread_wakeup ((event_t) ds);
        !          1153:     }
        !          1154: 
        !          1155:   if (bd && bd->open_count > 0)
        !          1156:     {
        !          1157:       if (err)
        !          1158:        *devp = NULL;
        !          1159:       else
        !          1160:        {
        !          1161:          *devp = &bd->device;
        !          1162:          bd->open_count++;
        !          1163:        }
        !          1164:       return err;
        !          1165:     }
        !          1166: 
        !          1167:   if (err)
        !          1168:     {
        !          1169:       if (bd)
        !          1170:        {
        !          1171:          if (bd->port != IP_NULL)
        !          1172:            {
        !          1173:              ipc_kobject_set (bd->port, IKO_NULL, IKOT_NONE);
        !          1174:              ipc_port_dealloc_kernel (bd->port);
        !          1175:            }
        !          1176:          kfree ((vm_offset_t) bd, sizeof (struct block_data));
        !          1177:          bd = NULL;
        !          1178:        }
        !          1179:     }
        !          1180:   else
        !          1181:     {
        !          1182:       bd->open_count = 1;
        !          1183:       bd->next = open_list;
        !          1184:       open_list = bd;
        !          1185:     }
        !          1186: 
        !          1187:   if (IP_VALID (reply_port))
        !          1188:     ds_device_open_reply (reply_port, reply_port_type, err, dev_to_port (bd));
        !          1189:   else if (! err)
        !          1190:     device_close (bd);
        !          1191: 
        !          1192:   return MIG_NO_REPLY;
        !          1193: }
        !          1194: 
        !          1195: static io_return_t
        !          1196: device_close (void *d)
        !          1197: {
        !          1198:   struct block_data *bd = d, *bdp, **prev;
        !          1199:   struct device_struct *ds = bd->ds;
        !          1200:   DECL_DATA;
        !          1201: 
        !          1202:   INIT_DATA ();
        !          1203: 
        !          1204:   /* Wait for any other open/close to complete.  */
        !          1205:   while (ds->busy)
        !          1206:     {
        !          1207:       ds->want = 1;
        !          1208:       assert_wait ((event_t) ds, FALSE);
        !          1209:       schedule ();
        !          1210:     }
        !          1211:   ds->busy = 1;
        !          1212: 
        !          1213:   if (--bd->open_count == 0)
        !          1214:     {
        !          1215:       /* Wait for pending I/O to complete.  */
        !          1216:       while (bd->iocount > 0)
        !          1217:        {
        !          1218:          bd->want = 1;
        !          1219:          assert_wait ((event_t) bd, FALSE);
        !          1220:          schedule ();
        !          1221:        }
        !          1222: 
        !          1223:       /* Remove device from open list.  */
        !          1224:       prev = &open_list;
        !          1225:       bdp = open_list;
        !          1226:       while (bdp)
        !          1227:        {
        !          1228:          if (bdp == bd)
        !          1229:            {
        !          1230:              *prev = bdp->next;
        !          1231:              break;
        !          1232:            }
        !          1233:          prev = &bdp->next;
        !          1234:          bdp = bdp->next;
        !          1235:        }
        !          1236: 
        !          1237:       assert (bdp == bd);
        !          1238: 
        !          1239:       if (ds->fops->release)
        !          1240:        (*ds->fops->release) (&td.inode, &td.file);
        !          1241: 
        !          1242:       ipc_kobject_set (bd->port, IKO_NULL, IKOT_NONE);
        !          1243:       ipc_port_dealloc_kernel (bd->port);
        !          1244:       kfree ((vm_offset_t) bd, sizeof (struct block_data));
        !          1245:     }
        !          1246: 
        !          1247:   ds->busy = 0;
        !          1248:   if (ds->want)
        !          1249:     {
        !          1250:       ds->want = 0;
        !          1251:       thread_wakeup ((event_t) ds);
        !          1252:     }
        !          1253:   return D_SUCCESS;
        !          1254: }
        !          1255: 
        !          1256: #define MAX_COPY       (VM_MAP_COPY_PAGE_LIST_MAX << PAGE_SHIFT)
        !          1257: 
        !          1258: /* Check block BN and size COUNT for I/O validity
        !          1259:    to from device BD.  Set *OFF to the byte offset
        !          1260:    where I/O is to begin and return the size of transfer.  */
        !          1261: static int
        !          1262: check_limit (struct block_data *bd, loff_t *off, long bn, int count)
        !          1263: {
        !          1264:   int major, minor;
        !          1265:   long maxsz, sz;
        !          1266:   struct disklabel *lp = NULL;
        !          1267: 
        !          1268:   if (count <= 0)
        !          1269:     return count;
        !          1270: 
        !          1271:   major = MAJOR (bd->dev);
        !          1272:   minor = MINOR (bd->dev);
        !          1273: 
        !          1274:   if (bd->ds->gd)
        !          1275:     {
        !          1276:       if (bd->part >= 0)
        !          1277:        {
        !          1278:          assert (bd->ds->labels);
        !          1279:          assert (bd->ds->labels[minor]);
        !          1280:          lp = bd->ds->labels[minor];
        !          1281:          maxsz = lp->d_partitions[bd->part].p_size;
        !          1282:        }
        !          1283:       else
        !          1284:        maxsz = bd->ds->gd->part[minor].nr_sects;
        !          1285:     }
        !          1286:   else
        !          1287:     {
        !          1288:       assert (blk_size[major]);
        !          1289:       maxsz = blk_size[major][minor] << (BLOCK_SIZE_BITS - 9);
        !          1290:     }
        !          1291:   assert (maxsz > 0);
        !          1292:   sz = maxsz - bn;
        !          1293:   if (sz <= 0)
        !          1294:     return sz;
        !          1295:   if (sz < ((count + 511) >> 9))
        !          1296:     count = sz << 9;
        !          1297:   if (lp)
        !          1298:     bn += (lp->d_partitions[bd->part].p_offset
        !          1299:           - bd->ds->gd->part[minor].start_sect);
        !          1300:   *off = (loff_t) bn << 9;
        !          1301:   bd->iocount++;
        !          1302:   return count;
        !          1303: }
        !          1304: 
        !          1305: static io_return_t
        !          1306: device_write (void *d, ipc_port_t reply_port,
        !          1307:              mach_msg_type_name_t reply_port_type, dev_mode_t mode,
        !          1308:              recnum_t bn, io_buf_ptr_t data, unsigned int orig_count,
        !          1309:              int *bytes_written)
        !          1310: {
        !          1311:   int resid, amt, i;
        !          1312:   int count = (int) orig_count;
        !          1313:   io_return_t err = 0;
        !          1314:   vm_map_copy_t copy;
        !          1315:   vm_offset_t addr, uaddr;
        !          1316:   vm_size_t len, size;
        !          1317:   struct block_data *bd = d;
        !          1318:   DECL_DATA;
        !          1319: 
        !          1320:   INIT_DATA ();
        !          1321: 
        !          1322:   *bytes_written = 0;
        !          1323: 
        !          1324:   if (bd->mode == O_RDONLY)
        !          1325:     return D_INVALID_OPERATION;
        !          1326:   if (! bd->ds->fops->write)
        !          1327:     return D_READ_ONLY;
        !          1328:   count = check_limit (bd, &td.file.f_pos, bn, count);
        !          1329:   if (count < 0)
        !          1330:     return D_INVALID_SIZE;
        !          1331:   if (count == 0)
        !          1332:     {
        !          1333:       vm_map_copy_discard (copy);
        !          1334:       return 0;
        !          1335:     }
        !          1336: 
        !          1337:   resid = count;
        !          1338:   copy = (vm_map_copy_t) data;
        !          1339:   uaddr = copy->offset;
        !          1340: 
        !          1341:   /* Allocate a kernel buffer.  */
        !          1342:   size = round_page (uaddr + count) - trunc_page (uaddr);
        !          1343:   if (size > MAX_COPY)
        !          1344:     size = MAX_COPY;
        !          1345:   addr = vm_map_min (device_io_map);
        !          1346:   err = vm_map_enter (device_io_map, &addr, size, 0, TRUE,
        !          1347:                      NULL, 0, FALSE, VM_PROT_READ|VM_PROT_WRITE,
        !          1348:                      VM_PROT_READ|VM_PROT_WRITE, VM_INHERIT_NONE);
        !          1349:   if (err)
        !          1350:     {
        !          1351:       vm_map_copy_discard (copy);
        !          1352:       goto out;
        !          1353:     }
        !          1354: 
        !          1355:   /* Determine size of I/O this time around.  */
        !          1356:   len = size - (uaddr & PAGE_MASK);
        !          1357:   if (len > resid)
        !          1358:     len = resid;
        !          1359: 
        !          1360:   while (1)
        !          1361:     {
        !          1362:       /* Map user pages.  */
        !          1363:       for (i = 0; i < copy->cpy_npages; i++)
        !          1364:        pmap_enter (vm_map_pmap (device_io_map),
        !          1365:                    addr + (i << PAGE_SHIFT),
        !          1366:                    copy->cpy_page_list[i]->phys_addr,
        !          1367:                    VM_PROT_READ|VM_PROT_WRITE, TRUE);
        !          1368: 
        !          1369:       /* Do the write.  */
        !          1370:       amt = (*bd->ds->fops->write) (&td.inode, &td.file,
        !          1371:                                    (char *) addr + (uaddr & PAGE_MASK), len);
        !          1372: 
        !          1373:       /* Unmap pages and deallocate copy.  */
        !          1374:       pmap_remove (vm_map_pmap (device_io_map),
        !          1375:                   addr, addr + (copy->cpy_npages << PAGE_SHIFT));
        !          1376:       vm_map_copy_discard (copy);
        !          1377: 
        !          1378:       /* Check result of write.  */
        !          1379:       if (amt > 0)
        !          1380:        {
        !          1381:          resid -= amt;
        !          1382:          if (resid == 0)
        !          1383:            break;
        !          1384:          uaddr += amt;
        !          1385:        }
        !          1386:       else
        !          1387:        {
        !          1388:          if (amt < 0)
        !          1389:            err = linux_to_mach_error (amt);
        !          1390:          break;
        !          1391:        }
        !          1392: 
        !          1393:       /* Determine size of I/O this time around and copy in pages.  */
        !          1394:       len = round_page (uaddr + resid) - trunc_page (uaddr);
        !          1395:       if (len > MAX_COPY)
        !          1396:        len = MAX_COPY;
        !          1397:       len -= uaddr & PAGE_MASK;
        !          1398:       if (len > resid)
        !          1399:        len = resid;
        !          1400:       err = vm_map_copyin_page_list (current_map (), uaddr, len,
        !          1401:                                     FALSE, FALSE, &copy, FALSE);
        !          1402:       if (err)
        !          1403:        break;
        !          1404:     }
        !          1405: 
        !          1406:   /* Delete kernel buffer.  */
        !          1407:   vm_map_remove (device_io_map, addr, addr + size);
        !          1408: 
        !          1409: out:
        !          1410:   if (--bd->iocount == 0 && bd->want)
        !          1411:     {
        !          1412:       bd->want = 0;
        !          1413:       thread_wakeup ((event_t) bd);
        !          1414:     }
        !          1415:   if (IP_VALID (reply_port))
        !          1416:     ds_device_write_reply (reply_port, reply_port_type, err, count - resid);
        !          1417:   return MIG_NO_REPLY;
        !          1418: }
        !          1419: 
        !          1420: static io_return_t
        !          1421: device_read (void *d, ipc_port_t reply_port,
        !          1422:             mach_msg_type_name_t reply_port_type, dev_mode_t mode,
        !          1423:             recnum_t bn, int count, io_buf_ptr_t *data,
        !          1424:             unsigned *bytes_read)
        !          1425: {
        !          1426:   boolean_t dirty;
        !          1427:   int resid, amt;
        !          1428:   io_return_t err = 0;
        !          1429:   queue_head_t pages;
        !          1430:   vm_map_copy_t copy;
        !          1431:   vm_offset_t addr, offset, alloc_offset, o;
        !          1432:   vm_object_t object;
        !          1433:   vm_page_t m;
        !          1434:   vm_size_t len, size;
        !          1435:   struct block_data *bd = d;
        !          1436:   DECL_DATA;
        !          1437: 
        !          1438:   INIT_DATA ();
        !          1439: 
        !          1440:   *data = 0;
        !          1441:   *bytes_read = 0;
        !          1442: 
        !          1443:   if (! bd->ds->fops->read)
        !          1444:     return D_INVALID_OPERATION;
        !          1445:   count = check_limit (bd, &td.file.f_pos, bn, count);
        !          1446:   if (count < 0)
        !          1447:     return D_INVALID_SIZE;
        !          1448:   if (count == 0)
        !          1449:     return 0;
        !          1450: 
        !          1451:   /* Allocate an object to hold the data.  */
        !          1452:   size = round_page (count);
        !          1453:   object = vm_object_allocate (size);
        !          1454:   if (! object)
        !          1455:     {
        !          1456:       err = D_NO_MEMORY;
        !          1457:       goto out;
        !          1458:     }
        !          1459:   alloc_offset = offset = 0;
        !          1460:   resid = count;
        !          1461: 
        !          1462:   /* Allocate a kernel buffer.  */
        !          1463:   addr = vm_map_min (device_io_map);
        !          1464:   if (size > MAX_COPY)
        !          1465:     size = MAX_COPY;
        !          1466:   err = vm_map_enter (device_io_map, &addr, size, 0, TRUE, NULL,
        !          1467:                      0, FALSE, VM_PROT_READ|VM_PROT_WRITE,
        !          1468:                      VM_PROT_READ|VM_PROT_WRITE, VM_INHERIT_NONE);
        !          1469:   if (err)
        !          1470:     goto out;
        !          1471: 
        !          1472:   queue_init (&pages);
        !          1473: 
        !          1474:   while (resid)
        !          1475:     {
        !          1476:       /* Determine size of I/O this time around.  */
        !          1477:       len = round_page (offset + resid) - trunc_page (offset);
        !          1478:       if (len > MAX_COPY)
        !          1479:        len = MAX_COPY;
        !          1480: 
        !          1481:       /* Map any pages left from previous operation.  */
        !          1482:       o = trunc_page (offset);
        !          1483:       queue_iterate (&pages, m, vm_page_t, pageq)
        !          1484:        {
        !          1485:          pmap_enter (vm_map_pmap (device_io_map),
        !          1486:                      addr + o - trunc_page (offset),
        !          1487:                      m->phys_addr, VM_PROT_READ|VM_PROT_WRITE, TRUE);
        !          1488:          o += PAGE_SIZE;
        !          1489:        }
        !          1490:       assert (o == alloc_offset);
        !          1491: 
        !          1492:       /* Allocate and map pages.  */
        !          1493:       while (alloc_offset < trunc_page (offset) + len)
        !          1494:        {
        !          1495:          while ((m = vm_page_grab ()) == 0)
        !          1496:            VM_PAGE_WAIT (0);
        !          1497:          assert (! m->active && ! m->inactive);
        !          1498:          m->busy = TRUE;
        !          1499:          queue_enter (&pages, m, vm_page_t, pageq);
        !          1500:          pmap_enter (vm_map_pmap (device_io_map),
        !          1501:                      addr + alloc_offset - trunc_page (offset),
        !          1502:                      m->phys_addr, VM_PROT_READ|VM_PROT_WRITE, TRUE);
        !          1503:          alloc_offset += PAGE_SIZE;
        !          1504:        }
        !          1505: 
        !          1506:       /* Do the read.  */
        !          1507:       amt = len - (offset & PAGE_MASK);
        !          1508:       if (amt > resid)
        !          1509:        amt = resid;
        !          1510:       amt = (*bd->ds->fops->read) (&td.inode, &td.file,
        !          1511:                                   (char *) addr + (offset & PAGE_MASK), amt);
        !          1512: 
        !          1513:       /* Compute number of pages to insert in object.  */
        !          1514:       o = trunc_page (offset);
        !          1515:       if (amt > 0)
        !          1516:        {
        !          1517:          dirty = TRUE;
        !          1518:          resid -= amt;
        !          1519:          if (resid == 0)
        !          1520:            {
        !          1521:              /* Zero any unused space.  */
        !          1522:              if (offset + amt < o + len)
        !          1523:                memset ((void *) (addr + offset - o + amt),
        !          1524:                        0, o + len - offset - amt);
        !          1525:              offset = o + len;
        !          1526:            }
        !          1527:          else
        !          1528:            offset += amt;
        !          1529:        }
        !          1530:       else
        !          1531:        {
        !          1532:          dirty = FALSE;
        !          1533:          offset = o + len;
        !          1534:        }
        !          1535: 
        !          1536:       /* Unmap pages and add them to the object.  */
        !          1537:       pmap_remove (vm_map_pmap (device_io_map), addr, addr + len);
        !          1538:       vm_object_lock (object);
        !          1539:       while (o < trunc_page (offset))
        !          1540:        {
        !          1541:          m = (vm_page_t) queue_first (&pages);
        !          1542:          assert (! queue_end (&pages, (queue_entry_t) m));
        !          1543:          queue_remove (&pages, m, vm_page_t, pageq);
        !          1544:          assert (m->busy);
        !          1545:          vm_page_lock_queues ();
        !          1546:          if (dirty)
        !          1547:            {
        !          1548:              PAGE_WAKEUP_DONE (m);
        !          1549:              m->dirty = TRUE;
        !          1550:              vm_page_insert (m, object, o);
        !          1551:            }
        !          1552:          else
        !          1553:            vm_page_free (m);
        !          1554:          vm_page_unlock_queues ();
        !          1555:          o += PAGE_SIZE;
        !          1556:        }
        !          1557:       vm_object_unlock (object);
        !          1558:       if (amt <= 0)
        !          1559:        {
        !          1560:          if (amt < 0)
        !          1561:            err = linux_to_mach_error (amt);
        !          1562:          break;
        !          1563:        }
        !          1564:     }
        !          1565: 
        !          1566:   /* Delete kernel buffer.  */
        !          1567:   vm_map_remove (device_io_map, addr, addr + size);
        !          1568: 
        !          1569:   assert (queue_empty (&pages));
        !          1570: 
        !          1571: out:
        !          1572:   if (! err)
        !          1573:     err = vm_map_copyin_object (object, 0, round_page (count), &copy);
        !          1574:   if (! err)
        !          1575:     {
        !          1576:       *data = (io_buf_ptr_t) copy;
        !          1577:       *bytes_read = count - resid;
        !          1578:     }
        !          1579:   else
        !          1580:     vm_object_deallocate (object);
        !          1581:   if (--bd->iocount == 0 && bd->want)
        !          1582:     {
        !          1583:       bd->want = 0;
        !          1584:       thread_wakeup ((event_t) bd);
        !          1585:     }
        !          1586:   return err;
        !          1587: }
        !          1588: 
        !          1589: static io_return_t
        !          1590: device_get_status (void *d, dev_flavor_t flavor, dev_status_t status,
        !          1591:                   mach_msg_type_number_t *status_count)
        !          1592: {
        !          1593:   struct block_data *bd = d;
        !          1594: 
        !          1595:   switch (flavor)
        !          1596:     {
        !          1597:     case DEV_GET_SIZE:
        !          1598:       if (disk_major (MAJOR (bd->dev)))
        !          1599:        {
        !          1600:          assert (bd->ds->gd);
        !          1601: 
        !          1602:          if (bd->part >= 0)
        !          1603:            {
        !          1604:              struct disklabel *lp;
        !          1605: 
        !          1606:              assert (bd->ds->labels);
        !          1607:              lp = bd->ds->labels[MINOR (bd->dev)];
        !          1608:              assert (lp);
        !          1609:              (status[DEV_GET_SIZE_DEVICE_SIZE]
        !          1610:               = lp->d_partitions[bd->part].p_size << 9);
        !          1611:            }
        !          1612:          else
        !          1613:            (status[DEV_GET_SIZE_DEVICE_SIZE]
        !          1614:             = bd->ds->gd->part[MINOR (bd->dev)].nr_sects << 9);
        !          1615:        }
        !          1616:       else
        !          1617:        {
        !          1618:          assert (blk_size[MAJOR (bd->dev)]);
        !          1619:          (status[DEV_GET_SIZE_DEVICE_SIZE]
        !          1620:           = (blk_size[MAJOR (bd->dev)][MINOR (bd->dev)]
        !          1621:              << BLOCK_SIZE_BITS));
        !          1622:        }
        !          1623:       /* It would be nice to return the block size as reported by
        !          1624:         the driver, but a lot of user level code assumes the sector
        !          1625:         size to be 512.  */
        !          1626:       status[DEV_GET_SIZE_RECORD_SIZE] = 512;
        !          1627:       /* Always return DEV_GET_SIZE_COUNT.  This is what all native
        !          1628:          Mach drivers do, and makes it possible to detect the absence
        !          1629:          of the call by setting it to a different value on input.  MiG
        !          1630:          makes sure that we will never return more integers than the
        !          1631:          user asked for.  */
        !          1632:       *status_count = DEV_GET_SIZE_COUNT;
        !          1633:       break;
        !          1634: 
        !          1635:     case V_GETPARMS:
        !          1636:       if (*status_count < (sizeof (struct disk_parms) / sizeof (int)))
        !          1637:        return D_INVALID_OPERATION;
        !          1638:       else
        !          1639:        {
        !          1640:          struct disk_parms *dp = status;
        !          1641:          struct hd_geometry hg;
        !          1642:          DECL_DATA;
        !          1643: 
        !          1644:          INIT_DATA();
        !          1645: 
        !          1646:          if ((*bd->ds->fops->ioctl) (&td.inode, &td.file,
        !          1647:                                      HDIO_GETGEO, &hg))
        !          1648:            return D_INVALID_OPERATION;
        !          1649: 
        !          1650:          dp->dp_type = DPT_WINI;  /* XXX: It may be a floppy...  */
        !          1651:          dp->dp_heads = hg.heads;
        !          1652:          dp->dp_cyls = hg.cylinders;
        !          1653:          dp->dp_sectors = hg.sectors;
        !          1654:          dp->dp_dosheads = hg.heads;
        !          1655:          dp->dp_doscyls = hg.cylinders;
        !          1656:          dp->dp_dossectors = hg.sectors;
        !          1657:          dp->dp_secsiz = 512;  /* XXX */
        !          1658:          dp->dp_ptag = 0;
        !          1659:          dp->dp_pflag = 0;
        !          1660:          
        !          1661:          /* XXX */
        !          1662:          dp->dp_pstartsec = -1;
        !          1663:          dp->dp_pnumsec = -1;
        !          1664: 
        !          1665:          *status_count = sizeof (struct disk_parms) / sizeof (int);
        !          1666:        }
        !          1667:       
        !          1668:       break;
        !          1669:       
        !          1670:     default:
        !          1671:       return D_INVALID_OPERATION;
        !          1672:     }
        !          1673: 
        !          1674:   return D_SUCCESS;
        !          1675: }
        !          1676: 
        !          1677: struct device_emulation_ops linux_block_emulation_ops =
        !          1678: {
        !          1679:   NULL,
        !          1680:   NULL,
        !          1681:   dev_to_port,
        !          1682:   device_open,
        !          1683:   device_close,
        !          1684:   device_write,
        !          1685:   NULL,
        !          1686:   device_read,
        !          1687:   NULL,
        !          1688:   NULL,
        !          1689:   device_get_status,
        !          1690:   NULL,
        !          1691:   NULL,
        !          1692:   NULL,
        !          1693:   NULL,
        !          1694:   NULL
        !          1695: };

unix.superglobalmegacorp.com

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