Annotation of Gnu-Mach/i386/i386at/gpl/linux/linux_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 <mach/mach_types.h>
        !            45: #include <mach/kern_return.h>
        !            46: #include <mach/mig_errors.h>
        !            47: #include <mach/port.h>
        !            48: #include <mach/vm_param.h>
        !            49: #include <mach/notify.h>
        !            50: 
        !            51: #include <ipc/ipc_port.h>
        !            52: #include <ipc/ipc_space.h>
        !            53: 
        !            54: #include <vm/vm_map.h>
        !            55: #include <vm/vm_kern.h>
        !            56: #include <vm/vm_page.h>
        !            57: 
        !            58: #include <device/device_types.h>
        !            59: #include <device/device_port.h>
        !            60: #include <device/disk_status.h>
        !            61: #include "device_reply.h"
        !            62: 
        !            63: #include <i386at/dev_hdr.h>
        !            64: #include <i386at/device_emul.h>
        !            65: #include <i386at/disk.h>
        !            66: 
        !            67: #include <i386at/gpl/linux/linux_emul.h>
        !            68: 
        !            69: #define MACH_INCLUDE
        !            70: #include <linux/fs.h>
        !            71: #include <linux/blk.h>
        !            72: #include <linux/string.h>
        !            73: #include <linux/errno.h>
        !            74: #include <linux/fcntl.h>
        !            75: #include <linux/major.h>
        !            76: #include <linux/kdev_t.h>
        !            77: #include <linux/delay.h>
        !            78: #include <linux/malloc.h>
        !            79: 
        !            80: /* Location of VTOC in units for sectors (512 bytes).  */
        !            81: #define PDLOCATION 29
        !            82: 
        !            83: /* Linux kernel variables.  */
        !            84: 
        !            85: /* One of these exists for each
        !            86:    driver associated with a major number.  */
        !            87: struct device_struct
        !            88: {
        !            89:   const char *name;            /* device name */
        !            90:   struct file_operations *fops;        /* operations vector */
        !            91:   int busy:1;                  /* driver is being opened/closed */
        !            92:   int want:1;                  /* someone wants to open/close driver */
        !            93:   struct gendisk *gd;          /* DOS partition information */
        !            94:   int *default_slice;          /* what slice to use when none is given */
        !            95:   struct disklabel **label;    /* disklabels for each DOS partition */
        !            96: };
        !            97: 
        !            98: /* An entry in the Mach name to Linux major number conversion table.  */
        !            99: struct name_map
        !           100: {
        !           101:   const char *name;    /* Mach name for device */
        !           102:   unsigned major;      /* Linux major number */
        !           103:   unsigned unit;       /* Linux unit number */
        !           104:   int read_only;       /* 1 if device is read only */
        !           105: };
        !           106: 
        !           107: /* Driver operation table.  */
        !           108: static struct device_struct blkdevs[MAX_BLKDEV];
        !           109: 
        !           110: /* Driver request function table.  */
        !           111: struct blk_dev_struct blk_dev[MAX_BLKDEV] =
        !           112: {
        !           113:   { NULL, NULL },              /* 0 no_dev */
        !           114:   { NULL, NULL },              /* 1 dev mem */
        !           115:   { NULL, NULL },              /* 2 dev fd */
        !           116:   { NULL, NULL },              /* 3 dev ide0 or hd */
        !           117:   { NULL, NULL },              /* 4 dev ttyx */
        !           118:   { NULL, NULL },              /* 5 dev tty */
        !           119:   { NULL, NULL },              /* 6 dev lp */
        !           120:   { NULL, NULL },              /* 7 dev pipes */
        !           121:   { NULL, NULL },              /* 8 dev sd */
        !           122:   { NULL, NULL },              /* 9 dev st */
        !           123:   { NULL, NULL },              /* 10 */
        !           124:   { NULL, NULL },              /* 11 */
        !           125:   { NULL, NULL },              /* 12 */
        !           126:   { NULL, NULL },              /* 13 */
        !           127:   { NULL, NULL },              /* 14 */
        !           128:   { NULL, NULL },              /* 15 */
        !           129:   { NULL, NULL },              /* 16 */
        !           130:   { NULL, NULL },              /* 17 */
        !           131:   { NULL, NULL },              /* 18 */
        !           132:   { NULL, NULL },              /* 19 */
        !           133:   { NULL, NULL },              /* 20 */
        !           134:   { NULL, NULL },              /* 21 */
        !           135:   { NULL, NULL }               /* 22 dev ide1 */
        !           136: };
        !           137: 
        !           138: /*
        !           139:  * blk_size contains the size of all block-devices in units of 1024 byte
        !           140:  * sectors:
        !           141:  *
        !           142:  * blk_size[MAJOR][MINOR]
        !           143:  *
        !           144:  * if (!blk_size[MAJOR]) then no minor size checking is done.
        !           145:  */
        !           146: int *blk_size[MAX_BLKDEV] = { NULL, NULL, };
        !           147: 
        !           148: /*
        !           149:  * blksize_size contains the size of all block-devices:
        !           150:  *
        !           151:  * blksize_size[MAJOR][MINOR]
        !           152:  *
        !           153:  * if (!blksize_size[MAJOR]) then 1024 bytes is assumed.
        !           154:  */
        !           155: int *blksize_size[MAX_BLKDEV] = { NULL, NULL, };
        !           156: 
        !           157: /*
        !           158:  * hardsect_size contains the size of the hardware sector of a device.
        !           159:  *
        !           160:  * hardsect_size[MAJOR][MINOR]
        !           161:  *
        !           162:  * if (!hardsect_size[MAJOR])
        !           163:  *             then 512 bytes is assumed.
        !           164:  * else
        !           165:  *             sector_size is hardsect_size[MAJOR][MINOR]
        !           166:  * This is currently set by some scsi device and read by the msdos fs driver
        !           167:  * This might be a some uses later.
        !           168:  */
        !           169: int *hardsect_size[MAX_BLKDEV] = { NULL, NULL, };
        !           170: 
        !           171: /* This specifies how many sectors to read ahead on the disk.
        !           172:    This is unused in Mach.  It is here to make drivers compile.  */
        !           173: int read_ahead[MAX_BLKDEV] = {0, };
        !           174: 
        !           175: /* Use to wait on when there are no free requests.
        !           176:    This is unused in Mach.  It is here to make drivers compile.  */
        !           177: struct wait_queue *wait_for_request = NULL;
        !           178: 
        !           179: /* Initialize block drivers.  */
        !           180: void
        !           181: blk_dev_init ()
        !           182: {
        !           183: #ifdef CONFIG_BLK_DEV_IDE
        !           184:   ide_init ();
        !           185: #endif
        !           186: #ifdef CONFIG_BLK_DEV_FD
        !           187:   floppy_init ();
        !           188: #endif
        !           189: }
        !           190: 
        !           191: /* Return 1 if major number MAJOR corresponds to a disk device.  */
        !           192: static inline int
        !           193: disk_major (int major)
        !           194: {
        !           195:   return (major == IDE0_MAJOR
        !           196:          || major == IDE1_MAJOR
        !           197:          || major == IDE2_MAJOR
        !           198:          || major == IDE3_MAJOR
        !           199:          || major == SCSI_DISK_MAJOR);
        !           200: }
        !           201: 
        !           202: /* Linux kernel block support routines.  */
        !           203: 
        !           204: /* Register a driver for major number MAJOR,
        !           205:    with name NAME, and operations vector FOPS.  */
        !           206: int
        !           207: register_blkdev (unsigned major, const char *name,
        !           208:                 struct file_operations *fops)
        !           209: {
        !           210:   int err = 0;
        !           211: 
        !           212:   if (major == 0)
        !           213:     {
        !           214:       for (major = MAX_BLKDEV - 1; major > 0; major--)
        !           215:        if (blkdevs[major].fops == NULL)
        !           216:          goto out;
        !           217:       return -LINUX_EBUSY;
        !           218:     }
        !           219:   if (major >= MAX_BLKDEV)
        !           220:     return -LINUX_EINVAL;
        !           221:   if (blkdevs[major].fops && blkdevs[major].fops != fops)
        !           222:     return -LINUX_EBUSY;
        !           223: 
        !           224: out:
        !           225:   blkdevs[major].name = name;
        !           226:   blkdevs[major].fops = fops;
        !           227:   blkdevs[major].busy = 0;
        !           228:   blkdevs[major].want = 0;
        !           229:   blkdevs[major].gd = NULL;
        !           230:   blkdevs[major].default_slice = NULL;
        !           231:   blkdevs[major].label = NULL;
        !           232:   return 0;
        !           233: }
        !           234: 
        !           235: /* Unregister the driver associated with
        !           236:    major number MAJOR and having the name NAME.  */
        !           237: int
        !           238: unregister_blkdev (unsigned major, const char *name)
        !           239: {
        !           240:   int err;
        !           241: 
        !           242:   if (major >= MAX_BLKDEV)
        !           243:     return -LINUX_EINVAL;
        !           244:   if (! blkdevs[major].fops || strcmp (blkdevs[major].name, name))
        !           245:     return -LINUX_EINVAL;
        !           246:   blkdevs[major].fops = NULL;
        !           247:   if (blkdevs[major].default_slice)
        !           248:     {
        !           249:       assert (blkdevs[major].gd);
        !           250:       kfree ((vm_offset_t) blkdevs[major].default_slice,
        !           251:             sizeof (int) * blkdevs[major].gd->max_nr);
        !           252:     }
        !           253:   if (blkdevs[major].label)
        !           254:     {
        !           255:       assert (blkdevs[major].gd);
        !           256:       kfree ((vm_offset_t) blkdevs[major].label,
        !           257:             (sizeof (struct disklabel *)
        !           258:              * blkdevs[major].gd->max_p * blkdevs[major].gd->max_nr));
        !           259:     }
        !           260:   return 0;
        !           261: }
        !           262: 
        !           263: /* One of these is associated with
        !           264:    each page allocated by the buffer management routines.  */
        !           265: struct pagehdr
        !           266: {
        !           267:   unsigned char busy;          /* page header is in use */
        !           268:   unsigned char avail;         /* number of blocks available in page */
        !           269:   unsigned short bitmap;       /* free space bitmap */
        !           270:   void *blks;                  /* the actual page */
        !           271:   struct pagehdr *next;                /* next header in list */
        !           272: };
        !           273: 
        !           274: /* This structure describes the different block sizes.  */
        !           275: struct bufsize
        !           276: {
        !           277:   unsigned short size;         /* size of block */
        !           278:   unsigned short avail;                /* # available blocks */
        !           279:   struct pagehdr *pages;       /* page list */
        !           280: };
        !           281: 
        !           282: /* List of supported block sizes.  */
        !           283: static struct bufsize bufsizes[] =
        !           284: {
        !           285:   {  512, 0, NULL },
        !           286:   { 1024, 0, NULL },
        !           287:   { 2048, 0, NULL },
        !           288:   { 4096, 0, NULL },
        !           289: };
        !           290: 
        !           291: /* Page headers.  */
        !           292: static struct pagehdr pagehdrs[50];    /* XXX: needs to be dynamic */
        !           293: 
        !           294: /* Find the block size that is greater than or equal to SIZE.  */
        !           295: static struct bufsize *
        !           296: get_bufsize (int size)
        !           297: {
        !           298:   struct bufsize *bs, *ebs;
        !           299: 
        !           300:   bs = &bufsizes[0];
        !           301:   ebs = &bufsizes[sizeof (bufsizes) / sizeof (bufsizes[0])];
        !           302:   while (bs < ebs)
        !           303:     {
        !           304:       if (bs->size >= size)
        !           305:        return bs;
        !           306:       bs++;
        !           307:     }
        !           308: 
        !           309:   panic ("%s:%d: alloc_buffer: bad buffer size %d", __FILE__, __LINE__, size);
        !           310: }
        !           311: 
        !           312: /* Free all pages that are not in use.
        !           313:    Called by __get_free_pages when pages are running low.  */
        !           314: void
        !           315: collect_buffer_pages ()
        !           316: {
        !           317:   struct bufsize *bs, *ebs;
        !           318:   struct pagehdr *ph, **prev_ph;
        !           319: 
        !           320:   bs = &bufsizes[0];
        !           321:   ebs = &bufsizes[sizeof (bufsizes) / sizeof (bufsizes[0])];
        !           322:   while (bs < ebs)
        !           323:     {
        !           324:       if (bs->avail >= PAGE_SIZE / bs->size)
        !           325:        {
        !           326:          ph = bs->pages;
        !           327:          prev_ph = &bs->pages;
        !           328:          while (ph)
        !           329:            if (ph->avail == PAGE_SIZE / bs->size)
        !           330:              {
        !           331:                bs->avail -= ph->avail;
        !           332:                ph->busy = 0;
        !           333:                *prev_ph = ph->next;
        !           334:                free_pages ((unsigned long) ph->blks, 0);
        !           335:                ph = *prev_ph;
        !           336:              }
        !           337:            else
        !           338:              {
        !           339:                prev_ph = &ph->next;
        !           340:                ph = ph->next;
        !           341:              }
        !           342:        }
        !           343:       bs++;
        !           344:     }
        !           345: }
        !           346: 
        !           347: /* Allocate a buffer of at least SIZE bytes.  */
        !           348: static void *
        !           349: alloc_buffer (int size)
        !           350: {
        !           351:   int i;
        !           352:   unsigned flags;
        !           353:   struct bufsize *bs;
        !           354:   struct pagehdr *ph, *eph;
        !           355: 
        !           356:   bs = get_bufsize (size);
        !           357:   save_flags (flags);
        !           358:   cli ();
        !           359:   if (bs->avail == 0)
        !           360:     {
        !           361:       ph = &pagehdrs[0];
        !           362:       eph = &pagehdrs[sizeof (pagehdrs) / sizeof (pagehdrs[0])];
        !           363:       while (ph < eph && ph->busy)
        !           364:        ph++;
        !           365:       if (ph == eph)
        !           366:        {
        !           367:          restore_flags (flags);
        !           368:          printf ("%s:%d: alloc_buffer: ran out of page headers\n",
        !           369:                  __FILE__, __LINE__);
        !           370:          return NULL;
        !           371:        }
        !           372:       ph->blks = (void *) __get_free_pages (GFP_KERNEL, 0, ~0UL);
        !           373:       if (! ph->blks)
        !           374:        {
        !           375:          restore_flags (flags);
        !           376:          return NULL;
        !           377:        }
        !           378:       ph->busy = 1;
        !           379:       ph->avail = PAGE_SIZE / bs->size;
        !           380:       ph->bitmap = 0;
        !           381:       ph->next = bs->pages;
        !           382:       bs->pages = ph;
        !           383:       bs->avail += ph->avail;
        !           384:     }
        !           385:   for (ph = bs->pages; ph; ph = ph->next)
        !           386:     if (ph->avail)
        !           387:       for (i = 0; i < PAGE_SIZE / bs->size; i++)
        !           388:        if ((ph->bitmap & (1 << i)) == 0)
        !           389:          {
        !           390:            bs->avail--;
        !           391:            ph->avail--;
        !           392:            ph->bitmap |= 1 << i;
        !           393:            restore_flags (flags);
        !           394:            return ph->blks + i * bs->size;
        !           395:          }
        !           396: 
        !           397:   panic ("%s:%d: alloc_buffer: list destroyed", __FILE__, __LINE__);
        !           398: }
        !           399: 
        !           400: /* Free buffer P of SIZE bytes previously allocated by alloc_buffer.  */
        !           401: static void
        !           402: free_buffer (void *p, int size)
        !           403: {
        !           404:   int i;
        !           405:   unsigned flags;
        !           406:   struct bufsize *bs;
        !           407:   struct pagehdr *ph;
        !           408: 
        !           409:   bs = get_bufsize (size);
        !           410:   save_flags (flags);
        !           411:   cli ();
        !           412:   for (ph = bs->pages; ph; ph = ph->next)
        !           413:     if (p >= ph->blks && p < ph->blks + PAGE_SIZE)
        !           414:       break;
        !           415:   assert (ph);
        !           416:   i = (int) (p - ph->blks) / bs->size;
        !           417:   assert (ph->bitmap & (1 << i));
        !           418:   ph->bitmap &= ~(1 << i);
        !           419:   ph->avail++;
        !           420:   bs->avail++;
        !           421:   restore_flags (flags);
        !           422: }
        !           423: 
        !           424: /* Allocate a buffer of SIZE bytes and
        !           425:    associate it with block number BLOCK of device DEV.  */
        !           426: struct buffer_head *
        !           427: getblk (kdev_t dev, int block, int size)
        !           428: {
        !           429:   struct buffer_head *bh;
        !           430: 
        !           431:   assert (size <= PAGE_SIZE);
        !           432: 
        !           433:   bh = linux_kmalloc (sizeof (struct buffer_head), GFP_KERNEL);
        !           434:   if (! bh)
        !           435:     return NULL;
        !           436:   bh->b_data = alloc_buffer (size);
        !           437:   if (! bh->b_data)
        !           438:     {
        !           439:       linux_kfree (bh);
        !           440:       return NULL;
        !           441:     }
        !           442:   bh->b_dev = dev;
        !           443:   bh->b_size = size;
        !           444:   bh->b_state = 1 << BH_Lock;
        !           445:   bh->b_blocknr = block;
        !           446:   bh->b_page_list = NULL;
        !           447:   bh->b_request = NULL;
        !           448:   bh->b_reqnext = NULL;
        !           449:   bh->b_wait = NULL;
        !           450:   bh->b_sem = NULL;
        !           451:   return bh;
        !           452: }
        !           453: 
        !           454: /* Release buffer BH previously allocated by getblk.  */
        !           455: void
        !           456: __brelse (struct buffer_head *bh)
        !           457: {
        !           458:   if (bh->b_request)
        !           459:     linux_kfree (bh->b_request);
        !           460:   free_buffer (bh->b_data, bh->b_size);
        !           461:   linux_kfree (bh);
        !           462: }
        !           463: 
        !           464: /* Check for I/O errors upon completion of I/O operation RW
        !           465:    on the buffer list BH.  The number of buffers is NBUF.
        !           466:    Copy any data from bounce buffers and free them.  */
        !           467: static int
        !           468: check_for_error (int rw, int nbuf, struct buffer_head **bh)
        !           469: {
        !           470:   int err;
        !           471:   struct request *req;
        !           472: 
        !           473:   req = bh[0]->b_request;
        !           474:   if (! req)
        !           475:     {
        !           476:       while (--nbuf >= 0)
        !           477:        if (bh[nbuf]->b_page_list)
        !           478:          {
        !           479:            bh[nbuf]->b_page_list = NULL;
        !           480:            free_buffer (bh[nbuf]->b_data, bh[nbuf]->b_size);
        !           481:          }
        !           482:       return -LINUX_ENOMEM;
        !           483:     }
        !           484: 
        !           485:   bh[0]->b_request = NULL;
        !           486:   err = 0;
        !           487: 
        !           488:   while (--nbuf >= 0)
        !           489:     {
        !           490:       struct buffer_head *bhp = bh[nbuf];
        !           491: 
        !           492:       if (bhp->b_page_list)
        !           493:        {
        !           494:          if (rw == READ && buffer_uptodate (bhp))
        !           495:            {
        !           496:              int amt;
        !           497:              vm_page_t *pages = bhp->b_page_list;
        !           498: 
        !           499:              amt = PAGE_SIZE - bhp->b_off;
        !           500:              if (amt > bhp->b_usrcnt)
        !           501:                amt = bhp->b_usrcnt;
        !           502:              memcpy ((void *) pages[bhp->b_index]->phys_addr + bhp->b_off,
        !           503:                      bhp->b_data, amt);
        !           504:              if (amt < bhp->b_usrcnt)
        !           505:                memcpy ((void *) pages[bhp->b_index + 1]->phys_addr,
        !           506:                        bhp->b_data + amt, bhp->b_usrcnt - amt);
        !           507:            }
        !           508:          bhp->b_page_list = NULL;
        !           509:          free_buffer (bhp->b_data, bhp->b_size);
        !           510:        }
        !           511:       if (! buffer_uptodate (bhp))
        !           512:        err = -LINUX_EIO;
        !           513:     }
        !           514: 
        !           515:   linux_kfree (req);
        !           516:   return err;
        !           517: }
        !           518: 
        !           519: /* Allocate a buffer of SIZE bytes and fill it with data
        !           520:    from device DEV starting at block number BLOCK.  */
        !           521: struct buffer_head *
        !           522: bread (kdev_t dev, int block, int size)
        !           523: {
        !           524:   int err;
        !           525:   struct buffer_head *bh;
        !           526: 
        !           527:   bh = getblk (dev, block, size);
        !           528:   if (! bh)
        !           529:     return NULL;
        !           530:   ll_rw_block (READ, 1, &bh);
        !           531:   wait_on_buffer (bh);
        !           532:   err = check_for_error (READ, 1, &bh);
        !           533:   if (err)
        !           534:     {
        !           535:       __brelse (bh);
        !           536:       return NULL;
        !           537:     }
        !           538:   return bh;
        !           539: }
        !           540: 
        !           541: /* Return the block size for device DEV in *BSIZE and
        !           542:    log2(block size) in *BSHIFT.  */
        !           543: static inline void
        !           544: get_block_size (kdev_t dev, int *bsize, int *bshift)
        !           545: {
        !           546:   int i, size, shift;
        !           547: 
        !           548:   size = BLOCK_SIZE;
        !           549:   if (blksize_size[MAJOR (dev)]
        !           550:       && blksize_size[MAJOR (dev)][MINOR (dev)])
        !           551:     size = blksize_size[MAJOR (dev)][MINOR (dev)];
        !           552:   for (i = size, shift = 0; i != 1; shift++, i >>= 1)
        !           553:     ;
        !           554:   *bsize = size;
        !           555:   *bshift = shift;
        !           556: }
        !           557: 
        !           558: /* Enqueue request REQ on a driver's queue.  */
        !           559: static inline void
        !           560: enqueue_request (struct request *req)
        !           561: {
        !           562:   struct request *tmp;
        !           563:   struct blk_dev_struct *dev;
        !           564: 
        !           565:   dev = blk_dev + MAJOR (req->rq_dev);
        !           566:   cli ();
        !           567:   tmp = dev->current_request;
        !           568:   if (! tmp)
        !           569:     {
        !           570:       dev->current_request = req;
        !           571:       (*dev->request_fn) ();
        !           572:       sti ();
        !           573:       return;
        !           574:     }
        !           575:   while (tmp->next)
        !           576:     {
        !           577:       if ((IN_ORDER (tmp, req) || ! IN_ORDER (tmp, tmp->next))
        !           578:          && IN_ORDER (req, tmp->next))
        !           579:        break;
        !           580:       tmp = tmp->next;
        !           581:     }
        !           582:   req->next = tmp->next;
        !           583:   tmp->next = req;
        !           584:   if (scsi_major (MAJOR (req->rq_dev)))
        !           585:     (*dev->request_fn) ();
        !           586:   sti ();
        !           587: }
        !           588: 
        !           589: /* Perform the I/O operation RW on the buffer list BH
        !           590:    containing NR buffers.  */
        !           591: void
        !           592: ll_rw_block (int rw, int nr, struct buffer_head **bh)
        !           593: {
        !           594:   int i, bsize, bshift;
        !           595:   unsigned major;
        !           596:   struct request *r;
        !           597: 
        !           598:   r = (struct request *) linux_kmalloc (sizeof (struct request), GFP_KERNEL);
        !           599:   if (! r)
        !           600:     {
        !           601:       bh[0]->b_request = NULL;
        !           602:       return;
        !           603:     }
        !           604:   bh[0]->b_request = r;
        !           605: 
        !           606:   major = MAJOR (bh[0]->b_dev);
        !           607:   assert (major < MAX_BLKDEV);
        !           608: 
        !           609:   get_block_size (bh[0]->b_dev, &bsize, &bshift);
        !           610:   assert (bsize <= PAGE_SIZE);
        !           611: 
        !           612:   for (i = 0, r->nr_sectors = 0; i < nr - 1; i++)
        !           613:     {
        !           614:       r->nr_sectors += bh[i]->b_size >> 9;
        !           615:       bh[i]->b_reqnext = bh[i + 1];
        !           616:     }
        !           617:   r->nr_sectors += bh[i]->b_size >> 9;
        !           618:   bh[i]->b_reqnext = NULL;
        !           619: 
        !           620:   r->rq_status = RQ_ACTIVE;
        !           621:   r->rq_dev = bh[0]->b_dev;
        !           622:   r->cmd = rw;
        !           623:   r->errors = 0;
        !           624:   r->sector = bh[0]->b_blocknr << (bshift - 9);
        !           625:   r->current_nr_sectors = bh[0]->b_size >> 9;
        !           626:   r->buffer = bh[0]->b_data;
        !           627:   r->sem = bh[0]->b_sem;
        !           628:   r->bh = bh[0];
        !           629:   r->bhtail = bh[nr - 1];
        !           630:   r->next = NULL;
        !           631: 
        !           632:   enqueue_request (r);
        !           633: }
        !           634: 
        !           635: /* Maximum amount of data to write per invocation of the driver.  */
        !           636: #define WRITE_MAXPHYS  (VM_MAP_COPY_PAGE_LIST_MAX << PAGE_SHIFT)
        !           637: #define WRITE_MAXPHYSPG        (WRITE_MAXPHYS >> PAGE_SHIFT)
        !           638: 
        !           639: int linux_block_write_trace = 0;
        !           640: 
        !           641: /* Write COUNT bytes of data from user buffer BUF
        !           642:    to device specified by INODE at location specified by FILP.  */
        !           643: int
        !           644: block_write (struct inode *inode, struct file *filp,
        !           645:             const char *buf, int count)
        !           646: {
        !           647:   char *p;
        !           648:   int i, bsize, bmask, bshift;
        !           649:   int err = 0, have_page_list = 1;
        !           650:   int resid = count, unaligned;
        !           651:   int page_index, pages, amt, cnt, nbuf;
        !           652:   unsigned blk;
        !           653:   vm_map_copy_t copy;
        !           654:   struct request req;
        !           655:   struct semaphore sem;
        !           656:   struct name_map *np = filp->f_np;
        !           657:   struct buffer_head *bh, *bhp, **bhlist;
        !           658: 
        !           659:   /* Compute device block size.  */
        !           660:   get_block_size (inode->i_rdev, &bsize, &bshift);
        !           661:   assert (bsize <= PAGE_SIZE);
        !           662:   bmask = bsize - 1;
        !           663: 
        !           664:   copy = (vm_map_copy_t) buf;
        !           665:   assert (copy);
        !           666:   assert (copy->type == VM_MAP_COPY_PAGE_LIST);
        !           667: 
        !           668:   p = (char *) copy->offset;
        !           669:   pages = copy->cpy_npages;
        !           670:   blk = (filp->f_pos + bmask) >> bshift;
        !           671: 
        !           672:   if (linux_block_write_trace)
        !           673:     printf ("block_write: at %d: f_pos 0x%x, count %d, blk 0x%x, p 0x%x\n",
        !           674:            __LINE__, (unsigned) filp->f_pos, count, blk, p);
        !           675: 
        !           676:   /* Allocate buffer headers.  */
        !           677:   nbuf = ((round_page ((vm_offset_t) p + resid) - trunc_page ((vm_offset_t) p))
        !           678:          >> PAGE_SHIFT);
        !           679:   if (nbuf > WRITE_MAXPHYSPG)
        !           680:     nbuf = WRITE_MAXPHYSPG;
        !           681:   if ((filp->f_pos & bmask) || ((int) p & PAGE_MASK))
        !           682:     nbuf *= 2;
        !           683:   bh = (struct buffer_head *) kalloc ((sizeof (*bh) + sizeof (*bhlist))
        !           684:                                      * nbuf);
        !           685:   if (! bh)
        !           686:     {
        !           687:       err = -LINUX_ENOMEM;
        !           688:       goto out;
        !           689:     }
        !           690:   bhlist = (struct buffer_head **) (bh + nbuf);
        !           691: 
        !           692:   /* Write any partial block.  */
        !           693:   if (filp->f_pos & bmask)
        !           694:     {
        !           695:       char *b, *q;
        !           696:       int use_req;
        !           697: 
        !           698:       use_req = (disk_major (MAJOR (inode->i_rdev)) && ! np->read_only);
        !           699: 
        !           700:       amt = bsize - (filp->f_pos & bmask);
        !           701:       if (amt > resid)
        !           702:        amt = resid;
        !           703: 
        !           704:       if (linux_block_write_trace)
        !           705:        printf ("block_write: at %d: amt %d, resid %d\n",
        !           706:                __LINE__, amt, resid);
        !           707: 
        !           708:       if (use_req)
        !           709:        {
        !           710:          i = (amt + 511) & ~511;
        !           711:          req.buffer = b = alloc_buffer (i);
        !           712:          if (! b)
        !           713:            {
        !           714:              printf ("%s:%d: block_write: ran out of buffers\n",
        !           715:                      __FILE__, __LINE__);
        !           716:              err = -LINUX_ENOMEM;
        !           717:              goto out;
        !           718:            }
        !           719:          req.sector = filp->f_pos >> 9;
        !           720:          req.nr_sectors = i >> 9;
        !           721:          req.current_nr_sectors = i >> 9;
        !           722:          req.rq_status = RQ_ACTIVE;
        !           723:          req.rq_dev = inode->i_rdev;
        !           724:          req.cmd = READ;
        !           725:          req.errors = 0;
        !           726:          req.sem = &sem;
        !           727:          req.bh = NULL;
        !           728:          req.bhtail = NULL;
        !           729:          req.next = NULL;
        !           730: 
        !           731:          sem.count = 0;
        !           732:          sem.wait = NULL;
        !           733: 
        !           734:          enqueue_request (&req);
        !           735:          __down (&sem);
        !           736: 
        !           737:          if (req.errors)
        !           738:            {
        !           739:              free_buffer (b, i);
        !           740:              err = -LINUX_EIO;
        !           741:              goto out;
        !           742:            }
        !           743:          q = b + (filp->f_pos & 511);
        !           744:        }
        !           745:       else
        !           746:        {
        !           747:          i = bsize;
        !           748:          bhp = bh;
        !           749:          bhp->b_data = b = alloc_buffer (i);
        !           750:          if (! b)
        !           751:            {
        !           752:              err = -LINUX_ENOMEM;
        !           753:              goto out;
        !           754:            }
        !           755:          bhp->b_blocknr = filp->f_pos >> bshift;
        !           756:          bhp->b_dev = inode->i_rdev;
        !           757:          bhp->b_size = bsize;
        !           758:          bhp->b_state = 1 << BH_Lock;
        !           759:          bhp->b_page_list = NULL;
        !           760:          bhp->b_request = NULL;
        !           761:          bhp->b_reqnext = NULL;
        !           762:          bhp->b_wait = NULL;
        !           763:          bhp->b_sem = NULL;
        !           764: 
        !           765:          ll_rw_block (READ, 1, &bhp);
        !           766:          wait_on_buffer (bhp);
        !           767:          err = check_for_error (READ, 1, &bhp);
        !           768:          if (err)
        !           769:            {
        !           770:              free_buffer (b, i);
        !           771:              goto out;
        !           772:            }
        !           773:          q = b + (filp->f_pos & bmask);
        !           774:        }
        !           775: 
        !           776:       cnt = PAGE_SIZE - ((int) p & PAGE_MASK);
        !           777:       if (cnt > amt)
        !           778:        cnt = amt;
        !           779:       memcpy (q, ((void *) copy->cpy_page_list[0]->phys_addr
        !           780:                  + ((int) p & PAGE_MASK)),
        !           781:              cnt);
        !           782:       if (cnt < amt)
        !           783:        {
        !           784:          assert (copy->cpy_npages >= 2);
        !           785:          memcpy (q + cnt,
        !           786:                  (void *) copy->cpy_page_list[1]->phys_addr, amt - cnt);
        !           787:        }
        !           788:       else
        !           789:        assert (copy->cpy_npages >= 1);
        !           790: 
        !           791:       if (use_req)
        !           792:        {
        !           793:          req.buffer = b;
        !           794:          req.sector = filp->f_pos >> 9;
        !           795:          req.nr_sectors = i >> 9;
        !           796:          req.current_nr_sectors = i >> 9;
        !           797:          req.rq_status = RQ_ACTIVE;
        !           798:          req.rq_dev = inode->i_rdev;
        !           799:          req.cmd = WRITE;
        !           800:          req.errors = 0;
        !           801:          req.sem = &sem;
        !           802:          req.bh = NULL;
        !           803:          req.bhtail = NULL;
        !           804:          req.next = NULL;
        !           805: 
        !           806:          sem.count = 0;
        !           807:          sem.wait = NULL;
        !           808: 
        !           809:          enqueue_request (&req);
        !           810:          __down (&sem);
        !           811: 
        !           812:          if (req.errors)
        !           813:            err = -LINUX_EIO;
        !           814:        }
        !           815:       else
        !           816:        {
        !           817:          bhp->b_state = (1 << BH_Dirty) | (1 << BH_Lock);
        !           818:          ll_rw_block (WRITE, 1, &bhp);
        !           819:          err = check_for_error (WRITE, 1, &bhp);
        !           820:        }
        !           821:       free_buffer (b, i);
        !           822:       if (err)
        !           823:        {
        !           824:          if (linux_block_write_trace)
        !           825:            printf ("block_write: at %d\n", __LINE__);
        !           826: 
        !           827:          goto out;
        !           828:        }
        !           829:       resid -= amt;
        !           830:       if (resid == 0)
        !           831:        goto out;
        !           832:       p += amt;
        !           833:     }
        !           834: 
        !           835:   unaligned = (int) p & 511;
        !           836: 
        !           837:   /* Write full blocks.  */
        !           838:   while (resid > bsize)
        !           839:     {
        !           840:       assert (have_page_list == 1);
        !           841: 
        !           842:       /* Construct buffer list.  */
        !           843:       for (i = 0, bhp = bh; resid > bsize && i < nbuf; i++, bhp++)
        !           844:        {
        !           845:          page_index = ((trunc_page ((vm_offset_t) p)
        !           846:                         - trunc_page (copy->offset))
        !           847:                        >> PAGE_SHIFT);
        !           848: 
        !           849:          if (page_index == pages)
        !           850:            break;
        !           851: 
        !           852:          bhlist[i] = bhp;
        !           853:          bhp->b_dev = inode->i_rdev;
        !           854:          bhp->b_state = (1 << BH_Dirty) | (1 << BH_Lock);
        !           855:          bhp->b_blocknr = blk;
        !           856:          bhp->b_wait = NULL;
        !           857:          bhp->b_page_list = NULL;
        !           858:          bhp->b_sem = &sem;
        !           859: 
        !           860:          cnt = PAGE_SIZE - ((int) p & PAGE_MASK);
        !           861:          if (! unaligned && cnt >= bsize)
        !           862:            {
        !           863:              if (cnt > resid)
        !           864:                cnt = resid;
        !           865:              bhp->b_size = cnt & ~bmask;
        !           866:              bhp->b_data = (((char *)
        !           867:                              copy->cpy_page_list[page_index]->phys_addr)
        !           868:                             + ((int) p & PAGE_MASK));
        !           869:            }
        !           870:          else
        !           871:            {
        !           872:              if (cnt < bsize)
        !           873:                {
        !           874:                  if (page_index == pages - 1)
        !           875:                    break;
        !           876:                  bhp->b_size = bsize;
        !           877:                }
        !           878:              else
        !           879:                {
        !           880:                  bhp->b_size = cnt;
        !           881:                  if (bhp->b_size > resid)
        !           882:                    bhp->b_size = resid;
        !           883:                  bhp->b_size &= ~bmask;
        !           884:                }
        !           885:              bhp->b_data = alloc_buffer (bhp->b_size);
        !           886:              if (! bhp->b_data)
        !           887:                {
        !           888:                  printf ("%s:%d: block_write: ran out of buffers\n",
        !           889:                          __FILE__, __LINE__);
        !           890:                  while (--i >= 0)
        !           891:                    if (bhlist[i]->b_page_list)
        !           892:                      free_buffer (bhlist[i]->b_data, bhlist[i]->b_size);
        !           893:                  err = -LINUX_ENOMEM;
        !           894:                  goto out;
        !           895:                }
        !           896:              bhp->b_page_list = (void *) 1;
        !           897:              if (cnt > bhp->b_size)
        !           898:                cnt = bhp->b_size;
        !           899:              memcpy (bhp->b_data,
        !           900:                      ((void *) copy->cpy_page_list[page_index]->phys_addr
        !           901:                       + ((int) p & PAGE_MASK)),
        !           902:                      cnt);
        !           903:              if (cnt < bhp->b_size)
        !           904:                memcpy (bhp->b_data + cnt,
        !           905:                        ((void *)
        !           906:                         copy->cpy_page_list[page_index + 1]->phys_addr),
        !           907:                        bhp->b_size - cnt);
        !           908:            }
        !           909: 
        !           910:          p += bhp->b_size;
        !           911:          resid -= bhp->b_size;
        !           912:          blk += bhp->b_size >> bshift;
        !           913:        }
        !           914: 
        !           915:       assert (i > 0);
        !           916: 
        !           917:       sem.count = 0;
        !           918:       sem.wait = NULL;
        !           919: 
        !           920:       /* Do the write.  */
        !           921:       ll_rw_block (WRITE, i, bhlist);
        !           922:       __down (&sem);
        !           923:       err = check_for_error (WRITE, i, bhlist);
        !           924:       if (err || resid == 0)
        !           925:        goto out;
        !           926: 
        !           927:       /* Discard current page list.  */
        !           928:       vm_map_copy_discard (copy);
        !           929:       have_page_list = 0;
        !           930: 
        !           931:       /* Compute # pages to wire down.  */
        !           932:       pages = ((round_page ((vm_offset_t) p + resid)
        !           933:                - trunc_page ((vm_offset_t) p))
        !           934:               >> PAGE_SHIFT);
        !           935:       if (pages > WRITE_MAXPHYSPG)
        !           936:        pages = WRITE_MAXPHYSPG;
        !           937: 
        !           938:       /* Wire down user pages and get page list.  */
        !           939:       err = vm_map_copyin_page_list (current_map (),
        !           940:                                     trunc_page ((vm_offset_t) p),
        !           941:                                     pages << PAGE_SHIFT, FALSE,
        !           942:                                     FALSE, &copy, FALSE);
        !           943:       if (err)
        !           944:        {
        !           945:          if (err == KERN_INVALID_ADDRESS || err == KERN_PROTECTION_FAILURE)
        !           946:            err = -LINUX_EINVAL;
        !           947:          else
        !           948:            err = -LINUX_ENOMEM;
        !           949:          goto out;
        !           950:        }
        !           951: 
        !           952:       assert (pages == copy->cpy_npages);
        !           953:       assert (! vm_map_copy_has_cont (copy));
        !           954: 
        !           955:       have_page_list = 1;
        !           956:     }
        !           957: 
        !           958:   /* Write any partial count.  */
        !           959:   if (resid > 0)
        !           960:     {
        !           961:       char *b;
        !           962:       int use_req;
        !           963: 
        !           964:       assert (have_page_list);
        !           965:       assert (pages >= 1);
        !           966: 
        !           967:       use_req = (disk_major (MAJOR (inode->i_rdev)) && ! np->read_only);
        !           968: 
        !           969:       if (linux_block_write_trace)
        !           970:        printf ("block_write: at %d: resid %d\n", __LINE__, resid);
        !           971: 
        !           972:       if (use_req)
        !           973:        {
        !           974:          i = (resid + 511) & ~511;
        !           975:          req.buffer = b = alloc_buffer (i);
        !           976:          if (! b)
        !           977:            {
        !           978:              printf ("%s:%d: block_write: ran out of buffers\n",
        !           979:                      __FILE__, __LINE__);
        !           980:              err = -LINUX_ENOMEM;
        !           981:              goto out;
        !           982:            }
        !           983:          req.sector = blk << (bshift - 9);
        !           984:          req.nr_sectors = i >> 9;
        !           985:          req.current_nr_sectors = i >> 9;
        !           986:          req.rq_status = RQ_ACTIVE;
        !           987:          req.rq_dev = inode->i_rdev;
        !           988:          req.cmd = READ;
        !           989:          req.errors = 0;
        !           990:          req.sem = &sem;
        !           991:          req.bh = NULL;
        !           992:          req.bhtail = NULL;
        !           993:          req.next = NULL;
        !           994: 
        !           995:          sem.count = 0;
        !           996:          sem.wait = NULL;
        !           997: 
        !           998:          enqueue_request (&req);
        !           999:          __down (&sem);
        !          1000: 
        !          1001:          if (req.errors)
        !          1002:            {
        !          1003:              free_buffer (b, i);
        !          1004:              err = -LINUX_EIO;
        !          1005:              goto out;
        !          1006:            }
        !          1007:        }
        !          1008:       else
        !          1009:        {
        !          1010:          i = bsize;
        !          1011:          bhp = bh;
        !          1012:          bhp->b_data = b = alloc_buffer (i);
        !          1013:          if (! b)
        !          1014:            {
        !          1015:              err = -LINUX_ENOMEM;
        !          1016:              goto out;
        !          1017:            }
        !          1018:          bhp->b_blocknr = blk;
        !          1019:          bhp->b_dev = inode->i_rdev;
        !          1020:          bhp->b_size = bsize;
        !          1021:          bhp->b_state = 1 << BH_Lock;
        !          1022:          bhp->b_page_list = NULL;
        !          1023:          bhp->b_request = NULL;
        !          1024:          bhp->b_reqnext = NULL;
        !          1025:          bhp->b_wait = NULL;
        !          1026:          bhp->b_sem = NULL;
        !          1027: 
        !          1028:          ll_rw_block (READ, 1, &bhp);
        !          1029:          wait_on_buffer (bhp);
        !          1030:          err = check_for_error (READ, 1, &bhp);
        !          1031:          if (err)
        !          1032:            {
        !          1033:              free_buffer (b, i);
        !          1034:              goto out;
        !          1035:            }
        !          1036:        }
        !          1037: 
        !          1038:       page_index = ((trunc_page ((vm_offset_t) p) - trunc_page (copy->offset))
        !          1039:                    >> PAGE_SHIFT);
        !          1040:       cnt = PAGE_SIZE - ((int) p & PAGE_MASK);
        !          1041:       if (cnt > resid)
        !          1042:        cnt = resid;
        !          1043:       memcpy (b, ((void *) copy->cpy_page_list[page_index]->phys_addr
        !          1044:                  + ((int) p & PAGE_MASK)),
        !          1045:              cnt);
        !          1046:       if (cnt < resid)
        !          1047:        {
        !          1048:          assert (copy->cpy_npages >= 2);
        !          1049:          memcpy (b + cnt,
        !          1050:                  (void *) copy->cpy_page_list[page_index + 1]->phys_addr,
        !          1051:                  resid - cnt);
        !          1052:        }
        !          1053:       else
        !          1054:        assert (copy->cpy_npages >= 1);
        !          1055: 
        !          1056:       if (use_req)
        !          1057:        {
        !          1058:          req.buffer = b;
        !          1059:          req.sector = blk << (bshift - 9);
        !          1060:          req.nr_sectors = i >> 9;
        !          1061:          req.current_nr_sectors = i >> 9;
        !          1062:          req.rq_status = RQ_ACTIVE;
        !          1063:          req.rq_dev = inode->i_rdev;
        !          1064:          req.cmd = WRITE;
        !          1065:          req.errors = 0;
        !          1066:          req.sem = &sem;
        !          1067:          req.bh = NULL;
        !          1068:          req.bhtail = NULL;
        !          1069:          req.next = NULL;
        !          1070: 
        !          1071:          sem.count = 0;
        !          1072:          sem.wait = NULL;
        !          1073: 
        !          1074:          enqueue_request (&req);
        !          1075:          __down (&sem);
        !          1076: 
        !          1077:          if (req.errors)
        !          1078:            err = -LINUX_EIO;
        !          1079:        }
        !          1080:       else
        !          1081:        {
        !          1082:          bhp->b_state = (1 << BH_Dirty) | (1 << BH_Lock);
        !          1083:          ll_rw_block (WRITE, 1, &bhp);
        !          1084:          err = check_for_error (WRITE, 1, &bhp);
        !          1085:        }
        !          1086:       free_buffer (b, i);
        !          1087:       if (! err)
        !          1088:        resid = 0;
        !          1089:     }
        !          1090: 
        !          1091: out:
        !          1092:   if (have_page_list)
        !          1093:     vm_map_copy_discard (copy);
        !          1094:   if (bh)
        !          1095:     kfree ((vm_offset_t) bh,
        !          1096:           (sizeof (*bh) + sizeof (*bhlist)) * nbuf);
        !          1097:   filp->f_resid = resid;
        !          1098:   return err;
        !          1099: }
        !          1100: 
        !          1101: int linux_block_read_trace = 0;
        !          1102: #define LINUX_BLOCK_READ_TRACE (linux_block_read_trace == -1 \
        !          1103:                                || linux_block_read_trace == inode->i_rdev)
        !          1104: 
        !          1105: /* Maximum amount of data to read per driver invocation.  */
        !          1106: #define READ_MAXPHYS   (64*1024)
        !          1107: #define READ_MAXPHYSPG (READ_MAXPHYS >> PAGE_SHIFT)
        !          1108: 
        !          1109: /* Read COUNT bytes of data into user buffer BUF
        !          1110:    from device specified by INODE from location specified by FILP.  */
        !          1111: int
        !          1112: block_read (struct inode *inode, struct file *filp, char *buf, int count)
        !          1113: {
        !          1114:   int err = 0, resid = count;
        !          1115:   int i, bsize, bmask, bshift;
        !          1116:   int pages, amt, unaligned;
        !          1117:   int page_index, nbuf;
        !          1118:   int have_page_list = 0;
        !          1119:   unsigned blk;
        !          1120:   vm_offset_t off, wire_offset, offset;
        !          1121:   vm_object_t object;
        !          1122:   vm_page_t *page_list;
        !          1123:   struct request req;
        !          1124:   struct semaphore sem;
        !          1125:   struct name_map *np = filp->f_np;
        !          1126:   struct buffer_head *bh, *bhp, **bhlist;
        !          1127: 
        !          1128:   /* Get device block size.  */
        !          1129:   get_block_size (inode->i_rdev, &bsize, &bshift);
        !          1130:   assert (bsize <= PAGE_SIZE);
        !          1131:   bmask = bsize - 1;
        !          1132: 
        !          1133:   off = 0;
        !          1134:   blk = (filp->f_pos + bmask) >> bshift;
        !          1135: 
        !          1136:   /* Allocate buffer headers.  */
        !          1137:   nbuf = round_page (count) >> PAGE_SHIFT;
        !          1138:   if (nbuf > READ_MAXPHYSPG)
        !          1139:     nbuf = READ_MAXPHYSPG;
        !          1140:   if (filp->f_pos & bmask)
        !          1141:     nbuf *= 2;
        !          1142:   bh = (struct buffer_head *) kalloc ((sizeof (*bh) + sizeof (*bhlist)) * nbuf
        !          1143:                                      + sizeof (*page_list) * READ_MAXPHYSPG);
        !          1144:   if (! bh)
        !          1145:     return -LINUX_ENOMEM;
        !          1146:   bhlist = (struct buffer_head **) (bh + nbuf);
        !          1147:   page_list = (vm_page_t *) (bhlist + nbuf);
        !          1148: 
        !          1149:   /* Allocate an object to hold the data.  */
        !          1150:   object = vm_object_allocate (round_page (count));
        !          1151:   if (! object)
        !          1152:     {
        !          1153:       err = -LINUX_ENOMEM;
        !          1154:       goto out;
        !          1155:     }
        !          1156: 
        !          1157:   /* Compute number of pages to be wired at a time.  */
        !          1158:   pages = round_page (count) >> PAGE_SHIFT;
        !          1159:   if (pages > READ_MAXPHYSPG)
        !          1160:     pages = READ_MAXPHYSPG;
        !          1161: 
        !          1162:   /* Allocate and wire down pages in the object.  */
        !          1163:   for (i = 0, wire_offset = offset = 0; i < pages; i++, offset += PAGE_SIZE)
        !          1164:     {
        !          1165:       while (1)
        !          1166:        {
        !          1167:          page_list[i] = vm_page_grab ();
        !          1168:          if (page_list[i])
        !          1169:            {
        !          1170:              assert (page_list[i]->busy);
        !          1171:              assert (! page_list[i]->wanted);
        !          1172:              break;
        !          1173:            }
        !          1174:          vm_page_wait (NULL);
        !          1175:        }
        !          1176:       vm_object_lock (object);
        !          1177:       vm_page_lock_queues ();
        !          1178:       assert (! vm_page_lookup (object, offset));
        !          1179:       vm_page_insert (page_list[i], object, offset);
        !          1180:       assert (page_list[i]->wire_count == 0);
        !          1181:       vm_page_wire (page_list[i]);
        !          1182:       vm_page_unlock_queues ();
        !          1183:       vm_object_unlock (object);
        !          1184:     }
        !          1185:   have_page_list = 1;
        !          1186: 
        !          1187:   /* Read any partial block.  */
        !          1188:   if (filp->f_pos & bmask)
        !          1189:     {
        !          1190:       char *b, *q;
        !          1191:       int use_req;
        !          1192: 
        !          1193:       use_req = (disk_major (MAJOR (inode->i_rdev)) && ! np->read_only);
        !          1194: 
        !          1195:       amt = bsize - (filp->f_pos & bmask);
        !          1196:       if (amt > resid)
        !          1197:        amt = resid;
        !          1198: 
        !          1199:       if (LINUX_BLOCK_READ_TRACE)
        !          1200:        printf ("block_read: at %d: amt %d, resid %d\n",
        !          1201:                __LINE__, amt, resid);
        !          1202: 
        !          1203:       if (use_req)
        !          1204:        {
        !          1205:          i = (amt + 511) & ~511;
        !          1206:          req.buffer = b = alloc_buffer (i);
        !          1207:          if (! b)
        !          1208:            {
        !          1209:              printf ("%s:%d: block_read: ran out of buffers\n",
        !          1210:                      __FILE__, __LINE__);
        !          1211:              err = -LINUX_ENOMEM;
        !          1212:              goto out;
        !          1213:            }
        !          1214:          req.sector = filp->f_pos >> 9;
        !          1215:          req.nr_sectors = i >> 9;
        !          1216:          req.current_nr_sectors = i >> 9;
        !          1217:          req.rq_status = RQ_ACTIVE;
        !          1218:          req.rq_dev = inode->i_rdev;
        !          1219:          req.cmd = READ;
        !          1220:          req.errors = 0;
        !          1221:          req.sem = &sem;
        !          1222:          req.bh = NULL;
        !          1223:          req.bhtail = NULL;
        !          1224:          req.next = NULL;
        !          1225: 
        !          1226:          sem.count = 0;
        !          1227:          sem.wait = NULL;
        !          1228: 
        !          1229:          enqueue_request (&req);
        !          1230:          __down (&sem);
        !          1231: 
        !          1232:          if (req.errors)
        !          1233:            {
        !          1234:              free_buffer (b, i);
        !          1235:              err = -LINUX_EIO;
        !          1236:              goto out;
        !          1237:            }
        !          1238:          q = b + (filp->f_pos & 511);
        !          1239:        }
        !          1240:       else
        !          1241:        {
        !          1242:          i = bsize;
        !          1243:          bhp = bh;
        !          1244:          bhp->b_data = b = alloc_buffer (i);
        !          1245:          if (! b)
        !          1246:            {
        !          1247:              err = -LINUX_ENOMEM;
        !          1248:              goto out;
        !          1249:            }
        !          1250:          bhp->b_blocknr = filp->f_pos >> bshift;
        !          1251:          bhp->b_dev = inode->i_rdev;
        !          1252:          bhp->b_size = bsize;
        !          1253:          bhp->b_state = 1 << BH_Lock;
        !          1254:          bhp->b_page_list = NULL;
        !          1255:          bhp->b_request = NULL;
        !          1256:          bhp->b_reqnext = NULL;
        !          1257:          bhp->b_wait = NULL;
        !          1258:          bhp->b_sem = NULL;
        !          1259: 
        !          1260:          ll_rw_block (READ, 1, &bhp);
        !          1261:          wait_on_buffer (bhp);
        !          1262:          err = check_for_error (READ, 1, &bhp);
        !          1263:          if (err)
        !          1264:            {
        !          1265:              free_buffer (b, i);
        !          1266:              goto out;
        !          1267:            }
        !          1268:          q = b + (filp->f_pos & bmask);
        !          1269:        }
        !          1270: 
        !          1271:       memcpy ((void *) page_list[0]->phys_addr, q, amt);
        !          1272: 
        !          1273:       free_buffer (b, i);
        !          1274:       resid -= amt;
        !          1275:       if (resid == 0)
        !          1276:        {
        !          1277:          if (LINUX_BLOCK_READ_TRACE)
        !          1278:            printf ("block_read: at %d\n", __LINE__);
        !          1279: 
        !          1280:          assert (pages == 1);
        !          1281:          goto out;
        !          1282:        }
        !          1283:       off += amt;
        !          1284:     }
        !          1285: 
        !          1286:   unaligned = off & 511;
        !          1287: 
        !          1288:   /* Read full blocks.  */
        !          1289:   while (resid > bsize)
        !          1290:     {
        !          1291:       /* Construct buffer list to hand to the driver.  */
        !          1292:       for (i = 0, bhp = bh; resid > bsize && i < nbuf; bhp++, i++)
        !          1293:        {
        !          1294:          if (off == wire_offset + (pages << PAGE_SHIFT))
        !          1295:            break;
        !          1296: 
        !          1297:          bhlist[i] = bhp;
        !          1298:          bhp->b_dev = inode->i_rdev;
        !          1299:          bhp->b_state = 1 << BH_Lock;
        !          1300:          bhp->b_blocknr = blk;
        !          1301:          bhp->b_wait = NULL;
        !          1302:          bhp->b_sem = &sem;
        !          1303: 
        !          1304:          page_index = (trunc_page (off) - wire_offset) >> PAGE_SHIFT;
        !          1305:          amt = PAGE_SIZE - (off & PAGE_MASK);
        !          1306:          if (! unaligned && amt >= bsize)
        !          1307:            {
        !          1308:              if (amt > resid)
        !          1309:                amt = resid;
        !          1310:              bhp->b_size = amt & ~bmask;
        !          1311:              bhp->b_data = ((char *) page_list[page_index]->phys_addr
        !          1312:                             + (off & PAGE_MASK));
        !          1313:              bhp->b_page_list = NULL;
        !          1314:            }
        !          1315:          else
        !          1316:            {
        !          1317:              if (amt < bsize)
        !          1318:                {
        !          1319:                  if (page_index == pages - 1)
        !          1320:                    {
        !          1321:                      assert (round_page (count) - off >= resid);
        !          1322:                      break;
        !          1323:                    }
        !          1324:                  bhp->b_size = bsize;
        !          1325:                }
        !          1326:              else
        !          1327:                {
        !          1328:                  if (amt > resid)
        !          1329:                    amt = resid;
        !          1330:                  bhp->b_size = amt & ~bmask;
        !          1331:                }
        !          1332:              bhp->b_data = alloc_buffer (bhp->b_size);
        !          1333:              if (! bhp->b_data)
        !          1334:                {
        !          1335:                  printf ("%s:%d: block_read: ran out of buffers\n",
        !          1336:                          __FILE__, __LINE__);
        !          1337: 
        !          1338:                  while (--i >= 0)
        !          1339:                    if (bhp->b_page_list)
        !          1340:                      free_buffer (bhp->b_data, bhp->b_size);
        !          1341:                  err = -LINUX_ENOMEM;
        !          1342:                  goto out;
        !          1343:                }
        !          1344:              bhp->b_page_list = page_list;
        !          1345:              bhp->b_index = page_index;
        !          1346:              bhp->b_off = off & PAGE_MASK;
        !          1347:              bhp->b_usrcnt = bhp->b_size;
        !          1348:            }
        !          1349: 
        !          1350:          resid -= bhp->b_size;
        !          1351:          off += bhp->b_size;
        !          1352:          blk += bhp->b_size >> bshift;
        !          1353:        }
        !          1354: 
        !          1355:       assert (i > 0);
        !          1356: 
        !          1357:       sem.count = 0;
        !          1358:       sem.wait = NULL;
        !          1359: 
        !          1360:       /* Do the read.  */
        !          1361:       ll_rw_block (READ, i, bhlist);
        !          1362:       __down (&sem);
        !          1363:       err = check_for_error (READ, i, bhlist);
        !          1364:       if (err || resid == 0)
        !          1365:        goto out;
        !          1366: 
        !          1367:       /* Unwire the pages and mark them dirty.  */
        !          1368:       offset = trunc_page (off);
        !          1369:       for (i = 0; wire_offset < offset; i++, wire_offset += PAGE_SIZE)
        !          1370:        {
        !          1371:          vm_object_lock (object);
        !          1372:          vm_page_lock_queues ();
        !          1373:          assert (vm_page_lookup (object, wire_offset) == page_list[i]);
        !          1374:          assert (page_list[i]->wire_count == 1);
        !          1375:          assert (! page_list[i]->active && ! page_list[i]->inactive);
        !          1376:          assert (! page_list[i]->reference);
        !          1377:          page_list[i]->dirty = TRUE;
        !          1378:          page_list[i]->reference = TRUE;
        !          1379:          page_list[i]->busy = FALSE;
        !          1380:          vm_page_unwire (page_list[i]);
        !          1381:          vm_page_unlock_queues ();
        !          1382:          vm_object_unlock (object);
        !          1383:        }
        !          1384: 
        !          1385:       assert (i <= pages);
        !          1386: 
        !          1387:       /* Wire down the next chunk of the object.  */
        !          1388:       if (i == pages)
        !          1389:        {
        !          1390:          i = 0;
        !          1391:          offset = wire_offset;
        !          1392:          have_page_list = 0;
        !          1393:        }
        !          1394:       else
        !          1395:        {
        !          1396:          int j;
        !          1397: 
        !          1398:          for (j = 0; i < pages; page_list[j++] = page_list[i++])
        !          1399:            offset += PAGE_SIZE;
        !          1400:          i = j;
        !          1401:        }
        !          1402:       pages = (round_page (count) - wire_offset) >> PAGE_SHIFT;
        !          1403:       if (pages > READ_MAXPHYSPG)
        !          1404:        pages = READ_MAXPHYSPG;
        !          1405:       while (i < pages)
        !          1406:        {
        !          1407:          while (1)
        !          1408:            {
        !          1409:              page_list[i] = vm_page_grab ();
        !          1410:              if (page_list[i])
        !          1411:                {
        !          1412:                  assert (page_list[i]->busy);
        !          1413:                  assert (! page_list[i]->wanted);
        !          1414:                  break;
        !          1415:                }
        !          1416:              vm_page_wait (NULL);
        !          1417:            }
        !          1418:          vm_object_lock (object);
        !          1419:          vm_page_lock_queues ();
        !          1420:          assert (! vm_page_lookup (object, offset));
        !          1421:          vm_page_insert (page_list[i], object, offset);
        !          1422:          assert (page_list[i]->wire_count == 0);
        !          1423:          vm_page_wire (page_list[i]);
        !          1424:          vm_page_unlock_queues ();
        !          1425:          vm_object_unlock (object);
        !          1426:          i++;
        !          1427:          offset += PAGE_SIZE;
        !          1428:        }
        !          1429:       have_page_list = 1;
        !          1430:     }
        !          1431: 
        !          1432:   /* Read any partial count.  */
        !          1433:   if (resid > 0)
        !          1434:     {
        !          1435:       char *b;
        !          1436:       int use_req;
        !          1437: 
        !          1438:       assert (have_page_list);
        !          1439:       assert (pages >= 1);
        !          1440: 
        !          1441:       use_req = (disk_major (MAJOR (inode->i_rdev)) && ! np->read_only);
        !          1442: 
        !          1443:       amt = bsize - (filp->f_pos & bmask);
        !          1444:       if (amt > resid)
        !          1445:        amt = resid;
        !          1446: 
        !          1447:       if (LINUX_BLOCK_READ_TRACE)
        !          1448:        printf ("block_read: at %d: resid %d\n", __LINE__, amt, resid);
        !          1449: 
        !          1450:       if (use_req)
        !          1451:        {
        !          1452:          i = (resid + 511) & ~511;
        !          1453:          req.buffer = b = alloc_buffer (i);
        !          1454:          if (! b)
        !          1455:            {
        !          1456:              printf ("%s:%d: block_read: ran out of buffers\n",
        !          1457:                      __FILE__, __LINE__);
        !          1458:              err = -LINUX_ENOMEM;
        !          1459:              goto out;
        !          1460:            }
        !          1461:          req.sector = blk << (bshift - 9);
        !          1462:          req.nr_sectors = i >> 9;
        !          1463:          req.current_nr_sectors = i >> 9;
        !          1464:          req.rq_status = RQ_ACTIVE;
        !          1465:          req.rq_dev = inode->i_rdev;
        !          1466:          req.cmd = READ;
        !          1467:          req.errors = 0;
        !          1468:          req.sem = &sem;
        !          1469:          req.bh = NULL;
        !          1470:          req.bhtail = NULL;
        !          1471:          req.next = NULL;
        !          1472: 
        !          1473:          sem.count = 0;
        !          1474:          sem.wait = NULL;
        !          1475: 
        !          1476:          enqueue_request (&req);
        !          1477:          __down (&sem);
        !          1478: 
        !          1479:          if (req.errors)
        !          1480:            {
        !          1481:              free_buffer (b, i);
        !          1482:              err = -LINUX_EIO;
        !          1483:              goto out;
        !          1484:            }
        !          1485:        }
        !          1486:       else
        !          1487:        {
        !          1488:          i = bsize;
        !          1489:          bhp = bh;
        !          1490:          bhp->b_data = b = alloc_buffer (i);
        !          1491:          if (! b)
        !          1492:            {
        !          1493:              err = -LINUX_ENOMEM;
        !          1494:              goto out;
        !          1495:            }
        !          1496:          bhp->b_blocknr = blk;
        !          1497:          bhp->b_dev = inode->i_rdev;
        !          1498:          bhp->b_size = bsize;
        !          1499:          bhp->b_state = 1 << BH_Lock;
        !          1500:          bhp->b_page_list = NULL;
        !          1501:          bhp->b_request = NULL;
        !          1502:          bhp->b_reqnext = NULL;
        !          1503:          bhp->b_wait = NULL;
        !          1504:          bhp->b_sem = NULL;
        !          1505: 
        !          1506:          ll_rw_block (READ, 1, &bhp);
        !          1507:          wait_on_buffer (bhp);
        !          1508:          err = check_for_error (READ, 1, &bhp);
        !          1509:          if (err)
        !          1510:            {
        !          1511:              free_buffer (b, i);
        !          1512:              goto out;
        !          1513:            }
        !          1514:        }
        !          1515: 
        !          1516:       page_index = (trunc_page (off) - wire_offset) >> PAGE_SHIFT;
        !          1517:       amt = PAGE_SIZE - (off & PAGE_MASK);
        !          1518:       if (amt > resid)
        !          1519:        amt = resid;
        !          1520:       memcpy (((void *) page_list[page_index]->phys_addr
        !          1521:               + (off & PAGE_MASK)),
        !          1522:              b, amt);
        !          1523:       if (amt < resid)
        !          1524:        {
        !          1525:          assert (pages >= 2);
        !          1526:          memcpy ((void *) page_list[page_index + 1]->phys_addr,
        !          1527:                  b + amt, resid - amt);
        !          1528:        }
        !          1529:       else
        !          1530:        assert (pages >= 1);
        !          1531: 
        !          1532:       free_buffer (b, i);
        !          1533:     }
        !          1534: 
        !          1535: out:
        !          1536:   if (have_page_list)
        !          1537:     {
        !          1538:       for (i = 0; i < pages; i++, wire_offset += PAGE_SIZE)
        !          1539:        {
        !          1540:          vm_object_lock (object);
        !          1541:          vm_page_lock_queues ();
        !          1542:          assert (vm_page_lookup (object, wire_offset) == page_list[i]);
        !          1543:          assert (page_list[i]->wire_count == 1);
        !          1544:          assert (! page_list[i]->active && ! page_list[i]->inactive);
        !          1545:          assert (! page_list[i]->reference);
        !          1546:          page_list[i]->dirty = TRUE;
        !          1547:          page_list[i]->reference = TRUE;
        !          1548:          page_list[i]->busy = FALSE;
        !          1549:          vm_page_unwire (page_list[i]);
        !          1550:          vm_page_unlock_queues ();
        !          1551:          vm_object_unlock (object);
        !          1552:        }
        !          1553:     }      
        !          1554:   kfree ((vm_offset_t) bh,
        !          1555:         ((sizeof (*bh) + sizeof (*bhlist)) * nbuf
        !          1556:          + sizeof (*page_list) * READ_MAXPHYSPG));
        !          1557:   if (err)
        !          1558:     {
        !          1559:       if (object)
        !          1560:        {
        !          1561:          assert (object->ref_count == 1);
        !          1562:          vm_object_deallocate (object);
        !          1563:        }
        !          1564:     }
        !          1565:   else
        !          1566:     {
        !          1567:       assert (object);
        !          1568:       assert (object->ref_count == 1);
        !          1569: 
        !          1570:       filp->f_resid = 0;
        !          1571:       filp->f_object = object;
        !          1572:     }
        !          1573: 
        !          1574:   if (LINUX_BLOCK_READ_TRACE)
        !          1575:     printf ("block_read: at %d: err %d\n", __LINE__, err);
        !          1576: 
        !          1577:   return err;
        !          1578: }
        !          1579: 
        !          1580: /*
        !          1581:  * This routine checks whether a removable media has been changed,
        !          1582:  * and invalidates all buffer-cache-entries in that case. This
        !          1583:  * is a relatively slow routine, so we have to try to minimize using
        !          1584:  * it. Thus it is called only upon a 'mount' or 'open'. This
        !          1585:  * is the best way of combining speed and utility, I think.
        !          1586:  * People changing diskettes in the middle of an operation deserve
        !          1587:  * to loose :-)
        !          1588:  */
        !          1589: int
        !          1590: check_disk_change (kdev_t dev)
        !          1591: {
        !          1592:   unsigned i;
        !          1593:   struct file_operations * fops;
        !          1594: 
        !          1595:   i = MAJOR(dev);
        !          1596:   if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
        !          1597:     return 0;
        !          1598:   if (fops->check_media_change == NULL)
        !          1599:     return 0;
        !          1600:   if (! (*fops->check_media_change) (dev))
        !          1601:     return 0;
        !          1602: 
        !          1603:   /*  printf ("Disk change detected on device %s\n", kdevname(dev));*/
        !          1604: 
        !          1605:   if (fops->revalidate)
        !          1606:     (*fops->revalidate) (dev);
        !          1607: 
        !          1608:   return 1;
        !          1609: }
        !          1610: 
        !          1611: /* Mach device interface routines.  */
        !          1612: 
        !          1613: /* Mach name to Linux major/minor number mapping table.  */
        !          1614: static struct name_map name_to_major[] =
        !          1615: {
        !          1616:   /* IDE disks */
        !          1617:   { "hd0", IDE0_MAJOR, 0, 0 },
        !          1618:   { "hd1", IDE0_MAJOR, 1, 0 },
        !          1619:   { "hd2", IDE1_MAJOR, 0, 0 },
        !          1620:   { "hd3", IDE1_MAJOR, 1, 0 },
        !          1621:   { "hd4", IDE2_MAJOR, 0, 0 },
        !          1622:   { "hd5", IDE2_MAJOR, 1, 0 },
        !          1623:   { "hd6", IDE3_MAJOR, 0, 0 },
        !          1624:   { "hd7", IDE3_MAJOR, 1, 0 },
        !          1625: 
        !          1626:   /* IDE CDROMs */
        !          1627:   { "wcd0", IDE0_MAJOR, 0, 1 },
        !          1628:   { "wcd1", IDE0_MAJOR, 1, 1 },
        !          1629:   { "wcd2", IDE1_MAJOR, 0, 1 },
        !          1630:   { "wcd3", IDE1_MAJOR, 1, 1 },
        !          1631:   { "wcd4", IDE2_MAJOR, 0, 1 },
        !          1632:   { "wcd5", IDE2_MAJOR, 1, 1 },
        !          1633:   { "wcd6", IDE3_MAJOR, 0, 1 },
        !          1634:   { "wcd7", IDE3_MAJOR, 1, 1 },
        !          1635: 
        !          1636:   /* SCSI disks */
        !          1637:   { "sd0", SCSI_DISK_MAJOR, 0, 0 },
        !          1638:   { "sd1", SCSI_DISK_MAJOR, 1, 0 },
        !          1639:   { "sd2", SCSI_DISK_MAJOR, 2, 0 },
        !          1640:   { "sd3", SCSI_DISK_MAJOR, 3, 0 },
        !          1641:   { "sd4", SCSI_DISK_MAJOR, 4, 0 },
        !          1642:   { "sd5", SCSI_DISK_MAJOR, 5, 0 },
        !          1643:   { "sd6", SCSI_DISK_MAJOR, 6, 0 },
        !          1644:   { "sd7", SCSI_DISK_MAJOR, 7, 0 },
        !          1645: 
        !          1646:   /* SCSI CDROMs */
        !          1647:   { "cd0", SCSI_CDROM_MAJOR, 0, 1 },
        !          1648:   { "cd1", SCSI_CDROM_MAJOR, 1, 1 },
        !          1649: 
        !          1650:   /* Floppy disks */
        !          1651:   { "fd0", FLOPPY_MAJOR, 0, 0 },
        !          1652:   { "fd1", FLOPPY_MAJOR, 1, 0 },
        !          1653: };
        !          1654: 
        !          1655: #define NUM_NAMES (sizeof (name_to_major) / sizeof (name_to_major[0]))
        !          1656: 
        !          1657: /* One of these is associated with each open instance of a device.  */
        !          1658: struct block_data
        !          1659: {
        !          1660:   const char *name;            /* Mach name for device */
        !          1661:   int want:1;                  /* someone is waiting for I/O to complete */
        !          1662:   int open_count;              /* number of opens */
        !          1663:   int iocount;                 /* number of pending I/O operations */
        !          1664:   int part;                    /* BSD partition number (-1 if none) */
        !          1665:   ipc_port_t port;             /* port representing device */
        !          1666:   struct device_struct *ds;    /* driver operation table entry */
        !          1667:   struct device device;                /* generic device header */
        !          1668:   struct file file;            /* Linux file structure */
        !          1669:   struct inode inode;          /* Linux inode structure */
        !          1670:   struct name_map *np;         /* name to inode map */
        !          1671:   struct block_data *next;     /* forward link */
        !          1672: };
        !          1673: 
        !          1674: /* List of open devices.  */
        !          1675: static struct block_data *open_list;
        !          1676: 
        !          1677: /* Forward declarations.  */
        !          1678: 
        !          1679: extern struct device_emulation_ops linux_block_emulation_ops;
        !          1680: 
        !          1681: static io_return_t device_close (void *);
        !          1682: 
        !          1683: /* Return a send right for block device BD.  */
        !          1684: static ipc_port_t
        !          1685: dev_to_port (void *bd)
        !          1686: {
        !          1687:   return (bd
        !          1688:          ? ipc_port_make_send (((struct block_data *) bd)->port)
        !          1689:          : IP_NULL);
        !          1690: }
        !          1691: 
        !          1692: /* Return 1 if C is a letter of the alphabet.  */
        !          1693: static inline int
        !          1694: isalpha (int c)
        !          1695: {
        !          1696:   return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
        !          1697: }
        !          1698: 
        !          1699: /* Return 1 if C is a digit.  */
        !          1700: static inline int
        !          1701: isdigit (int c)
        !          1702: {
        !          1703:   return c >= '0' && c <= '9';
        !          1704: }
        !          1705: 
        !          1706: int linux_device_open_trace = 0;
        !          1707: 
        !          1708: static io_return_t
        !          1709: device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
        !          1710:             dev_mode_t mode, char *name, device_t *devp)
        !          1711: {
        !          1712:   char *p;
        !          1713:   int i, part = -1, slice = 0, err = 0;
        !          1714:   unsigned major, minor;
        !          1715:   kdev_t dev;
        !          1716:   ipc_port_t notify;
        !          1717:   struct file file;
        !          1718:   struct inode inode;
        !          1719:   struct name_map *np;
        !          1720:   struct device_struct *ds;
        !          1721:   struct block_data *bd = NULL, *bdp;
        !          1722: 
        !          1723:   if (linux_device_open_trace)
        !          1724:     printf ("device_open: at %d: name %s\n", __LINE__, name);
        !          1725: 
        !          1726:   /* Parse name into name, unit, DOS partition (slice) and partition.  */
        !          1727:   for (p = name; isalpha (*p); p++)
        !          1728:     ;
        !          1729:   if (p == name || ! isdigit (*p))
        !          1730:     {
        !          1731:       if (linux_device_open_trace)
        !          1732:        printf ("device_open: at %d\n", __LINE__);
        !          1733: 
        !          1734:       return D_NO_SUCH_DEVICE;
        !          1735:     }
        !          1736:   do
        !          1737:     p++;
        !          1738:   while (isdigit (*p));
        !          1739:   if (*p)
        !          1740:     {
        !          1741:       char *q = p;
        !          1742: 
        !          1743:       if (! isalpha (*q))
        !          1744:        {
        !          1745:          if (linux_device_open_trace)
        !          1746:            printf ("device_open: at %d\n", __LINE__);
        !          1747: 
        !          1748:          return D_NO_SUCH_DEVICE;
        !          1749:        }
        !          1750:       if (*q == 's' && isdigit (*(q + 1)))
        !          1751:        {
        !          1752:          q++;
        !          1753:          slice = 0;
        !          1754:          do
        !          1755:            slice = slice * 10 + *q++ - '0';
        !          1756:          while (isdigit (*q));
        !          1757:          if (! *q)
        !          1758:            goto find_major;
        !          1759:          if (! isalpha (*q))
        !          1760:            {
        !          1761:              if (linux_device_open_trace)
        !          1762:                printf ("device_open: at %d\n", __LINE__);
        !          1763: 
        !          1764:              return D_NO_SUCH_DEVICE;
        !          1765:            }
        !          1766:        }
        !          1767:       if (*(q + 1))
        !          1768:        {
        !          1769:          if (linux_device_open_trace)
        !          1770:            printf ("device_open: at %d\n", __LINE__);
        !          1771: 
        !          1772:          return D_NO_SUCH_DEVICE;
        !          1773:        }
        !          1774:       part = *q - 'a';
        !          1775:     }
        !          1776:   else
        !          1777:     slice = -1;
        !          1778: 
        !          1779: find_major:
        !          1780:   /* Convert name to major number.  */
        !          1781:   for (i = 0, np = name_to_major; i < NUM_NAMES; i++, np++)
        !          1782:     {
        !          1783:       int len = strlen (np->name);
        !          1784: 
        !          1785:       if (len == p - name && ! strncmp (np->name, name, len))
        !          1786:        break;
        !          1787:     }
        !          1788:   if (i == NUM_NAMES)
        !          1789:     {
        !          1790:       if (linux_device_open_trace)
        !          1791:        printf ("device_open: at %d\n", __LINE__);
        !          1792: 
        !          1793:       return D_NO_SUCH_DEVICE;
        !          1794:     }
        !          1795: 
        !          1796:   major = np->major;
        !          1797:   ds = &blkdevs[major];
        !          1798: 
        !          1799:   /* Check that driver exists.  */
        !          1800:   if (! ds->fops)
        !          1801:     {
        !          1802:       if (linux_device_open_trace)
        !          1803:        printf ("device_open: at %d\n", __LINE__);
        !          1804: 
        !          1805:       return D_NO_SUCH_DEVICE;
        !          1806:     }
        !          1807: 
        !          1808:   /* Slice and partition numbers are only used by disk drives.
        !          1809:      The test for read-only is for IDE CDROMs.  */
        !          1810:   if (! disk_major (major) || np->read_only)
        !          1811:     {
        !          1812:       slice = -1;
        !          1813:       part = -1;
        !          1814:     }
        !          1815: 
        !          1816:   /* Wait for any other open/close calls to finish.  */
        !          1817:   ds = &blkdevs[major];
        !          1818:   while (ds->busy)
        !          1819:     {
        !          1820:       ds->want = 1;
        !          1821:       assert_wait ((event_t) ds, FALSE);
        !          1822:       thread_block (0);
        !          1823:     }
        !          1824:   ds->busy = 1;
        !          1825: 
        !          1826:   /* Compute minor number.  */
        !          1827:   if (disk_major (major) && ! ds->gd)
        !          1828:     {
        !          1829:       struct gendisk *gd;
        !          1830: 
        !          1831:       for (gd = gendisk_head; gd && gd->major != major; gd = gd->next)
        !          1832:        ;
        !          1833:       assert (gd);
        !          1834:       ds->gd = gd;
        !          1835:     }
        !          1836:   minor = np->unit;
        !          1837:   if (ds->gd)
        !          1838:     minor <<= ds->gd->minor_shift;
        !          1839:   dev = MKDEV (major, minor);
        !          1840: 
        !          1841:   /* If no DOS partition is specified, find one we can handle.  */
        !          1842:   if (slice == 0 && (! ds->default_slice || ds->default_slice[np->unit] == 0))
        !          1843:     {
        !          1844:       int sysid, bsize, bshift;
        !          1845:       struct mboot *mp;
        !          1846:       struct ipart *pp;
        !          1847:       struct buffer_head *bhp;
        !          1848: 
        !          1849:       /* Open partition 0.  */
        !          1850:       inode.i_rdev = dev;
        !          1851:       file.f_mode = O_RDONLY;
        !          1852:       file.f_flags = 0;
        !          1853:       if (ds->fops->open)
        !          1854:        {
        !          1855:          linux_intr_pri = SPL5;
        !          1856:          err = (*ds->fops->open) (&inode, &file);
        !          1857:          if (err)
        !          1858:            {
        !          1859:              if (linux_device_open_trace)
        !          1860:                printf ("device_open: at %d\n", __LINE__);
        !          1861: 
        !          1862:              err = linux_to_mach_error (err);
        !          1863:              goto out;
        !          1864:            }
        !          1865:        }
        !          1866: 
        !          1867:       /* Allocate a buffer for I/O.  */
        !          1868:       get_block_size (inode.i_rdev, &bsize, &bshift);
        !          1869:       assert (bsize <= PAGE_SIZE);
        !          1870:       bhp = getblk (inode.i_rdev, 0, bsize);
        !          1871:       if (! bhp)
        !          1872:        {
        !          1873:          if (linux_device_open_trace)
        !          1874:            printf ("device_open: at %d\n", __LINE__);
        !          1875: 
        !          1876:          err = D_NO_MEMORY;
        !          1877:          goto slice_done;
        !          1878:        }
        !          1879: 
        !          1880:       /* Read DOS partition table.  */
        !          1881:       ll_rw_block (READ, 1, &bhp);
        !          1882:       wait_on_buffer (bhp);
        !          1883:       err = check_for_error (READ, 1, &bhp);
        !          1884:       if (err)
        !          1885:        {
        !          1886:          printf ("%s: error reading boot sector\n", np->name);
        !          1887:          err = linux_to_mach_error (err);
        !          1888:          goto slice_done;
        !          1889:        }
        !          1890: 
        !          1891:       /* Check for valid partition table.  */
        !          1892:       mp = (struct mboot *) bhp->b_data;
        !          1893:       if (mp->signature != BOOT_MAGIC)
        !          1894:        {
        !          1895:          printf ("%s: invalid partition table\n", np->name);
        !          1896:          err = D_NO_SUCH_DEVICE;
        !          1897:          goto slice_done;
        !          1898:        }
        !          1899: 
        !          1900:       /* Search for a Mach, BSD or Linux partition.  */
        !          1901:       sysid = 0;
        !          1902:       pp = (struct ipart *) mp->parts;
        !          1903:       for (i = 0; i < FD_NUMPART; i++, pp++)
        !          1904:        {
        !          1905:          if ((pp->systid == UNIXOS
        !          1906:               || pp->systid == BSDOS
        !          1907:               || pp->systid == LINUXOS)
        !          1908:              && (! sysid || pp->bootid == ACTIVE))
        !          1909:            {
        !          1910:              sysid = pp->systid;
        !          1911:              slice = i + 1;
        !          1912:            }
        !          1913:        }
        !          1914:       if (! sysid)
        !          1915:        {
        !          1916:          printf ("%s: No Mach, BSD or Linux partition found\n", np->name);
        !          1917:          err = D_NO_SUCH_DEVICE;
        !          1918:          goto slice_done;
        !          1919:        }
        !          1920: 
        !          1921:       /*      printf ("%s: default slice %d: %s OS\n", np->name, slice,
        !          1922:              (sysid == UNIXOS ? "Mach" : (sysid == BSDOS ? "BSD" : "LINUX")));*/
        !          1923: 
        !          1924:     slice_done:
        !          1925:       if (ds->fops->release)
        !          1926:        (*ds->fops->release) (&inode, &file);
        !          1927:       __brelse (bhp);
        !          1928:       if (err)
        !          1929:        goto out;
        !          1930:       if (! ds->default_slice)
        !          1931:        {
        !          1932:          ds->default_slice = (int *) kalloc (sizeof (int) * ds->gd->max_nr);
        !          1933:          if (! ds->default_slice)
        !          1934:            {
        !          1935:              if (linux_device_open_trace)
        !          1936:                printf ("device_open: at %d\n", __LINE__);
        !          1937: 
        !          1938:              err = D_NO_MEMORY;
        !          1939:              goto out;
        !          1940:            }
        !          1941:          memset (ds->default_slice, 0, sizeof (int) * ds->gd->max_nr);
        !          1942:        }
        !          1943:       ds->default_slice[np->unit] = slice;
        !          1944:     }
        !          1945: 
        !          1946:   /* Add slice to minor number.  */
        !          1947:   if (slice == 0)
        !          1948:     slice = ds->default_slice[np->unit];
        !          1949:   if (slice > 0)
        !          1950:     {
        !          1951:       if (slice >= ds->gd->max_p)
        !          1952:        {
        !          1953:          if (linux_device_open_trace)
        !          1954:            printf ("device_open: at %d\n", __LINE__);
        !          1955: 
        !          1956:          err = D_NO_SUCH_DEVICE;
        !          1957:          goto out;
        !          1958:        }
        !          1959:       minor |= slice;
        !          1960: 
        !          1961:       if (linux_device_open_trace)
        !          1962:        printf ("device_open: at %d: start_sect 0x%x, nr_sects %d\n",
        !          1963:                __LINE__, ds->gd->part[minor].start_sect,
        !          1964:                ds->gd->part[minor].nr_sects);
        !          1965:     }
        !          1966:   dev = MKDEV (major, minor);
        !          1967: 
        !          1968:   /* Initialize file structure.  */
        !          1969:   file.f_mode = (mode == D_READ || np->read_only) ? O_RDONLY : O_RDWR;
        !          1970:   file.f_flags = (mode & D_NODELAY) ? O_NDELAY : 0;
        !          1971: 
        !          1972:   /* Check if the device is currently open.  */
        !          1973:   for (bdp = open_list; bdp; bdp = bdp->next)
        !          1974:     if (bdp->inode.i_rdev == dev
        !          1975:        && bdp->part == part
        !          1976:        && bdp->file.f_mode == file.f_mode
        !          1977:        && bdp->file.f_flags == file.f_flags)
        !          1978:       {
        !          1979:        bd = bdp;
        !          1980:        goto out;
        !          1981:       }
        !          1982: 
        !          1983:   /* Open the device.  */
        !          1984:   if (ds->fops->open)
        !          1985:     {
        !          1986:       inode.i_rdev = dev;
        !          1987:       linux_intr_pri = SPL5;
        !          1988:       err = (*ds->fops->open) (&inode, &file);
        !          1989:       if (err)
        !          1990:        {
        !          1991:          if (linux_device_open_trace)
        !          1992:            printf ("device_open: at %d\n", __LINE__);
        !          1993: 
        !          1994:          err = linux_to_mach_error (err);
        !          1995:          goto out;
        !          1996:        }
        !          1997:     }
        !          1998:       
        !          1999:   /* Read disklabel.  */
        !          2000:   if (part >= 0 && (! ds->label || ! ds->label[minor]))
        !          2001:     {
        !          2002:       int bsize, bshift;
        !          2003:       struct evtoc *evp;
        !          2004:       struct disklabel *lp, *dlp;
        !          2005:       struct buffer_head *bhp;
        !          2006: 
        !          2007:       assert (disk_major (major));
        !          2008: 
        !          2009:       /* Allocate a disklabel.  */
        !          2010:       lp = (struct disklabel *) kalloc (sizeof (struct disklabel));
        !          2011:       if (! lp)
        !          2012:        {
        !          2013:          if (linux_device_open_trace)
        !          2014:            printf ("device_open: at %d\n", __LINE__);
        !          2015: 
        !          2016:          err = D_NO_MEMORY;
        !          2017:          goto bad;
        !          2018:        }
        !          2019: 
        !          2020:       /* Allocate a buffer for I/O.  */
        !          2021:       get_block_size (dev, &bsize, &bshift);
        !          2022:       assert (bsize <= PAGE_SIZE);
        !          2023:       bhp = getblk (dev, LBLLOC >> (bshift - 9), bsize);
        !          2024:       if (! bhp)
        !          2025:        {
        !          2026:          if (linux_device_open_trace)
        !          2027:            printf ("device_open: at %d\n", __LINE__);
        !          2028: 
        !          2029:          err = D_NO_MEMORY;
        !          2030:          goto label_done;
        !          2031:        }
        !          2032: 
        !          2033:       /* Set up 'c' partition to span the entire DOS partition.  */
        !          2034:       lp->d_npartitions = PART_DISK + 1;
        !          2035:       memset (lp->d_partitions, 0, MAXPARTITIONS * sizeof (struct partition));
        !          2036:       lp->d_partitions[PART_DISK].p_offset = ds->gd->part[minor].start_sect;
        !          2037:       lp->d_partitions[PART_DISK].p_size = ds->gd->part[minor].nr_sects;
        !          2038: 
        !          2039:       /* Try reading a BSD disklabel.  */
        !          2040:       ll_rw_block (READ, 1, &bhp);
        !          2041:       wait_on_buffer (bhp);
        !          2042:       err = check_for_error (READ, 1, &bhp);
        !          2043:       if (err)
        !          2044:        {
        !          2045:          printf ("%s: error reading BSD label\n", np->name);
        !          2046:          err = 0;
        !          2047:          goto vtoc;
        !          2048:        }
        !          2049:       dlp = (struct disklabel *) (bhp->b_data + ((LBLLOC << 9) & (bsize - 1)));
        !          2050:       if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC)
        !          2051:        goto vtoc;
        !          2052:       /*      printf ("%s: BSD LABEL\n", np->name);*/
        !          2053:       lp->d_npartitions = dlp->d_npartitions;
        !          2054:       memcpy (lp->d_partitions, dlp->d_partitions,
        !          2055:              MAXPARTITIONS * sizeof (struct partition));
        !          2056: 
        !          2057:       /* Check for NetBSD DOS partition bogosity.  */
        !          2058:       for (i = 0; i < lp->d_npartitions; i++)
        !          2059:        if (lp->d_partitions[i].p_size > ds->gd->part[minor].nr_sects)
        !          2060:          ds->gd->part[minor].nr_sects = lp->d_partitions[i].p_size;
        !          2061:       goto label_done;
        !          2062: 
        !          2063:     vtoc:
        !          2064:       /* Try reading VTOC.  */
        !          2065:       bhp->b_blocknr = PDLOCATION >> (bshift - 9);
        !          2066:       bhp->b_state = 1 << BH_Lock;
        !          2067:       ll_rw_block (READ, 1, &bhp);
        !          2068:       wait_on_buffer (bhp);
        !          2069:       err = check_for_error (READ, 1, &bhp);
        !          2070:       if (err)
        !          2071:        {
        !          2072:          printf ("%s: error reading evtoc\n", np->name);
        !          2073:          err = linux_to_mach_error (err);
        !          2074:          goto label_done;
        !          2075:        }
        !          2076:       evp = (struct evtoc *) (bhp->b_data + ((PDLOCATION << 9) & (bsize - 1)));
        !          2077:       if (evp->sanity != VTOC_SANE)
        !          2078:        {
        !          2079:          printf ("%s: No BSD or Mach label found\n", np->name);
        !          2080:          err = D_NO_SUCH_DEVICE;
        !          2081:          goto label_done;
        !          2082:        }
        !          2083:       /*      printf ("%s: LOCAL LABEL\n", np->name);*/
        !          2084:       lp->d_npartitions = (evp->nparts > MAXPARTITIONS
        !          2085:                           ? MAXPARTITIONS : evp->nparts);
        !          2086:       for (i = 0; i < lp->d_npartitions; i++)
        !          2087:        {
        !          2088:          lp->d_partitions[i].p_size = evp->part[i].p_size;
        !          2089:          lp->d_partitions[i].p_offset = evp->part[i].p_start;
        !          2090:          lp->d_partitions[i].p_fstype = FS_BSDFFS;
        !          2091:        }
        !          2092: 
        !          2093:     label_done:
        !          2094:       if (bhp)
        !          2095:        __brelse (bhp);
        !          2096:       if (err)
        !          2097:        {
        !          2098:          kfree ((vm_offset_t) lp, sizeof (struct disklabel));
        !          2099:          goto bad;
        !          2100:        }
        !          2101:       if (! ds->label)
        !          2102:        {
        !          2103:          ds->label = (struct disklabel **) kalloc (sizeof (struct disklabel *)
        !          2104:                                                    * ds->gd->max_p
        !          2105:                                                    * ds->gd->max_nr);
        !          2106:          if (! ds->label)
        !          2107:            {
        !          2108:              if (linux_device_open_trace)
        !          2109:                printf ("device_open: at %d\n", __LINE__);
        !          2110: 
        !          2111:              kfree ((vm_offset_t) lp, sizeof (struct disklabel));
        !          2112:              err = D_NO_MEMORY;
        !          2113:              goto bad;
        !          2114:            }
        !          2115:          memset (ds->label, 0,
        !          2116:                  (sizeof (struct disklabel *)
        !          2117:                   * ds->gd->max_p * ds->gd->max_nr));
        !          2118:        }
        !          2119:       ds->label[minor] = lp;
        !          2120:     }
        !          2121: 
        !          2122:   /* Check partition number.  */
        !          2123:   if (part >= 0
        !          2124:       && (part >= ds->label[minor]->d_npartitions
        !          2125:          || ds->label[minor]->d_partitions[part].p_size == 0))
        !          2126:     {
        !          2127:       err = D_NO_SUCH_DEVICE;
        !          2128:       goto bad;
        !          2129:     }
        !          2130: 
        !          2131:   /* Allocate and initialize device data.  */
        !          2132:   bd = (struct block_data *) kalloc (sizeof (struct block_data));
        !          2133:   if (! bd)
        !          2134:     {
        !          2135:       if (linux_device_open_trace)
        !          2136:        printf ("device_open: at %d\n", __LINE__);
        !          2137: 
        !          2138:       err = D_NO_MEMORY;
        !          2139:       goto bad;
        !          2140:     }
        !          2141:   bd->want = 0;
        !          2142:   bd->open_count = 0;
        !          2143:   bd->iocount = 0;
        !          2144:   bd->part = part;
        !          2145:   bd->ds = ds;
        !          2146:   bd->device.emul_data = bd;
        !          2147:   bd->device.emul_ops = &linux_block_emulation_ops;
        !          2148:   bd->inode.i_rdev = dev;
        !          2149:   bd->file.f_mode = file.f_mode;
        !          2150:   bd->file.f_np = np;
        !          2151:   bd->file.f_flags = file.f_flags;
        !          2152:   bd->port = ipc_port_alloc_kernel ();
        !          2153:   if (bd->port == IP_NULL)
        !          2154:     {
        !          2155:       if (linux_device_open_trace)
        !          2156:        printf ("device_open: at %d\n", __LINE__);
        !          2157: 
        !          2158:       err = KERN_RESOURCE_SHORTAGE;
        !          2159:       goto bad;
        !          2160:     }
        !          2161:   ipc_kobject_set (bd->port, (ipc_kobject_t) &bd->device, IKOT_DEVICE);
        !          2162:   notify = ipc_port_make_sonce (bd->port);
        !          2163:   ip_lock (bd->port);
        !          2164:   ipc_port_nsrequest (bd->port, 1, notify, &notify);
        !          2165:   assert (notify == IP_NULL);
        !          2166: 
        !          2167:   goto out;
        !          2168: 
        !          2169: bad:
        !          2170:   if (ds->fops->release)
        !          2171:     (*ds->fops->release) (&inode, &file);
        !          2172: 
        !          2173: out:
        !          2174:   ds->busy = 0;
        !          2175:   if (ds->want)
        !          2176:     {
        !          2177:       ds->want = 0;
        !          2178:       thread_wakeup ((event_t) ds);
        !          2179:     }
        !          2180: 
        !          2181:   if (bd && bd->open_count > 0)
        !          2182:     {
        !          2183:       if (err)
        !          2184:        *devp = NULL;
        !          2185:       else
        !          2186:        {
        !          2187:          *devp = &bd->device;
        !          2188:          bd->open_count++;
        !          2189:        }
        !          2190:       return err;
        !          2191:     }
        !          2192: 
        !          2193:   if (err)
        !          2194:     {
        !          2195:       if (bd)
        !          2196:        {
        !          2197:          if (bd->port != IP_NULL)
        !          2198:            {
        !          2199:              ipc_kobject_set (bd->port, IKO_NULL, IKOT_NONE);
        !          2200:              ipc_port_dealloc_kernel (bd->port);
        !          2201:            }
        !          2202:          kfree ((vm_offset_t) bd, sizeof (struct block_data));
        !          2203:          bd = NULL;
        !          2204:        }
        !          2205:     }
        !          2206:   else
        !          2207:     {
        !          2208:       bd->open_count = 1;
        !          2209:       bd->next = open_list;
        !          2210:       open_list = bd;
        !          2211:     }
        !          2212: 
        !          2213:   if (IP_VALID (reply_port))
        !          2214:     ds_device_open_reply (reply_port, reply_port_type, err, dev_to_port (bd));
        !          2215:   else if (! err)
        !          2216:     device_close (bd);
        !          2217: 
        !          2218:   return MIG_NO_REPLY;
        !          2219: }
        !          2220: 
        !          2221: static io_return_t
        !          2222: device_close (void *d)
        !          2223: {
        !          2224:   struct block_data *bd = d, *bdp, **prev;
        !          2225:   struct device_struct *ds = bd->ds;
        !          2226: 
        !          2227:   /* Wait for any other open/close to complete.  */
        !          2228:   while (ds->busy)
        !          2229:     {
        !          2230:       ds->want = 1;
        !          2231:       assert_wait ((event_t) ds, FALSE);
        !          2232:       thread_block (0);
        !          2233:     }
        !          2234:   ds->busy = 1;
        !          2235: 
        !          2236:   if (--bd->open_count == 0)
        !          2237:     {
        !          2238:       /* Wait for pending I/O to complete.  */
        !          2239:       while (bd->iocount > 0)
        !          2240:        {
        !          2241:          bd->want = 1;
        !          2242:          assert_wait ((event_t) bd, FALSE);
        !          2243:          thread_block (0);
        !          2244:        }
        !          2245: 
        !          2246:       /* Remove device from open list.  */
        !          2247:       prev = &open_list;
        !          2248:       bdp = open_list;
        !          2249:       while (bdp)
        !          2250:        {
        !          2251:          if (bdp == bd)
        !          2252:            {
        !          2253:              *prev = bdp->next;
        !          2254:              break;
        !          2255:            }
        !          2256:          prev = &bdp->next;
        !          2257:          bdp = bdp->next;
        !          2258:        }
        !          2259: 
        !          2260:       assert (bdp == bd);
        !          2261: 
        !          2262:       if (ds->fops->release)
        !          2263:        (*ds->fops->release) (&bd->inode, &bd->file);
        !          2264: 
        !          2265:       ipc_kobject_set (bd->port, IKO_NULL, IKOT_NONE);
        !          2266:       ipc_port_dealloc_kernel (bd->port);
        !          2267:       kfree ((vm_offset_t) bd, sizeof (struct block_data));
        !          2268:     }
        !          2269: 
        !          2270:   ds->busy = 0;
        !          2271:   if (ds->want)
        !          2272:     {
        !          2273:       ds->want = 0;
        !          2274:       thread_wakeup ((event_t) ds);
        !          2275:     }
        !          2276:   return D_SUCCESS;
        !          2277: }
        !          2278: 
        !          2279: /* XXX: Assumes all drivers use block_write.  */
        !          2280: static io_return_t
        !          2281: device_write (void *d, ipc_port_t reply_port,
        !          2282:              mach_msg_type_name_t reply_port_type, dev_mode_t mode,
        !          2283:              recnum_t bn, io_buf_ptr_t data, unsigned int count,
        !          2284:              int *bytes_written)
        !          2285: {
        !          2286:   int major, minor;
        !          2287:   unsigned sz, maxsz, off;
        !          2288:   io_return_t err = 0;
        !          2289:   struct block_data *bd = d;
        !          2290: 
        !          2291:   if (! bd->ds->fops->write)
        !          2292:     {
        !          2293:       printf ("device_write: at %d\n", __LINE__);
        !          2294:       return D_INVALID_OPERATION;
        !          2295:     }
        !          2296: 
        !          2297:   if ((int) count <= 0)
        !          2298:     {
        !          2299:       printf ("device_write: at %d\n", __LINE__);
        !          2300:       return D_INVALID_SIZE;
        !          2301:     }
        !          2302: 
        !          2303:   major = MAJOR (bd->inode.i_rdev);
        !          2304:   minor = MINOR (bd->inode.i_rdev);
        !          2305: 
        !          2306:   if (disk_major (major))
        !          2307:     {
        !          2308:       assert (bd->ds->gd);
        !          2309: 
        !          2310:       if (bd->part >= 0)
        !          2311:        {
        !          2312:          struct disklabel *lp;
        !          2313: 
        !          2314:          assert (bd->ds->label);
        !          2315:          lp = bd->ds->label[minor];
        !          2316:          assert (lp);
        !          2317:          maxsz = lp->d_partitions[bd->part].p_size;
        !          2318:          off = (lp->d_partitions[bd->part].p_offset
        !          2319:                 - bd->ds->gd->part[minor].start_sect);
        !          2320: 
        !          2321:          if (linux_block_write_trace)
        !          2322:            printf ("device_write: at %d: dev %s, part %d, "
        !          2323:                    "offset 0x%x (%u), start_sect 0x%x (%u), "
        !          2324:                    "maxsz 0x%x (%u)\n",
        !          2325:                    __LINE__,
        !          2326:                    kdevname (bd->inode.i_rdev),
        !          2327:                    bd->part,
        !          2328:                    lp->d_partitions[bd->part].p_offset,
        !          2329:                    lp->d_partitions[bd->part].p_offset,
        !          2330:                    bd->ds->gd->part[minor].start_sect,
        !          2331:                    bd->ds->gd->part[minor].start_sect,
        !          2332:                    maxsz, maxsz);
        !          2333: 
        !          2334:          assert (off < bd->ds->gd->part[minor].nr_sects);
        !          2335:        }
        !          2336:       else
        !          2337:        {
        !          2338:          maxsz = bd->ds->gd->part[minor].nr_sects;
        !          2339:          off = 0;
        !          2340:        }
        !          2341:     }
        !          2342:   else
        !          2343:     {
        !          2344:       assert (blk_size[major]);
        !          2345:       maxsz = blk_size[major][minor] << (BLOCK_SIZE_BITS - 9);
        !          2346:       off = 0;
        !          2347:     }
        !          2348: 
        !          2349:   if (bn >= maxsz)
        !          2350:     {
        !          2351:       if (linux_block_write_trace)
        !          2352:        printf ("device_write: at %d\n", __LINE__);
        !          2353: 
        !          2354:       return D_INVALID_SIZE;
        !          2355:     }
        !          2356: 
        !          2357:   bd->iocount++;
        !          2358: 
        !          2359:   sz = (count + 511) >> 9;
        !          2360:   if (sz > maxsz - bn)
        !          2361:     {
        !          2362:       sz = maxsz - bn;
        !          2363:       if (count > (sz << 9))
        !          2364:        count = sz << 9;
        !          2365:     }
        !          2366: 
        !          2367:   bd->file.f_pos = (loff_t) (bn + off) << 9;
        !          2368: 
        !          2369:   err = (*bd->ds->fops->write) (&bd->inode, &bd->file, (char *) data, count);
        !          2370:   if (err)
        !          2371:     err = linux_to_mach_error (err);
        !          2372: 
        !          2373:   if (linux_block_write_trace)
        !          2374:     printf ("device_write: at %d: err %d\n", __LINE__, err);
        !          2375: 
        !          2376:   if (IP_VALID (reply_port))
        !          2377:     ds_device_write_reply (reply_port, reply_port_type,
        !          2378:                           err, count - bd->file.f_resid);
        !          2379: 
        !          2380:   if (--bd->iocount == 0 && bd->want)
        !          2381:     {
        !          2382:       bd->want = 0;
        !          2383:       thread_wakeup ((event_t) bd);
        !          2384:     }
        !          2385:   return MIG_NO_REPLY;
        !          2386: }
        !          2387: 
        !          2388: /* XXX: Assumes all drivers use block_read.  */
        !          2389: static io_return_t
        !          2390: device_read (void *d, ipc_port_t reply_port,
        !          2391:             mach_msg_type_name_t reply_port_type, dev_mode_t mode,
        !          2392:             recnum_t bn, int count, io_buf_ptr_t *data,
        !          2393:             unsigned *bytes_read)
        !          2394: {
        !          2395:   int major, minor;
        !          2396:   unsigned sz, maxsz, off;
        !          2397:   io_return_t err = 0;
        !          2398:   vm_offset_t addr;
        !          2399:   vm_object_t object;
        !          2400:   vm_map_copy_t copy;
        !          2401:   struct block_data *bd = d;
        !          2402:   struct inode *inode = &bd->inode;
        !          2403: 
        !          2404:   *data = 0;
        !          2405:   *bytes_read = 0;
        !          2406: 
        !          2407:   if (! bd->ds->fops->read)
        !          2408:     return D_INVALID_OPERATION;
        !          2409: 
        !          2410:   if (count <= 0)
        !          2411:     return D_INVALID_SIZE;
        !          2412: 
        !          2413:   major = MAJOR (bd->inode.i_rdev);
        !          2414:   minor = MINOR (bd->inode.i_rdev);
        !          2415: 
        !          2416:   if (LINUX_BLOCK_READ_TRACE)
        !          2417:     printf ("device_read: at %d: major %d, minor %d, count %d, recnum %u\n",
        !          2418:            __LINE__, major, minor, count, bn);
        !          2419: 
        !          2420:   if (disk_major (major))
        !          2421:     {
        !          2422:       assert (bd->ds->gd);
        !          2423: 
        !          2424:       if (bd->part >= 0)
        !          2425:        {
        !          2426:          struct disklabel *lp;
        !          2427: 
        !          2428:          assert (bd->ds->label);
        !          2429:          lp = bd->ds->label[minor];
        !          2430:          assert (lp);
        !          2431:          maxsz = lp->d_partitions[bd->part].p_size;
        !          2432:          off = (lp->d_partitions[bd->part].p_offset
        !          2433:                 - bd->ds->gd->part[minor].start_sect);
        !          2434: 
        !          2435:          if (LINUX_BLOCK_READ_TRACE)
        !          2436:            printf ("device_read: at %d: dev %s, part %d, offset 0x%x, "
        !          2437:                    "size %d, start_sect 0x%x, nr_sects %d\n",
        !          2438:                    __LINE__, kdevname (major), bd->part, off, maxsz,
        !          2439:                    bd->ds->gd->part[minor].start_sect,
        !          2440:                    bd->ds->gd->part[minor].nr_sects);
        !          2441: 
        !          2442:          assert (off < bd->ds->gd->part[minor].nr_sects);
        !          2443:        }
        !          2444:       else
        !          2445:        {
        !          2446:          maxsz = bd->ds->gd->part[minor].nr_sects;
        !          2447:          off = 0;
        !          2448:        }
        !          2449:     }
        !          2450:   else
        !          2451:     {
        !          2452:       assert (blk_size[major]);
        !          2453:       maxsz = blk_size[major][minor] << (BLOCK_SIZE_BITS - 9);
        !          2454:       off = 0;
        !          2455:     }
        !          2456: 
        !          2457:   if (bn > maxsz)
        !          2458:     return D_INVALID_SIZE;
        !          2459: 
        !          2460:   /* Be backward compatible with Unix.  */
        !          2461:   if (bn == maxsz)
        !          2462:     {
        !          2463:       if (LINUX_BLOCK_READ_TRACE)
        !          2464:        printf ("device_read: at %d\n", __LINE__);
        !          2465:       return 0;
        !          2466:     }
        !          2467: 
        !          2468:   sz = (count + 511) >> 9;
        !          2469:   if (sz > maxsz - bn)
        !          2470:     {
        !          2471:       sz = maxsz - bn;
        !          2472:       if (count > (sz << 9))
        !          2473:        count = sz << 9;
        !          2474:     }
        !          2475: 
        !          2476:   bd->file.f_pos = (loff_t) (bn + off) << 9;
        !          2477:   bd->file.f_object = NULL;
        !          2478: 
        !          2479:   if (LINUX_BLOCK_READ_TRACE)
        !          2480:     printf ("device_read: at %d: f_pos 0x%x\n",
        !          2481:            __LINE__, (unsigned) bd->file.f_pos);
        !          2482: 
        !          2483:   bd->iocount++;
        !          2484: 
        !          2485:   err = (*bd->ds->fops->read) (&bd->inode, &bd->file, (char *) data, count);
        !          2486:   if (err)
        !          2487:     err = linux_to_mach_error (err);
        !          2488:   else
        !          2489:     {
        !          2490:       object = bd->file.f_object;
        !          2491:       assert (object);
        !          2492:       assert (object->ref_count == 1);
        !          2493:       err = vm_map_copyin_object (object, 0, round_page (count), &copy);
        !          2494:       assert (object->ref_count == 1);
        !          2495:       if (err)
        !          2496:        vm_object_deallocate (object);
        !          2497:       else
        !          2498:        {
        !          2499:          assert (copy->cpy_object->ref_count == 1);
        !          2500:          *data = (io_buf_ptr_t) copy;
        !          2501:          *bytes_read = count - bd->file.f_resid;
        !          2502:        }
        !          2503:     }
        !          2504:   if (--bd->iocount == 0 && bd->want)
        !          2505:     {
        !          2506:       bd->want = 0;
        !          2507:       thread_wakeup ((event_t) bd);
        !          2508:     }
        !          2509:   return err;
        !          2510: }
        !          2511: 
        !          2512: static io_return_t
        !          2513: device_get_status (void *d, dev_flavor_t flavor, dev_status_t status,
        !          2514:                   mach_msg_type_number_t *status_count)
        !          2515: {
        !          2516:   struct block_data *bd = d;
        !          2517: 
        !          2518:   switch (flavor)
        !          2519:     {
        !          2520:     case DEV_GET_SIZE:
        !          2521:       if (*status_count != DEV_GET_SIZE_COUNT)
        !          2522:        return D_INVALID_SIZE;
        !          2523:       if (disk_major (MAJOR (bd->inode.i_rdev)))
        !          2524:        {
        !          2525:          assert (bd->ds->gd);
        !          2526: 
        !          2527:          if (bd->part >= 0)
        !          2528:            {
        !          2529:              struct disklabel *lp;
        !          2530: 
        !          2531:              assert (bd->ds->label);
        !          2532:              lp = bd->ds->label[MINOR (bd->inode.i_rdev)];
        !          2533:              assert (lp);
        !          2534:              (status[DEV_GET_SIZE_DEVICE_SIZE]
        !          2535:               = lp->d_partitions[bd->part].p_size << 9);
        !          2536:            }
        !          2537:          else
        !          2538:            (status[DEV_GET_SIZE_DEVICE_SIZE]
        !          2539:             = bd->ds->gd->part[MINOR (bd->inode.i_rdev)].nr_sects << 9);
        !          2540:        }
        !          2541:       else
        !          2542:        {
        !          2543:          assert (blk_size[MAJOR (bd->inode.i_rdev)]);
        !          2544:          (status[DEV_GET_SIZE_DEVICE_SIZE]
        !          2545:           = (blk_size[MAJOR (bd->inode.i_rdev)][MINOR (bd->inode.i_rdev)]
        !          2546:              << BLOCK_SIZE_BITS));
        !          2547:        }
        !          2548:       /* It would be nice to return the block size as reported by
        !          2549:         the driver, but a lot of user level code assumes the sector
        !          2550:         size to be 512.  */
        !          2551:       status[DEV_GET_SIZE_RECORD_SIZE] = 512;
        !          2552:       break;
        !          2553: 
        !          2554:     default:
        !          2555:       return D_INVALID_OPERATION;
        !          2556:     }
        !          2557: 
        !          2558:   return D_SUCCESS;
        !          2559: }
        !          2560: 
        !          2561: struct device_emulation_ops linux_block_emulation_ops =
        !          2562: {
        !          2563:   NULL,
        !          2564:   NULL,
        !          2565:   dev_to_port,
        !          2566:   device_open,
        !          2567:   device_close,
        !          2568:   device_write,
        !          2569:   NULL,
        !          2570:   device_read,
        !          2571:   NULL,
        !          2572:   NULL,
        !          2573:   device_get_status,
        !          2574:   NULL,
        !          2575:   NULL,
        !          2576:   NULL,
        !          2577:   NULL,
        !          2578:   NULL
        !          2579: };

unix.superglobalmegacorp.com

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