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

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

unix.superglobalmegacorp.com

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