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

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

unix.superglobalmegacorp.com

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