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

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

unix.superglobalmegacorp.com

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