| File: | obj-scan-build/../linux/dev/glue/block.c |
| Location: | line 454, column 11 |
| Description: | Dereference of undefined pointer value |
| 1 | /* | |||||
| 2 | * Linux block driver support. | |||||
| 3 | * | |||||
| 4 | * Copyright (C) 1996 The University of Utah and the Computer Systems | |||||
| 5 | * Laboratory at the University of Utah (CSL) | |||||
| 6 | * | |||||
| 7 | * This program is free software; you can redistribute it and/or modify | |||||
| 8 | * it under the terms of the GNU General Public License as published by | |||||
| 9 | * the Free Software Foundation; either version 2, or (at your option) | |||||
| 10 | * any later version. | |||||
| 11 | * | |||||
| 12 | * This program is distributed in the hope that it will be useful, | |||||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| 15 | * GNU General Public License for more details. | |||||
| 16 | * | |||||
| 17 | * You should have received a copy of the GNU General Public License | |||||
| 18 | * along with this program; if not, write to the Free Software | |||||
| 19 | * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
| 20 | * | |||||
| 21 | * Author: Shantanu Goel, University of Utah CSL | |||||
| 22 | */ | |||||
| 23 | ||||||
| 24 | /* | |||||
| 25 | * linux/drivers/block/ll_rw_blk.c | |||||
| 26 | * | |||||
| 27 | * Copyright (C) 1991, 1992 Linus Torvalds | |||||
| 28 | * Copyright (C) 1994, Karl Keyte: Added support for disk statistics | |||||
| 29 | */ | |||||
| 30 | ||||||
| 31 | /* | |||||
| 32 | * linux/fs/block_dev.c | |||||
| 33 | * | |||||
| 34 | * Copyright (C) 1991, 1992 Linus Torvalds | |||||
| 35 | */ | |||||
| 36 | ||||||
| 37 | /* | |||||
| 38 | * linux/fs/buffer.c | |||||
| 39 | * | |||||
| 40 | * Copyright (C) 1991, 1992 Linus Torvalds | |||||
| 41 | */ | |||||
| 42 | ||||||
| 43 | #include <sys/types.h> | |||||
| 44 | #include <machine/spl.h> | |||||
| 45 | #include <mach/mach_types.h> | |||||
| 46 | #include <mach/kern_return.h> | |||||
| 47 | #include <mach/mig_errors.h> | |||||
| 48 | #include <mach/port.h> | |||||
| 49 | #include <mach/vm_param.h> | |||||
| 50 | #include <mach/notify.h> | |||||
| 51 | ||||||
| 52 | #include <kern/kalloc.h> | |||||
| 53 | ||||||
| 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> | |||||
| 64 | #include <device/device_reply.user.h> | |||||
| 65 | #include <device/device_emul.h> | |||||
| 66 | #include <device/ds_routines.h> | |||||
| 67 | ||||||
| 68 | /* TODO. This should be fixed to not be i386 specific. */ | |||||
| 69 | #include <i386at/disk.h> | |||||
| 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 | ||||||
| 84 | #include <linux/dev/glue/glue.h> | |||||
| 85 | ||||||
| 86 | /* This task queue is not used in Mach: just for fixing undefined symbols. */ | |||||
| 87 | DECLARE_TASK_QUEUE (tq_disk)task_queue tq_disk = ((void *) 0); | |||||
| 88 | ||||||
| 89 | /* Location of VTOC in units for sectors (512 bytes). */ | |||||
| 90 | #define PDLOCATION29 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_BLKDEV128]; | |||||
| 127 | ||||||
| 128 | /* Driver request function table. */ | |||||
| 129 | struct blk_dev_struct blk_dev[MAX_BLKDEV128] = | |||||
| 130 | { | |||||
| 131 | { NULL((void *) 0), NULL((void *) 0) }, /* 0 no_dev */ | |||||
| 132 | { NULL((void *) 0), NULL((void *) 0) }, /* 1 dev mem */ | |||||
| 133 | { NULL((void *) 0), NULL((void *) 0) }, /* 2 dev fd */ | |||||
| 134 | { NULL((void *) 0), NULL((void *) 0) }, /* 3 dev ide0 or hd */ | |||||
| 135 | { NULL((void *) 0), NULL((void *) 0) }, /* 4 dev ttyx */ | |||||
| 136 | { NULL((void *) 0), NULL((void *) 0) }, /* 5 dev tty */ | |||||
| 137 | { NULL((void *) 0), NULL((void *) 0) }, /* 6 dev lp */ | |||||
| 138 | { NULL((void *) 0), NULL((void *) 0) }, /* 7 dev pipes */ | |||||
| 139 | { NULL((void *) 0), NULL((void *) 0) }, /* 8 dev sd */ | |||||
| 140 | { NULL((void *) 0), NULL((void *) 0) }, /* 9 dev st */ | |||||
| 141 | { NULL((void *) 0), NULL((void *) 0) }, /* 10 */ | |||||
| 142 | { NULL((void *) 0), NULL((void *) 0) }, /* 11 */ | |||||
| 143 | { NULL((void *) 0), NULL((void *) 0) }, /* 12 */ | |||||
| 144 | { NULL((void *) 0), NULL((void *) 0) }, /* 13 */ | |||||
| 145 | { NULL((void *) 0), NULL((void *) 0) }, /* 14 */ | |||||
| 146 | { NULL((void *) 0), NULL((void *) 0) }, /* 15 */ | |||||
| 147 | { NULL((void *) 0), NULL((void *) 0) }, /* 16 */ | |||||
| 148 | { NULL((void *) 0), NULL((void *) 0) }, /* 17 */ | |||||
| 149 | { NULL((void *) 0), NULL((void *) 0) }, /* 18 */ | |||||
| 150 | { NULL((void *) 0), NULL((void *) 0) }, /* 19 */ | |||||
| 151 | { NULL((void *) 0), NULL((void *) 0) }, /* 20 */ | |||||
| 152 | { NULL((void *) 0), NULL((void *) 0) }, /* 21 */ | |||||
| 153 | { NULL((void *) 0), NULL((void *) 0) } /* 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_BLKDEV128] = { NULL((void *) 0), NULL((void *) 0), }; | |||||
| 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_BLKDEV128] = { NULL((void *) 0), NULL((void *) 0), }; | |||||
| 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_BLKDEV128] = { NULL((void *) 0), NULL((void *) 0), }; | |||||
| 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_BLKDEV128] = {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((void *) 0); | |||||
| 196 | ||||||
| 197 | /* Initialize block drivers. */ | |||||
| 198 | int | |||||
| 199 | blk_dev_init () | |||||
| 200 | { | |||||
| 201 | #ifdef CONFIG_BLK_DEV_IDE1 | |||||
| 202 | ide_init (); | |||||
| 203 | #endif | |||||
| 204 | #ifdef CONFIG_BLK_DEV_FD1 | |||||
| 205 | floppy_init (); | |||||
| 206 | #else | |||||
| 207 | outb_p (0xc, 0x3f2)((__builtin_constant_p((0x3f2)) && (0x3f2) < 256) ? __outbc_p((0xc),(0x3f2)) : __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 inlineinline __attribute__((always_inline)) int | |||||
| 214 | disk_major (int major) | |||||
| 215 | { | |||||
| 216 | return (major == IDE0_MAJOR3 | |||||
| 217 | || major == IDE1_MAJOR22 | |||||
| 218 | || major == IDE2_MAJOR33 | |||||
| 219 | || major == IDE3_MAJOR34 | |||||
| 220 | || major == SCSI_DISK_MAJOR8); | |||||
| 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_BLKDEV128 - 1; major > 0; major--) | |||||
| 234 | if (blkdevs[major].fops == NULL((void *) 0)) | |||||
| 235 | goto out; | |||||
| 236 | return -EBUSY16; | |||||
| 237 | } | |||||
| 238 | if (major >= MAX_BLKDEV128) | |||||
| 239 | return -EINVAL22; | |||||
| 240 | if (blkdevs[major].fops && blkdevs[major].fops != fops) | |||||
| 241 | return -EBUSY16; | |||||
| 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((void *) 0); | |||||
| 249 | blkdevs[major].default_slice = 0; | |||||
| 250 | blkdevs[major].labels = NULL((void *) 0); | |||||
| 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_BLKDEV128) | |||||
| 260 | return -EINVAL22; | |||||
| 261 | if (! blkdevs[major].fops || strcmp (blkdevs[major].name, name)) | |||||
| 262 | return -EINVAL22; | |||||
| 263 | blkdevs[major].fops = NULL((void *) 0); | |||||
| 264 | if (blkdevs[major].labels) | |||||
| 265 | { | |||||
| 266 | assert (blkdevs[major].gd)({ if (!(blkdevs[major].gd)) Assert("blkdevs[major].gd", "../linux/dev/glue/block.c" , 266); }); | |||||
| 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)((dev) >> 8)]) | |||||
| 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)((dev) >> 8)][MINOR (dev)((dev) & ((1<<8) - 1))] = 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)({ if (!(size <= (1 << 12))) Assert("size <= PAGE_SIZE" , "../linux/dev/glue/block.c", 301); }); | |||||
| 302 | ||||||
| 303 | if (! linux_auto_config) | |||||
| 304 | { | |||||
| 305 | while ((m = vm_page_grab (FALSE((boolean_t) 0))) == 0) | |||||
| 306 | VM_PAGE_WAIT (0)vm_page_wait(0); | |||||
| 307 | d = current_thread ()(active_threads[(0)])->pcb->data; | |||||
| 308 | assert (d)({ if (!(d)) Assert("d", "../linux/dev/glue/block.c", 308); } ); | |||||
| 309 | queue_enter (&d->pages, m, vm_page_t, pageq){ queue_entry_t prev; prev = (&d->pages)->prev; if ( (&d->pages) == prev) { (&d->pages)->next = ( queue_entry_t) (m); } else { ((vm_page_t)prev)->pageq.next = (queue_entry_t)(m); } (m)->pageq.prev = prev; (m)->pageq .next = &d->pages; (&d->pages)->prev = (queue_entry_t ) m; }; | |||||
| 310 | return (void *) phystokv(m->phys_addr)((vm_offset_t)(m->phys_addr) + 0xC0000000UL); | |||||
| 311 | } | |||||
| 312 | return (void *) __get_free_pages (GFP_KERNEL0x03, 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)({ if (!(size <= (1 << 12))) Assert("size <= PAGE_SIZE" , "../linux/dev/glue/block.c", 322); }); | |||||
| 323 | ||||||
| 324 | if (! linux_auto_config) | |||||
| 325 | { | |||||
| 326 | d = current_thread ()(active_threads[(0)])->pcb->data; | |||||
| 327 | assert (d)({ if (!(d)) Assert("d", "../linux/dev/glue/block.c", 327); } ); | |||||
| 328 | queue_iterate (&d->pages, m, vm_page_t, pageq)for ((m) = (vm_page_t) ((&d->pages)->next); !(((& d->pages)) == ((queue_entry_t)(m))); (m) = (vm_page_t) ((& (m)->pageq)->next)) | |||||
| 329 | { | |||||
| 330 | if (phystokv(m->phys_addr)((vm_offset_t)(m->phys_addr) + 0xC0000000UL) == (vm_offset_t) p) | |||||
| 331 | { | |||||
| 332 | queue_remove (&d->pages, m, vm_page_t, pageq){ queue_entry_t next, prev; next = (m)->pageq.next; prev = (m)->pageq.prev; if ((&d->pages) == next) (&d-> pages)->prev = prev; else ((vm_page_t)next)->pageq.prev = prev; if ((&d->pages) == prev) (&d->pages)-> next = next; else ((vm_page_t)prev)->pageq.next = next; }; | |||||
| 333 | VM_PAGE_FREE (m)({ ; vm_page_free(m); ((void)(&vm_page_queue_lock)); }); | |||||
| 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)({ if (!(size <= (1 << 12))) Assert("size <= PAGE_SIZE" , "../linux/dev/glue/block.c", 349); }); | |||||
| 350 | ||||||
| 351 | bh = (struct buffer_head *) kalloc (sizeof (struct buffer_head)); | |||||
| 352 | if (bh) | |||||
| 353 | { | |||||
| 354 | memset (bh, 0, sizeof (struct buffer_head))(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof (struct buffer_head))) ? __constant_c_and_count_memset(((bh)),((0x01010101UL *(unsigned char)(0))),((sizeof (struct buffer_head)))) : __constant_c_memset (((bh)),((0x01010101UL*(unsigned char)(0))),((sizeof (struct buffer_head ))))) : (__builtin_constant_p((sizeof (struct buffer_head))) ? __memset_generic((((bh))),(((0))),(((sizeof (struct buffer_head ))))) : __memset_generic(((bh)),((0)),((sizeof (struct buffer_head )))))); | |||||
| 355 | bh->b_data = alloc_buffer (size); | |||||
| 356 | if (! bh->b_data) | |||||
| 357 | { | |||||
| 358 | kfree ((vm_offset_t) bh, sizeof (struct buffer_head)); | |||||
| 359 | return NULL((void *) 0); | |||||
| 360 | } | |||||
| 361 | bh->b_dev = dev; | |||||
| 362 | bh->b_size = size; | |||||
| 363 | bh->b_state = 1 << BH_Lock2; | |||||
| 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); | |||||
| 374 | kfree ((vm_offset_t) bh, sizeof (*bh)); | |||||
| 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 | { | |||||
| 387 | ll_rw_block (READ0, 1, &bh, 0); | |||||
| 388 | wait_on_buffer (bh); | |||||
| 389 | if (! buffer_uptodate (bh)) | |||||
| 390 | { | |||||
| 391 | __brelse (bh); | |||||
| 392 | return NULL((void *) 0); | |||||
| 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_SIZE1024; | |||||
| 406 | if (blksize_size[MAJOR (dev)((dev) >> 8)] | |||||
| 407 | && blksize_size[MAJOR (dev)((dev) >> 8)][MINOR (dev)((dev) & ((1<<8) - 1))]) | |||||
| 408 | *bsize = blksize_size[MAJOR (dev)((dev) >> 8)][MINOR (dev)((dev) & ((1<<8) - 1))]; | |||||
| 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 inlineinline __attribute__((always_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)((req->rq_dev) >> 8); | |||||
| 421 | cli ()__asm__ __volatile__ ("cli": : :"memory"); | |||||
| 422 | tmp = dev->current_request; | |||||
| 423 | if (! tmp) | |||||
| 424 | { | |||||
| 425 | dev->current_request = req; | |||||
| 426 | (*dev->request_fn) (); | |||||
| 427 | sti ()__asm__ __volatile__ ("sti": : :"memory"); | |||||
| 428 | return; | |||||
| 429 | } | |||||
| 430 | while (tmp->next) | |||||
| 431 | { | |||||
| 432 | if ((IN_ORDER (tmp, req)((tmp)->rq_dev < (req)->rq_dev || (((tmp)->rq_dev == (req)->rq_dev && (tmp)->sector < (req)-> sector))) || ! IN_ORDER (tmp, tmp->next)((tmp)->rq_dev < (tmp->next)->rq_dev || (((tmp)-> rq_dev == (tmp->next)->rq_dev && (tmp)->sector < (tmp->next)->sector)))) | |||||
| 433 | && IN_ORDER (req, tmp->next)((req)->rq_dev < (tmp->next)->rq_dev || (((req)-> rq_dev == (tmp->next)->rq_dev && (req)->sector < (tmp->next)->sector)))) | |||||
| 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)((req->rq_dev) >> 8))) | |||||
| 440 | (*dev->request_fn) (); | |||||
| 441 | sti ()__asm__ __volatile__ ("sti": : :"memory"); | |||||
| 442 | } | |||||
| 443 | ||||||
| 444 | /* Perform the I/O operation RW on the buffer list BH | |||||
| 445 | containing NR buffers. */ | |||||
| 446 | void | |||||
| 447 | ll_rw_block (int rw, int nr, struct buffer_head **bh, int quiet) | |||||
| 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)((bh[0]->b_dev) >> 8); | |||||
| ||||||
| 455 | assert (major < MAX_BLKDEV)({ if (!(major < 128)) Assert("major < MAX_BLKDEV", "../linux/dev/glue/block.c" , 455); }); | |||||
| 456 | ||||||
| 457 | get_block_size (bh[0]->b_dev, &bsize, &bshift); | |||||
| 458 | ||||||
| 459 | if (! linux_auto_config) | |||||
| 460 | { | |||||
| 461 | assert (current_thread ()->pcb->data)({ if (!((active_threads[(0)])->pcb->data)) Assert("current_thread ()->pcb->data" , "../linux/dev/glue/block.c", 461); }); | |||||
| 462 | r = &((struct temp_data *) current_thread ()(active_threads[(0)])->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((void *) 0); | |||||
| 474 | ||||||
| 475 | r->rq_status = RQ_ACTIVE1; | |||||
| 476 | r->rq_dev = bh[0]->b_dev; | |||||
| 477 | r->cmd = rw; | |||||
| 478 | r->errors = 0; | |||||
| 479 | r->quiet = quiet; | |||||
| 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((void *) 0); | |||||
| 486 | r->next = NULL((void *) 0); | |||||
| 487 | ||||||
| 488 | enqueue_request (r); | |||||
| 489 | } | |||||
| 490 | ||||||
| 491 | #define BSIZE(1 << bshift) (1 << bshift) | |||||
| 492 | #define BMASK((1 << bshift) - 1) (BSIZE(1 << bshift) - 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))(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof (struct buffer_head))) ? __constant_c_and_count_memset(((bh)),((0x01010101UL *(unsigned char)(0))),((sizeof (struct buffer_head)))) : __constant_c_memset (((bh)),((0x01010101UL*(unsigned char)(0))),((sizeof (struct buffer_head ))))) : (__builtin_constant_p((sizeof (struct buffer_head))) ? __memset_generic((((bh))),(((0))),(((sizeof (struct buffer_head ))))) : __memset_generic(((bh)),((0)),((sizeof (struct buffer_head )))))); | |||||
| 510 | bh->b_state = 1 << BH_Lock2; | |||||
| 511 | bh->b_dev = dev; | |||||
| 512 | bh->b_blocknr = *off >> bshift; | |||||
| 513 | bh->b_size = BSIZE(1 << bshift); | |||||
| 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)((dev) >> 8)) | |||||
| 518 | { | |||||
| 519 | nsect = gd->part[MINOR (dev)((dev) & ((1<<8) - 1))].nr_sects; | |||||
| 520 | break; | |||||
| 521 | } | |||||
| 522 | if (nsect > 0) | |||||
| 523 | { | |||||
| 524 | sect = bh->b_blocknr << (bshift - 9); | |||||
| 525 | assert ((nsect - sect) > 0)({ if (!((nsect - sect) > 0)) Assert("(nsect - sect) > 0" , "../linux/dev/glue/block.c", 525); }); | |||||
| 526 | if (nsect - sect < (BSIZE(1 << bshift) >> 9)) | |||||
| 527 | bh->b_size = (nsect - sect) << 9; | |||||
| 528 | } | |||||
| 529 | bh->b_data = alloc_buffer (bh->b_size); | |||||
| 530 | if (! bh->b_data) | |||||
| 531 | return -ENOMEM12; | |||||
| 532 | ll_rw_block (READ0, 1, &bh, 0); | |||||
| 533 | wait_on_buffer (bh); | |||||
| 534 | if (buffer_uptodate (bh)) | |||||
| 535 | { | |||||
| 536 | o = *off & BMASK((1 << bshift) - 1); | |||||
| 537 | c = bh->b_size - o; | |||||
| 538 | if (c > *resid) | |||||
| 539 | c = *resid; | |||||
| 540 | if (rw == READ0) | |||||
| 541 | memcpy (*buf, bh->b_data + o, c)(__builtin_constant_p(c) ? __constant_memcpy((*buf),(bh->b_data + o),(c)) : __memcpy((*buf),(bh->b_data + o),(c))); | |||||
| 542 | else | |||||
| 543 | { | |||||
| 544 | memcpy (bh->b_data + o, *buf, c)(__builtin_constant_p(c) ? __constant_memcpy((bh->b_data + o),(*buf),(c)) : __memcpy((bh->b_data + o),(*buf),(c))); | |||||
| 545 | bh->b_state = (1 << BH_Dirty1) | (1 << BH_Lock2); | |||||
| 546 | ll_rw_block (WRITE1, 1, &bh, 0); | |||||
| 547 | wait_on_buffer (bh); | |||||
| 548 | if (! buffer_uptodate (bh)) | |||||
| 549 | { | |||||
| 550 | err = -EIO5; | |||||
| 551 | goto out; | |||||
| 552 | } | |||||
| 553 | } | |||||
| 554 | *buf += c; | |||||
| 555 | *resid -= c; | |||||
| 556 | *off += c; | |||||
| 557 | } | |||||
| 558 | else | |||||
| 559 | err = -EIO5; | |||||
| 560 | out: | |||||
| 561 | free_buffer (bh->b_data, bh->b_size); | |||||
| 562 | return err; | |||||
| 563 | } | |||||
| 564 | ||||||
| 565 | #define BH_Bounce16 16 | |||||
| 566 | #define MAX_BUF8 8 | |||||
| 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_BUF8], *bh, *bhp[MAX_BUF8]; | |||||
| 580 | ||||||
| 581 | assert ((*off & BMASK) == 0)({ if (!((*off & ((1 << bshift) - 1)) == 0)) Assert ("(*off & BMASK) == 0", "../linux/dev/glue/block.c", 581) ; }); | |||||
| 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))(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof (*bh ))) ? __constant_c_and_count_memset(((bh)),((0x01010101UL*(unsigned char)(0))),((sizeof (*bh)))) : __constant_c_memset(((bh)),(( 0x01010101UL*(unsigned char)(0))),((sizeof (*bh))))) : (__builtin_constant_p ((sizeof (*bh))) ? __memset_generic((((bh))),(((0))),(((sizeof (*bh))))) : __memset_generic(((bh)),((0)),((sizeof (*bh))))) ); | |||||
| 588 | bh->b_dev = dev; | |||||
| 589 | bh->b_blocknr = blk; | |||||
| 590 | set_bit (BH_Lock2, &bh->b_state); | |||||
| 591 | if (rw == WRITE1) | |||||
| 592 | set_bit (BH_Dirty1, &bh->b_state); | |||||
| 593 | cc = PAGE_SIZE(1 << 12) - (((int) *buf + (nb << bshift)) & PAGE_MASK((1 << 12)-1)); | |||||
| 594 | if (cc >= BSIZE(1 << bshift) && (((int) *buf + (nb << bshift)) & 511) == 0) | |||||
| 595 | cc &= ~BMASK((1 << bshift) - 1); | |||||
| 596 | else | |||||
| 597 | { | |||||
| 598 | cc = PAGE_SIZE(1 << 12); | |||||
| 599 | set_bit (BH_Bounce16, &bh->b_state); | |||||
| 600 | } | |||||
| 601 | if (cc > ((nbuf - nb) << bshift)) | |||||
| 602 | cc = (nbuf - nb) << bshift; | |||||
| 603 | if (! test_bit (BH_Bounce16, &bh->b_state)) | |||||
| 604 | bh->b_data = (char *) phystokv(pmap_extract (vm_map_pmap (device_io_map),((vm_offset_t)(pmap_extract (((device_io_map)->pmap), (((vm_offset_t ) *buf) + (nb << bshift)))) + 0xC0000000UL) | |||||
| 605 | (((vm_offset_t) *buf)((vm_offset_t)(pmap_extract (((device_io_map)->pmap), (((vm_offset_t ) *buf) + (nb << bshift)))) + 0xC0000000UL) | |||||
| 606 | + (nb << bshift))))((vm_offset_t)(pmap_extract (((device_io_map)->pmap), (((vm_offset_t ) *buf) + (nb << bshift)))) + 0xC0000000UL); | |||||
| 607 | else | |||||
| 608 | { | |||||
| 609 | bh->b_data = alloc_buffer (cc); | |||||
| 610 | if (! bh->b_data) | |||||
| 611 | { | |||||
| 612 | err = -ENOMEM12; | |||||
| 613 | break; | |||||
| 614 | } | |||||
| 615 | if (rw == WRITE1) | |||||
| 616 | memcpy (bh->b_data, *buf + (nb << bshift), cc)(__builtin_constant_p(cc) ? __constant_memcpy((bh->b_data) ,(*buf + (nb << bshift)),(cc)) : __memcpy((bh->b_data ),(*buf + (nb << bshift)),(cc))); | |||||
| 617 | } | |||||
| 618 | bh->b_size = cc; | |||||
| 619 | bhp[i] = bh; | |||||
| 620 | nb += cc >> bshift; | |||||
| 621 | blk += cc >> bshift; | |||||
| 622 | if (++i == MAX_BUF8) | |||||
| 623 | break; | |||||
| 624 | } | |||||
| 625 | if (! err) | |||||
| 626 | { | |||||
| 627 | ll_rw_block (rw, i, bhp, 0); | |||||
| 628 | wait_on_buffer (bhp[i - 1]); | |||||
| 629 | } | |||||
| 630 | for (bh = bhead, cc = 0, j = 0; j < i; cc += bh->b_size, bh++, j++) | |||||
| 631 | { | |||||
| 632 | if (! err && buffer_uptodate (bh) | |||||
| 633 | && rw == READ0 && test_bit (BH_Bounce16, &bh->b_state)) | |||||
| 634 | memcpy (*buf + cc, bh->b_data, bh->b_size)(__builtin_constant_p(bh->b_size) ? __constant_memcpy((*buf + cc),(bh->b_data),(bh->b_size)) : __memcpy((*buf + cc ),(bh->b_data),(bh->b_size))); | |||||
| 635 | else if (! err && ! buffer_uptodate (bh)) | |||||
| 636 | err = -EIO5; | |||||
| 637 | if (test_bit (BH_Bounce16, &bh->b_state)) | |||||
| 638 | free_buffer (bh->b_data, bh->b_size); | |||||
| 639 | } | |||||
| 640 | if (! err) | |||||
| 641 | { | |||||
| 642 | *buf += cc; | |||||
| 643 | *resid -= cc; | |||||
| 644 | *off += cc; | |||||
| 645 | } | |||||
| 646 | return err; | |||||
| 647 | } | |||||
| 648 | ||||||
| 649 | /* Perform read/write operation RW on device DEV | |||||
| 650 | starting at *off to/from buffer BUF of size COUNT. | |||||
| 651 | *OFF is updated if the operation completed successfully. */ | |||||
| 652 | static int | |||||
| 653 | do_rdwr (int rw, kdev_t dev, loff_t *off, char *buf, int count) | |||||
| 654 | { | |||||
| 655 | int bsize, bshift, err = 0, resid = count; | |||||
| 656 | ||||||
| 657 | get_block_size (dev, &bsize, &bshift); | |||||
| 658 | if (*off & BMASK((1 << bshift) - 1)) | |||||
| 659 | err = rdwr_partial (rw, dev, off, &buf, &resid, bshift); | |||||
| 660 | while (resid >= bsize && ! err) | |||||
| 661 | err = rdwr_full (rw, dev, off, &buf, &resid, bshift); | |||||
| 662 | if (! err && resid) | |||||
| 663 | err = rdwr_partial (rw, dev, off, &buf, &resid, bshift); | |||||
| 664 | return err ? err : count - resid; | |||||
| 665 | } | |||||
| 666 | ||||||
| 667 | int | |||||
| 668 | block_write (struct inode *inode, struct file *filp, | |||||
| 669 | const char *buf, int count) | |||||
| 670 | { | |||||
| 671 | return do_rdwr (WRITE1, inode->i_rdev, &filp->f_pos, (char *) buf, count); | |||||
| 672 | } | |||||
| 673 | ||||||
| 674 | int | |||||
| 675 | block_read (struct inode *inode, struct file *filp, char *buf, int count) | |||||
| 676 | { | |||||
| 677 | return do_rdwr (READ0, inode->i_rdev, &filp->f_pos, buf, count); | |||||
| ||||||
| 678 | } | |||||
| 679 | ||||||
| 680 | /* | |||||
| 681 | * This routine checks whether a removable media has been changed, | |||||
| 682 | * and invalidates all buffer-cache-entries in that case. This | |||||
| 683 | * is a relatively slow routine, so we have to try to minimize using | |||||
| 684 | * it. Thus it is called only upon a 'mount' or 'open'. This | |||||
| 685 | * is the best way of combining speed and utility, I think. | |||||
| 686 | * People changing diskettes in the middle of an operation deserve | |||||
| 687 | * to loose :-) | |||||
| 688 | */ | |||||
| 689 | int | |||||
| 690 | check_disk_change (kdev_t dev) | |||||
| 691 | { | |||||
| 692 | unsigned i; | |||||
| 693 | struct file_operations * fops; | |||||
| 694 | ||||||
| 695 | i = MAJOR(dev)((dev) >> 8); | |||||
| 696 | if (i >= MAX_BLKDEV128 || (fops = blkdevs[i].fops) == NULL((void *) 0)) | |||||
| 697 | return 0; | |||||
| 698 | if (fops->check_media_change == NULL((void *) 0)) | |||||
| 699 | return 0; | |||||
| 700 | if (! (*fops->check_media_change) (dev)) | |||||
| 701 | return 0; | |||||
| 702 | ||||||
| 703 | /* printf ("Disk change detected on device %s\n", kdevname(dev));*/ | |||||
| 704 | ||||||
| 705 | if (fops->revalidate) | |||||
| 706 | (*fops->revalidate) (dev); | |||||
| 707 | ||||||
| 708 | return 1; | |||||
| 709 | } | |||||
| 710 | ||||||
| 711 | /* Mach device interface routines. */ | |||||
| 712 | ||||||
| 713 | /* Mach name to Linux major/minor number mapping table. */ | |||||
| 714 | static struct name_map name_to_major[] = | |||||
| 715 | { | |||||
| 716 | /* IDE disks */ | |||||
| 717 | { "hd0", IDE0_MAJOR3, 0, 0 }, | |||||
| 718 | { "hd1", IDE0_MAJOR3, 1, 0 }, | |||||
| 719 | { "hd2", IDE1_MAJOR22, 0, 0 }, | |||||
| 720 | { "hd3", IDE1_MAJOR22, 1, 0 }, | |||||
| 721 | { "hd4", IDE2_MAJOR33, 0, 0 }, | |||||
| 722 | { "hd5", IDE2_MAJOR33, 1, 0 }, | |||||
| 723 | { "hd6", IDE3_MAJOR34, 0, 0 }, | |||||
| 724 | { "hd7", IDE3_MAJOR34, 1, 0 }, | |||||
| 725 | ||||||
| 726 | /* IDE CDROMs */ | |||||
| 727 | { "wcd0", IDE0_MAJOR3, 0, 1 }, | |||||
| 728 | { "wcd1", IDE0_MAJOR3, 1, 1 }, | |||||
| 729 | { "wcd2", IDE1_MAJOR22, 0, 1 }, | |||||
| 730 | { "wcd3", IDE1_MAJOR22, 1, 1 }, | |||||
| 731 | { "wcd4", IDE2_MAJOR33, 0, 1 }, | |||||
| 732 | { "wcd5", IDE2_MAJOR33, 1, 1 }, | |||||
| 733 | { "wcd6", IDE3_MAJOR34, 0, 1 }, | |||||
| 734 | { "wcd7", IDE3_MAJOR34, 1, 1 }, | |||||
| 735 | ||||||
| 736 | /* SCSI disks */ | |||||
| 737 | { "sd0", SCSI_DISK_MAJOR8, 0, 0 }, | |||||
| 738 | { "sd1", SCSI_DISK_MAJOR8, 1, 0 }, | |||||
| 739 | { "sd2", SCSI_DISK_MAJOR8, 2, 0 }, | |||||
| 740 | { "sd3", SCSI_DISK_MAJOR8, 3, 0 }, | |||||
| 741 | { "sd4", SCSI_DISK_MAJOR8, 4, 0 }, | |||||
| 742 | { "sd5", SCSI_DISK_MAJOR8, 5, 0 }, | |||||
| 743 | { "sd6", SCSI_DISK_MAJOR8, 6, 0 }, | |||||
| 744 | { "sd7", SCSI_DISK_MAJOR8, 7, 0 }, | |||||
| 745 | ||||||
| 746 | /* SCSI CDROMs */ | |||||
| 747 | { "cd0", SCSI_CDROM_MAJOR11, 0, 1 }, | |||||
| 748 | { "cd1", SCSI_CDROM_MAJOR11, 1, 1 }, | |||||
| 749 | ||||||
| 750 | /* Floppy disks */ | |||||
| 751 | { "fd0", FLOPPY_MAJOR2, 0, 0 }, | |||||
| 752 | { "fd1", FLOPPY_MAJOR2, 1, 0 }, | |||||
| 753 | }; | |||||
| 754 | ||||||
| 755 | #define NUM_NAMES(sizeof (name_to_major) / sizeof (name_to_major[0])) (sizeof (name_to_major) / sizeof (name_to_major[0])) | |||||
| 756 | ||||||
| 757 | /* One of these is associated with each open instance of a device. */ | |||||
| 758 | struct block_data | |||||
| 759 | { | |||||
| 760 | const char *name; /* Mach name for device */ | |||||
| 761 | int want:1; /* someone is waiting for I/O to complete */ | |||||
| 762 | int open_count; /* number of opens */ | |||||
| 763 | int iocount; /* number of pending I/O operations */ | |||||
| 764 | int part; /* BSD partition number (-1 if none) */ | |||||
| 765 | int flags; /* Linux file flags */ | |||||
| 766 | int mode; /* Linux file mode */ | |||||
| 767 | kdev_t dev; /* Linux device number */ | |||||
| 768 | ipc_port_t port; /* port representing device */ | |||||
| 769 | struct device_struct *ds; /* driver operation table entry */ | |||||
| 770 | struct device device; /* generic device header */ | |||||
| 771 | struct name_map *np; /* name to inode map */ | |||||
| 772 | struct block_data *next; /* forward link */ | |||||
| 773 | }; | |||||
| 774 | ||||||
| 775 | /* List of open devices. */ | |||||
| 776 | static struct block_data *open_list; | |||||
| 777 | ||||||
| 778 | /* Forward declarations. */ | |||||
| 779 | ||||||
| 780 | extern struct device_emulation_ops linux_block_emulation_ops; | |||||
| 781 | ||||||
| 782 | static io_return_t device_close (void *); | |||||
| 783 | static io_return_t device_close_forced (void *, int); | |||||
| 784 | ||||||
| 785 | /* Return a send right for block device BD. */ | |||||
| 786 | static ipc_port_t | |||||
| 787 | dev_to_port (void *bd) | |||||
| 788 | { | |||||
| 789 | return (bd | |||||
| 790 | ? ipc_port_make_send (((struct block_data *) bd)->port) | |||||
| 791 | : IP_NULL((ipc_port_t) ((ipc_object_t) 0))); | |||||
| 792 | } | |||||
| 793 | ||||||
| 794 | /* Return 1 if C is a letter of the alphabet. */ | |||||
| 795 | static inlineinline __attribute__((always_inline)) int | |||||
| 796 | isalpha (int c) | |||||
| 797 | { | |||||
| 798 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); | |||||
| 799 | } | |||||
| 800 | ||||||
| 801 | /* Return 1 if C is a digit. */ | |||||
| 802 | static inlineinline __attribute__((always_inline)) int | |||||
| 803 | isdigit (int c) | |||||
| 804 | { | |||||
| 805 | return c >= '0' && c <= '9'; | |||||
| 806 | } | |||||
| 807 | ||||||
| 808 | /* Find the name map entry for device NAME. | |||||
| 809 | Set *SLICE to be the DOS partition and | |||||
| 810 | *PART the BSD/Mach partition, if any. */ | |||||
| 811 | static struct name_map * | |||||
| 812 | find_name (char *name, int *slice, int *part) | |||||
| 813 | { | |||||
| 814 | char *p, *q; | |||||
| 815 | int i, len; | |||||
| 816 | struct name_map *np; | |||||
| 817 | ||||||
| 818 | /* Parse name into name, unit, DOS partition (slice) and partition. */ | |||||
| 819 | for (*slice = 0, *part = -1, p = name; isalpha (*p); p++) | |||||
| 820 | ; | |||||
| 821 | if (p == name || ! isdigit (*p)) | |||||
| 822 | return NULL((void *) 0); | |||||
| 823 | do | |||||
| 824 | p++; | |||||
| 825 | while (isdigit (*p)); | |||||
| 826 | if (*p) | |||||
| 827 | { | |||||
| 828 | q = p; | |||||
| 829 | if (*q == 's' && isdigit (*(q + 1))) | |||||
| 830 | { | |||||
| 831 | q++; | |||||
| 832 | do | |||||
| 833 | *slice = *slice * 10 + *q++ - '0'; | |||||
| 834 | while (isdigit (*q)); | |||||
| 835 | if (! *q) | |||||
| 836 | goto find_major; | |||||
| 837 | } | |||||
| 838 | if (! isalpha (*q) || *(q + 1)) | |||||
| 839 | return NULL((void *) 0); | |||||
| 840 | *part = *q - 'a'; | |||||
| 841 | } | |||||
| 842 | ||||||
| 843 | find_major: | |||||
| 844 | /* Convert name to major number. */ | |||||
| 845 | for (i = 0, np = name_to_major; i < NUM_NAMES(sizeof (name_to_major) / sizeof (name_to_major[0])); i++, np++) | |||||
| 846 | { | |||||
| 847 | len = strlen (np->name); | |||||
| 848 | if (len == (p - name) && ! strncmp (np->name, name, len)) | |||||
| 849 | return np; | |||||
| 850 | } | |||||
| 851 | return NULL((void *) 0); | |||||
| 852 | } | |||||
| 853 | ||||||
| 854 | /* Attempt to read a BSD disklabel from device DEV. */ | |||||
| 855 | static struct disklabel * | |||||
| 856 | read_bsd_label (kdev_t dev) | |||||
| 857 | { | |||||
| 858 | int bsize, bshift; | |||||
| 859 | struct buffer_head *bh; | |||||
| 860 | struct disklabel *dlp, *lp = NULL((void *) 0); | |||||
| 861 | ||||||
| 862 | get_block_size (dev, &bsize, &bshift); | |||||
| 863 | bh = bread (dev, LBLLOC1 >> (bshift - 9), bsize); | |||||
| 864 | if (bh) | |||||
| 865 | { | |||||
| 866 | dlp = (struct disklabel *) (bh->b_data + ((LBLLOC1 << 9) & (bsize - 1))); | |||||
| 867 | if (dlp->d_magic == DISKMAGIC((unsigned int) 0x82564557U) && dlp->d_magic2 == DISKMAGIC((unsigned int) 0x82564557U)) | |||||
| 868 | { | |||||
| 869 | lp = (struct disklabel *) kalloc (sizeof (*lp)); | |||||
| 870 | assert (lp)({ if (!(lp)) Assert("lp", "../linux/dev/glue/block.c", 870); }); | |||||
| 871 | memcpy (lp, dlp, sizeof (*lp))(__builtin_constant_p(sizeof (*lp)) ? __constant_memcpy((lp), (dlp),(sizeof (*lp))) : __memcpy((lp),(dlp),(sizeof (*lp)))); | |||||
| 872 | } | |||||
| 873 | __brelse (bh); | |||||
| 874 | } | |||||
| 875 | return lp; | |||||
| 876 | } | |||||
| 877 | ||||||
| 878 | /* Attempt to read a VTOC from device DEV. */ | |||||
| 879 | static struct disklabel * | |||||
| 880 | read_vtoc (kdev_t dev) | |||||
| 881 | { | |||||
| 882 | int bshift, bsize, i; | |||||
| 883 | struct buffer_head *bh; | |||||
| 884 | struct evtoc *evp; | |||||
| 885 | struct disklabel *lp = NULL((void *) 0); | |||||
| 886 | ||||||
| 887 | get_block_size (dev, &bsize, &bshift); | |||||
| 888 | bh = bread (dev, PDLOCATION29 >> (bshift - 9), bsize); | |||||
| 889 | if (bh) | |||||
| 890 | { | |||||
| 891 | evp = (struct evtoc *) (bh->b_data + ((PDLOCATION29 << 9) & (bsize - 1))); | |||||
| 892 | if (evp->sanity == VTOC_SANE0x600DDEEE) | |||||
| 893 | { | |||||
| 894 | lp = (struct disklabel *) kalloc (sizeof (*lp)); | |||||
| 895 | assert (lp)({ if (!(lp)) Assert("lp", "../linux/dev/glue/block.c", 895); }); | |||||
| 896 | lp->d_npartitions = evp->nparts; | |||||
| 897 | if (lp->d_npartitions > MAXPARTITIONS8) | |||||
| 898 | lp->d_npartitions = MAXPARTITIONS8; | |||||
| 899 | for (i = 0; i < lp->d_npartitions; i++) | |||||
| 900 | { | |||||
| 901 | lp->d_partitions[i].p_size = evp->part[i].p_size; | |||||
| 902 | lp->d_partitions[i].p_offset = evp->part[i].p_start; | |||||
| 903 | lp->d_partitions[i].p_fstype = FS_BSDFFS7; | |||||
| 904 | } | |||||
| 905 | } | |||||
| 906 | __brelse (bh); | |||||
| 907 | } | |||||
| 908 | return lp; | |||||
| 909 | } | |||||
| 910 | ||||||
| 911 | /* Initialize BSD/Mach partition table for device | |||||
| 912 | specified by NP, DS and *DEV. Check SLICE and *PART for validity. */ | |||||
| 913 | static kern_return_t | |||||
| 914 | init_partition (struct name_map *np, kdev_t *dev, | |||||
| 915 | struct device_struct *ds, int slice, int *part) | |||||
| 916 | { | |||||
| 917 | int i, j; | |||||
| 918 | struct disklabel *lp; | |||||
| 919 | struct gendisk *gd = ds->gd; | |||||
| 920 | struct partition *p; | |||||
| 921 | struct temp_data *d = current_thread ()(active_threads[(0)])->pcb->data; | |||||
| 922 | ||||||
| 923 | if (! gd) | |||||
| 924 | { | |||||
| 925 | *part = -1; | |||||
| 926 | return 0; | |||||
| 927 | } | |||||
| 928 | if (ds->labels) | |||||
| 929 | goto check; | |||||
| 930 | ds->labels = (struct disklabel **) kalloc (sizeof (struct disklabel *) | |||||
| 931 | * gd->max_nr * gd->max_p); | |||||
| 932 | if (! ds->labels) | |||||
| 933 | return D_NO_MEMORY2508; | |||||
| 934 | memset ((void *) ds->labels, 0,(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof (struct disklabel *) * gd->max_nr * gd->max_p)) ? __constant_c_and_count_memset ((((void *) ds->labels)),((0x01010101UL*(unsigned char)(0) )),((sizeof (struct disklabel *) * gd->max_nr * gd->max_p ))) : __constant_c_memset((((void *) ds->labels)),((0x01010101UL *(unsigned char)(0))),((sizeof (struct disklabel *) * gd-> max_nr * gd->max_p)))) : (__builtin_constant_p((sizeof (struct disklabel *) * gd->max_nr * gd->max_p)) ? __memset_generic (((((void *) ds->labels))),(((0))),(((sizeof (struct disklabel *) * gd->max_nr * gd->max_p)))) : __memset_generic(((( void *) ds->labels)),((0)),((sizeof (struct disklabel *) * gd->max_nr * gd->max_p))))) | |||||
| 935 | sizeof (struct disklabel *) * gd->max_nr * gd->max_p)(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof (struct disklabel *) * gd->max_nr * gd->max_p)) ? __constant_c_and_count_memset ((((void *) ds->labels)),((0x01010101UL*(unsigned char)(0) )),((sizeof (struct disklabel *) * gd->max_nr * gd->max_p ))) : __constant_c_memset((((void *) ds->labels)),((0x01010101UL *(unsigned char)(0))),((sizeof (struct disklabel *) * gd-> max_nr * gd->max_p)))) : (__builtin_constant_p((sizeof (struct disklabel *) * gd->max_nr * gd->max_p)) ? __memset_generic (((((void *) ds->labels))),(((0))),(((sizeof (struct disklabel *) * gd->max_nr * gd->max_p)))) : __memset_generic(((( void *) ds->labels)),((0)),((sizeof (struct disklabel *) * gd->max_nr * gd->max_p))))); | |||||
| 936 | for (i = 1; i < gd->max_p; i++) | |||||
| 937 | { | |||||
| 938 | d->inode.i_rdev = *dev | i; | |||||
| 939 | if (gd->part[MINOR (d->inode.i_rdev)((d->inode.i_rdev) & ((1<<8) - 1))].nr_sects <= 0 | |||||
| 940 | || gd->part[MINOR (d->inode.i_rdev)((d->inode.i_rdev) & ((1<<8) - 1))].start_sect < 0) | |||||
| 941 | continue; | |||||
| 942 | linux_intr_pri = SPL66; | |||||
| 943 | d->file.f_flags = 0; | |||||
| 944 | d->file.f_mode = O_RDONLY00; | |||||
| 945 | if (ds->fops->open && (*ds->fops->open) (&d->inode, &d->file)) | |||||
| 946 | continue; | |||||
| 947 | lp = read_bsd_label (d->inode.i_rdev); | |||||
| 948 | if (! lp && gd->part[MINOR (d->inode.i_rdev)((d->inode.i_rdev) & ((1<<8) - 1))].nr_sects > PDLOCATION29) | |||||
| 949 | lp = read_vtoc (d->inode.i_rdev); | |||||
| 950 | if (ds->fops->release) | |||||
| 951 | (*ds->fops->release) (&d->inode, &d->file); | |||||
| 952 | if (lp) | |||||
| 953 | { | |||||
| 954 | if (ds->default_slice == 0) | |||||
| 955 | ds->default_slice = i; | |||||
| 956 | for (j = 0, p = lp->d_partitions; j < lp->d_npartitions; j++, p++) | |||||
| 957 | { | |||||
| 958 | if (p->p_offset < 0 || p->p_size <= 0) | |||||
| 959 | continue; | |||||
| 960 | ||||||
| 961 | /* Sanity check. */ | |||||
| 962 | if (p->p_size > gd->part[MINOR (d->inode.i_rdev)((d->inode.i_rdev) & ((1<<8) - 1))].nr_sects) | |||||
| 963 | p->p_size = gd->part[MINOR (d->inode.i_rdev)((d->inode.i_rdev) & ((1<<8) - 1))].nr_sects; | |||||
| 964 | } | |||||
| 965 | } | |||||
| 966 | ds->labels[MINOR (d->inode.i_rdev)((d->inode.i_rdev) & ((1<<8) - 1))] = lp; | |||||
| 967 | } | |||||
| 968 | ||||||
| 969 | check: | |||||
| 970 | if (*part >= 0 && slice == 0) | |||||
| 971 | slice = ds->default_slice; | |||||
| 972 | if (*part >= 0 && slice == 0) | |||||
| 973 | return D_NO_SUCH_DEVICE2502; | |||||
| 974 | *dev = MKDEV (MAJOR (*dev), MINOR (*dev) | slice)(((((*dev) >> 8)) << 8) | (((*dev) & ((1<< 8) - 1)) | slice)); | |||||
| 975 | if (slice >= gd->max_p | |||||
| 976 | || gd->part[MINOR (*dev)((*dev) & ((1<<8) - 1))].start_sect < 0 | |||||
| 977 | || gd->part[MINOR (*dev)((*dev) & ((1<<8) - 1))].nr_sects <= 0) | |||||
| 978 | return D_NO_SUCH_DEVICE2502; | |||||
| 979 | if (*part >= 0) | |||||
| 980 | { | |||||
| 981 | lp = ds->labels[MINOR (*dev)((*dev) & ((1<<8) - 1))]; | |||||
| 982 | if (! lp | |||||
| 983 | || *part >= lp->d_npartitions | |||||
| 984 | || lp->d_partitions[*part].p_offset < 0 | |||||
| 985 | || lp->d_partitions[*part].p_size <= 0) | |||||
| 986 | return D_NO_SUCH_DEVICE2502; | |||||
| 987 | } | |||||
| 988 | return 0; | |||||
| 989 | } | |||||
| 990 | ||||||
| 991 | #define DECL_DATAstruct temp_data td struct temp_data td | |||||
| 992 | #define INIT_DATA(){ ((&td.pages)->next = (&td.pages)->prev = & td.pages); td.inode.i_rdev = bd->dev; td.file.f_mode = bd-> mode; td.file.f_flags = bd->flags; (active_threads[(0)])-> pcb->data = &td; } \ | |||||
| 993 | { \ | |||||
| 994 | queue_init (&td.pages)((&td.pages)->next = (&td.pages)->prev = &td .pages); \ | |||||
| 995 | td.inode.i_rdev = bd->dev; \ | |||||
| 996 | td.file.f_mode = bd->mode; \ | |||||
| 997 | td.file.f_flags = bd->flags; \ | |||||
| 998 | current_thread ()(active_threads[(0)])->pcb->data = &td; \ | |||||
| 999 | } | |||||
| 1000 | ||||||
| 1001 | static io_return_t | |||||
| 1002 | device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type, | |||||
| 1003 | dev_mode_t mode, char *name, device_t *devp) | |||||
| 1004 | { | |||||
| 1005 | int part, slice, err; | |||||
| 1006 | unsigned major, minor; | |||||
| 1007 | kdev_t dev; | |||||
| 1008 | ipc_port_t notify; | |||||
| 1009 | struct block_data *bd = NULL((void *) 0), *bdp; | |||||
| 1010 | struct device_struct *ds; | |||||
| 1011 | struct gendisk *gd; | |||||
| 1012 | struct name_map *np; | |||||
| 1013 | DECL_DATAstruct temp_data td; | |||||
| 1014 | ||||||
| 1015 | np = find_name (name, &slice, &part); | |||||
| 1016 | if (! np) | |||||
| 1017 | return D_NO_SUCH_DEVICE2502; | |||||
| 1018 | major = np->major; | |||||
| 1019 | ds = &blkdevs[major]; | |||||
| 1020 | ||||||
| 1021 | /* Check that driver exists. */ | |||||
| 1022 | if (! ds->fops) | |||||
| 1023 | return D_NO_SUCH_DEVICE2502; | |||||
| 1024 | ||||||
| 1025 | /* Wait for any other open/close calls to finish. */ | |||||
| 1026 | ds = &blkdevs[major]; | |||||
| 1027 | while (ds->busy) | |||||
| 1028 | { | |||||
| 1029 | ds->want = 1; | |||||
| 1030 | assert_wait ((event_t) ds, FALSE((boolean_t) 0)); | |||||
| 1031 | schedule (); | |||||
| 1032 | } | |||||
| 1033 | ds->busy = 1; | |||||
| 1034 | ||||||
| 1035 | /* Compute minor number. */ | |||||
| 1036 | if (! ds->gd) | |||||
| 1037 | { | |||||
| 1038 | for (gd = gendisk_head; gd && gd->major != major; gd = gd->next) | |||||
| 1039 | ; | |||||
| 1040 | ds->gd = gd; | |||||
| 1041 | } | |||||
| 1042 | minor = np->unit; | |||||
| 1043 | gd = ds->gd; | |||||
| 1044 | if (gd) | |||||
| 1045 | minor <<= gd->minor_shift; | |||||
| 1046 | dev = MKDEV (major, minor)(((major) << 8) | (minor)); | |||||
| 1047 | ||||||
| 1048 | queue_init (&td.pages)((&td.pages)->next = (&td.pages)->prev = &td .pages); | |||||
| 1049 | current_thread ()(active_threads[(0)])->pcb->data = &td; | |||||
| 1050 | ||||||
| 1051 | /* Check partition. */ | |||||
| 1052 | err = init_partition (np, &dev, ds, slice, &part); | |||||
| 1053 | if (err) | |||||
| 1054 | goto out; | |||||
| 1055 | ||||||
| 1056 | /* Initialize file structure. */ | |||||
| 1057 | switch (mode & (D_READ0x1|D_WRITE0x2)) | |||||
| 1058 | { | |||||
| 1059 | case D_WRITE0x2: | |||||
| 1060 | td.file.f_mode = O_WRONLY01; | |||||
| 1061 | break; | |||||
| 1062 | ||||||
| 1063 | case D_READ0x1|D_WRITE0x2: | |||||
| 1064 | td.file.f_mode = O_RDWR02; | |||||
| 1065 | break; | |||||
| 1066 | ||||||
| 1067 | default: | |||||
| 1068 | td.file.f_mode = O_RDONLY00; | |||||
| 1069 | break; | |||||
| 1070 | } | |||||
| 1071 | td.file.f_flags = (mode & D_NODELAY0x4) ? O_NDELAY04000 : 0; | |||||
| 1072 | ||||||
| 1073 | /* Check if the device is currently open. */ | |||||
| 1074 | for (bdp = open_list; bdp; bdp = bdp->next) | |||||
| 1075 | if (bdp->dev == dev | |||||
| 1076 | && bdp->part == part | |||||
| 1077 | && bdp->mode == td.file.f_mode | |||||
| 1078 | && bdp->flags == td.file.f_flags) | |||||
| 1079 | { | |||||
| 1080 | bd = bdp; | |||||
| 1081 | goto out; | |||||
| 1082 | } | |||||
| 1083 | ||||||
| 1084 | /* Open the device. */ | |||||
| 1085 | if (ds->fops->open) | |||||
| 1086 | { | |||||
| 1087 | td.inode.i_rdev = dev; | |||||
| 1088 | linux_intr_pri = SPL66; | |||||
| 1089 | err = (*ds->fops->open) (&td.inode, &td.file); | |||||
| 1090 | if (err) | |||||
| 1091 | { | |||||
| 1092 | err = linux_to_mach_error (err); | |||||
| 1093 | goto out; | |||||
| 1094 | } | |||||
| 1095 | } | |||||
| 1096 | ||||||
| 1097 | /* Allocate and initialize device data. */ | |||||
| 1098 | bd = (struct block_data *) kalloc (sizeof (struct block_data)); | |||||
| 1099 | if (! bd) | |||||
| 1100 | { | |||||
| 1101 | err = D_NO_MEMORY2508; | |||||
| 1102 | goto bad; | |||||
| 1103 | } | |||||
| 1104 | bd->want = 0; | |||||
| 1105 | bd->open_count = 0; | |||||
| 1106 | bd->iocount = 0; | |||||
| 1107 | bd->part = part; | |||||
| 1108 | bd->ds = ds; | |||||
| 1109 | bd->device.emul_data = bd; | |||||
| 1110 | bd->device.emul_ops = &linux_block_emulation_ops; | |||||
| 1111 | bd->dev = dev; | |||||
| 1112 | bd->mode = td.file.f_mode; | |||||
| 1113 | bd->flags = td.file.f_flags; | |||||
| 1114 | bd->port = ipc_port_alloc_kernel ()ipc_port_alloc_special(ipc_space_kernel); | |||||
| 1115 | if (bd->port == IP_NULL((ipc_port_t) ((ipc_object_t) 0))) | |||||
| 1116 | { | |||||
| 1117 | err = KERN_RESOURCE_SHORTAGE6; | |||||
| 1118 | goto bad; | |||||
| 1119 | } | |||||
| 1120 | ipc_kobject_set (bd->port, (ipc_kobject_t) &bd->device, IKOT_DEVICE10); | |||||
| 1121 | notify = ipc_port_make_sonce (bd->port); | |||||
| 1122 | ip_lock (bd->port); | |||||
| 1123 | ipc_port_nsrequest (bd->port, 1, notify, ¬ify); | |||||
| 1124 | assert (notify == IP_NULL)({ if (!(notify == ((ipc_port_t) ((ipc_object_t) 0)))) Assert ("notify == IP_NULL", "../linux/dev/glue/block.c", 1124); }); | |||||
| 1125 | goto out; | |||||
| 1126 | ||||||
| 1127 | bad: | |||||
| 1128 | if (ds->fops->release) | |||||
| 1129 | (*ds->fops->release) (&td.inode, &td.file); | |||||
| 1130 | ||||||
| 1131 | out: | |||||
| 1132 | ds->busy = 0; | |||||
| 1133 | if (ds->want) | |||||
| 1134 | { | |||||
| 1135 | ds->want = 0; | |||||
| 1136 | thread_wakeup ((event_t) ds)thread_wakeup_prim(((event_t) ds), ((boolean_t) 0), 0); | |||||
| 1137 | } | |||||
| 1138 | ||||||
| 1139 | if (bd && bd->open_count > 0) | |||||
| 1140 | { | |||||
| 1141 | if (err) | |||||
| 1142 | *devp = NULL((void *) 0); | |||||
| 1143 | else | |||||
| 1144 | { | |||||
| 1145 | *devp = &bd->device; | |||||
| 1146 | bd->open_count++; | |||||
| 1147 | } | |||||
| 1148 | return err; | |||||
| 1149 | } | |||||
| 1150 | ||||||
| 1151 | if (err) | |||||
| 1152 | { | |||||
| 1153 | if (bd) | |||||
| 1154 | { | |||||
| 1155 | if (bd->port != IP_NULL((ipc_port_t) ((ipc_object_t) 0))) | |||||
| 1156 | { | |||||
| 1157 | ipc_kobject_set (bd->port, IKO_NULL((ipc_kobject_t) 0), IKOT_NONE0); | |||||
| 1158 | ipc_port_dealloc_kernel (bd->port)ipc_port_dealloc_special((bd->port), ipc_space_kernel); | |||||
| 1159 | *devp = IP_NULL((ipc_port_t) ((ipc_object_t) 0)); | |||||
| 1160 | } | |||||
| 1161 | kfree ((vm_offset_t) bd, sizeof (struct block_data)); | |||||
| 1162 | bd = NULL((void *) 0); | |||||
| 1163 | } | |||||
| 1164 | } | |||||
| 1165 | else | |||||
| 1166 | { | |||||
| 1167 | bd->open_count = 1; | |||||
| 1168 | bd->next = open_list; | |||||
| 1169 | open_list = bd; | |||||
| 1170 | *devp = &bd -> device; | |||||
| 1171 | } | |||||
| 1172 | ||||||
| 1173 | if (!IP_VALID (reply_port)(((&(reply_port)->ip_target.ipt_object) != ((ipc_object_t ) 0)) && ((&(reply_port)->ip_target.ipt_object ) != ((ipc_object_t) -1))) && ! err) | |||||
| 1174 | device_close (bd); | |||||
| 1175 | return err; | |||||
| 1176 | } | |||||
| 1177 | ||||||
| 1178 | static io_return_t | |||||
| 1179 | device_close_forced (void *d, int force) | |||||
| 1180 | { | |||||
| 1181 | struct block_data *bd = d, *bdp, **prev; | |||||
| 1182 | struct device_struct *ds = bd->ds; | |||||
| 1183 | DECL_DATAstruct temp_data td; | |||||
| 1184 | ||||||
| 1185 | INIT_DATA (){ ((&td.pages)->next = (&td.pages)->prev = & td.pages); td.inode.i_rdev = bd->dev; td.file.f_mode = bd-> mode; td.file.f_flags = bd->flags; (active_threads[(0)])-> pcb->data = &td; }; | |||||
| 1186 | ||||||
| 1187 | /* Wait for any other open/close to complete. */ | |||||
| 1188 | while (ds->busy) | |||||
| 1189 | { | |||||
| 1190 | ds->want = 1; | |||||
| 1191 | assert_wait ((event_t) ds, FALSE((boolean_t) 0)); | |||||
| 1192 | schedule (); | |||||
| 1193 | } | |||||
| 1194 | ds->busy = 1; | |||||
| 1195 | ||||||
| 1196 | if (force || --bd->open_count == 0) | |||||
| 1197 | { | |||||
| 1198 | /* Wait for pending I/O to complete. */ | |||||
| 1199 | while (bd->iocount > 0) | |||||
| 1200 | { | |||||
| 1201 | bd->want = 1; | |||||
| 1202 | assert_wait ((event_t) bd, FALSE((boolean_t) 0)); | |||||
| 1203 | schedule (); | |||||
| 1204 | } | |||||
| 1205 | ||||||
| 1206 | /* Remove device from open list. */ | |||||
| 1207 | prev = &open_list; | |||||
| 1208 | bdp = open_list; | |||||
| 1209 | while (bdp) | |||||
| 1210 | { | |||||
| 1211 | if (bdp == bd) | |||||
| 1212 | { | |||||
| 1213 | *prev = bdp->next; | |||||
| 1214 | break; | |||||
| 1215 | } | |||||
| 1216 | prev = &bdp->next; | |||||
| 1217 | bdp = bdp->next; | |||||
| 1218 | } | |||||
| 1219 | ||||||
| 1220 | assert (bdp == bd)({ if (!(bdp == bd)) Assert("bdp == bd", "../linux/dev/glue/block.c" , 1220); }); | |||||
| 1221 | ||||||
| 1222 | if (ds->fops->release) | |||||
| 1223 | (*ds->fops->release) (&td.inode, &td.file); | |||||
| 1224 | ||||||
| 1225 | ipc_kobject_set (bd->port, IKO_NULL((ipc_kobject_t) 0), IKOT_NONE0); | |||||
| 1226 | ipc_port_dealloc_kernel (bd->port)ipc_port_dealloc_special((bd->port), ipc_space_kernel); | |||||
| 1227 | kfree ((vm_offset_t) bd, sizeof (struct block_data)); | |||||
| 1228 | } | |||||
| 1229 | ||||||
| 1230 | ds->busy = 0; | |||||
| 1231 | if (ds->want) | |||||
| 1232 | { | |||||
| 1233 | ds->want = 0; | |||||
| 1234 | thread_wakeup ((event_t) ds)thread_wakeup_prim(((event_t) ds), ((boolean_t) 0), 0); | |||||
| 1235 | } | |||||
| 1236 | return D_SUCCESS0; | |||||
| 1237 | } | |||||
| 1238 | ||||||
| 1239 | static io_return_t | |||||
| 1240 | device_close (void *d) | |||||
| 1241 | { | |||||
| 1242 | return device_close_forced (d, 0); | |||||
| 1243 | } | |||||
| 1244 | ||||||
| 1245 | ||||||
| 1246 | #define MAX_COPY(64 << 12) (VM_MAP_COPY_PAGE_LIST_MAX64 << PAGE_SHIFT12) | |||||
| 1247 | ||||||
| 1248 | /* Check block BN and size COUNT for I/O validity | |||||
| 1249 | to from device BD. Set *OFF to the byte offset | |||||
| 1250 | where I/O is to begin and return the size of transfer. */ | |||||
| 1251 | static int | |||||
| 1252 | check_limit (struct block_data *bd, loff_t *off, long bn, int count) | |||||
| 1253 | { | |||||
| 1254 | int major, minor; | |||||
| 1255 | long maxsz, sz; | |||||
| 1256 | struct disklabel *lp = NULL((void *) 0); | |||||
| 1257 | ||||||
| 1258 | if (count <= 0) | |||||
| 1259 | return count; | |||||
| 1260 | ||||||
| 1261 | major = MAJOR (bd->dev)((bd->dev) >> 8); | |||||
| 1262 | minor = MINOR (bd->dev)((bd->dev) & ((1<<8) - 1)); | |||||
| 1263 | ||||||
| 1264 | if (bd->ds->gd) | |||||
| 1265 | { | |||||
| 1266 | if (bd->part >= 0) | |||||
| 1267 | { | |||||
| 1268 | assert (bd->ds->labels)({ if (!(bd->ds->labels)) Assert("bd->ds->labels" , "../linux/dev/glue/block.c", 1268); }); | |||||
| 1269 | assert (bd->ds->labels[minor])({ if (!(bd->ds->labels[minor])) Assert("bd->ds->labels[minor]" , "../linux/dev/glue/block.c", 1269); }); | |||||
| 1270 | lp = bd->ds->labels[minor]; | |||||
| 1271 | maxsz = lp->d_partitions[bd->part].p_size; | |||||
| 1272 | } | |||||
| 1273 | else | |||||
| 1274 | maxsz = bd->ds->gd->part[minor].nr_sects; | |||||
| 1275 | } | |||||
| 1276 | else | |||||
| 1277 | { | |||||
| 1278 | assert (blk_size[major])({ if (!(blk_size[major])) Assert("blk_size[major]", "../linux/dev/glue/block.c" , 1278); }); | |||||
| 1279 | maxsz = blk_size[major][minor] << (BLOCK_SIZE_BITS10 - 9); | |||||
| 1280 | } | |||||
| 1281 | assert (maxsz > 0)({ if (!(maxsz > 0)) Assert("maxsz > 0", "../linux/dev/glue/block.c" , 1281); }); | |||||
| 1282 | sz = maxsz - bn; | |||||
| 1283 | if (sz <= 0) | |||||
| 1284 | return sz; | |||||
| 1285 | if (sz < ((count + 511) >> 9)) | |||||
| 1286 | count = sz << 9; | |||||
| 1287 | if (lp) | |||||
| 1288 | bn += (lp->d_partitions[bd->part].p_offset | |||||
| 1289 | - bd->ds->gd->part[minor].start_sect); | |||||
| 1290 | *off = (loff_t) bn << 9; | |||||
| 1291 | bd->iocount++; | |||||
| 1292 | return count; | |||||
| 1293 | } | |||||
| 1294 | ||||||
| 1295 | static io_return_t | |||||
| 1296 | device_write (void *d, ipc_port_t reply_port, | |||||
| 1297 | mach_msg_type_name_t reply_port_type, dev_mode_t mode, | |||||
| 1298 | recnum_t bn, io_buf_ptr_t data, unsigned int orig_count, | |||||
| 1299 | int *bytes_written) | |||||
| 1300 | { | |||||
| 1301 | int resid, amt, i; | |||||
| 1302 | int count = (int) orig_count; | |||||
| 1303 | io_return_t err = 0; | |||||
| 1304 | vm_map_copy_t copy; | |||||
| 1305 | vm_offset_t addr, uaddr; | |||||
| 1306 | vm_size_t len, size; | |||||
| 1307 | struct block_data *bd = d; | |||||
| 1308 | DECL_DATAstruct temp_data td; | |||||
| 1309 | ||||||
| 1310 | INIT_DATA (){ ((&td.pages)->next = (&td.pages)->prev = & td.pages); td.inode.i_rdev = bd->dev; td.file.f_mode = bd-> mode; td.file.f_flags = bd->flags; (active_threads[(0)])-> pcb->data = &td; }; | |||||
| 1311 | ||||||
| 1312 | *bytes_written = 0; | |||||
| 1313 | ||||||
| 1314 | if (bd->mode == O_RDONLY00) | |||||
| 1315 | return D_INVALID_OPERATION2505; | |||||
| 1316 | if (! bd->ds->fops->write) | |||||
| 1317 | return D_READ_ONLY2509; | |||||
| 1318 | count = check_limit (bd, &td.file.f_pos, bn, count); | |||||
| 1319 | if (count < 0) | |||||
| 1320 | return D_INVALID_SIZE2507; | |||||
| 1321 | if (count == 0) | |||||
| 1322 | { | |||||
| 1323 | vm_map_copy_discard (copy); | |||||
| 1324 | return 0; | |||||
| 1325 | } | |||||
| 1326 | ||||||
| 1327 | resid = count; | |||||
| 1328 | copy = (vm_map_copy_t) data; | |||||
| 1329 | uaddr = copy->offset; | |||||
| 1330 | ||||||
| 1331 | /* Allocate a kernel buffer. */ | |||||
| 1332 | size = round_page (uaddr + count)((vm_offset_t)((((vm_offset_t)(uaddr + count)) + ((1 << 12)-1)) & ~((1 << 12)-1))) - trunc_page (uaddr)((vm_offset_t)(((vm_offset_t)(uaddr)) & ~((1 << 12) -1))); | |||||
| 1333 | if (size > MAX_COPY(64 << 12)) | |||||
| 1334 | size = MAX_COPY(64 << 12); | |||||
| 1335 | addr = vm_map_min (device_io_map)((device_io_map)->hdr.links.start); | |||||
| 1336 | err = vm_map_enter (device_io_map, &addr, size, 0, TRUE((boolean_t) 1), | |||||
| 1337 | NULL((void *) 0), 0, FALSE((boolean_t) 0), VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02), | |||||
| 1338 | VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02), VM_INHERIT_NONE((vm_inherit_t) 2)); | |||||
| 1339 | if (err) | |||||
| 1340 | { | |||||
| 1341 | vm_map_copy_discard (copy); | |||||
| 1342 | goto out; | |||||
| 1343 | } | |||||
| 1344 | ||||||
| 1345 | /* Determine size of I/O this time around. */ | |||||
| 1346 | len = size - (uaddr & PAGE_MASK((1 << 12)-1)); | |||||
| 1347 | if (len > resid) | |||||
| 1348 | len = resid; | |||||
| 1349 | ||||||
| 1350 | while (1) | |||||
| 1351 | { | |||||
| 1352 | /* Map user pages. */ | |||||
| 1353 | for (i = 0; i < copy->cpy_npagesc_u.c_p.npages; i++) | |||||
| 1354 | pmap_enter (vm_map_pmap (device_io_map)((device_io_map)->pmap), | |||||
| 1355 | addr + (i << PAGE_SHIFT12), | |||||
| 1356 | copy->cpy_page_listc_u.c_p.page_list[i]->phys_addr, | |||||
| 1357 | VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02), TRUE((boolean_t) 1)); | |||||
| 1358 | ||||||
| 1359 | /* Do the write. */ | |||||
| 1360 | amt = (*bd->ds->fops->write) (&td.inode, &td.file, | |||||
| 1361 | (char *) addr + (uaddr & PAGE_MASK((1 << 12)-1)), len); | |||||
| 1362 | ||||||
| 1363 | /* Unmap pages and deallocate copy. */ | |||||
| 1364 | pmap_remove (vm_map_pmap (device_io_map)((device_io_map)->pmap), | |||||
| 1365 | addr, addr + (copy->cpy_npagesc_u.c_p.npages << PAGE_SHIFT12)); | |||||
| 1366 | vm_map_copy_discard (copy); | |||||
| 1367 | ||||||
| 1368 | /* Check result of write. */ | |||||
| 1369 | if (amt > 0) | |||||
| 1370 | { | |||||
| 1371 | resid -= amt; | |||||
| 1372 | if (resid == 0) | |||||
| 1373 | break; | |||||
| 1374 | uaddr += amt; | |||||
| 1375 | } | |||||
| 1376 | else | |||||
| 1377 | { | |||||
| 1378 | if (amt < 0) | |||||
| 1379 | err = linux_to_mach_error (amt); | |||||
| 1380 | break; | |||||
| 1381 | } | |||||
| 1382 | ||||||
| 1383 | /* Determine size of I/O this time around and copy in pages. */ | |||||
| 1384 | len = round_page (uaddr + resid)((vm_offset_t)((((vm_offset_t)(uaddr + resid)) + ((1 << 12)-1)) & ~((1 << 12)-1))) - trunc_page (uaddr)((vm_offset_t)(((vm_offset_t)(uaddr)) & ~((1 << 12) -1))); | |||||
| 1385 | if (len > MAX_COPY(64 << 12)) | |||||
| 1386 | len = MAX_COPY(64 << 12); | |||||
| 1387 | len -= uaddr & PAGE_MASK((1 << 12)-1); | |||||
| 1388 | if (len > resid) | |||||
| 1389 | len = resid; | |||||
| 1390 | err = vm_map_copyin_page_list (current_map ()(((active_threads[(0)])->task)->map), uaddr, len, | |||||
| 1391 | FALSE((boolean_t) 0), FALSE((boolean_t) 0), ©, FALSE((boolean_t) 0)); | |||||
| 1392 | if (err) | |||||
| 1393 | break; | |||||
| 1394 | } | |||||
| 1395 | ||||||
| 1396 | /* Delete kernel buffer. */ | |||||
| 1397 | vm_map_remove (device_io_map, addr, addr + size); | |||||
| 1398 | ||||||
| 1399 | out: | |||||
| 1400 | if (--bd->iocount == 0 && bd->want) | |||||
| 1401 | { | |||||
| 1402 | bd->want = 0; | |||||
| 1403 | thread_wakeup ((event_t) bd)thread_wakeup_prim(((event_t) bd), ((boolean_t) 0), 0); | |||||
| 1404 | } | |||||
| 1405 | if (IP_VALID (reply_port)(((&(reply_port)->ip_target.ipt_object) != ((ipc_object_t ) 0)) && ((&(reply_port)->ip_target.ipt_object ) != ((ipc_object_t) -1)))) | |||||
| 1406 | ds_device_write_reply (reply_port, reply_port_type, err, count - resid); | |||||
| 1407 | return MIG_NO_REPLY-305; | |||||
| 1408 | } | |||||
| 1409 | ||||||
| 1410 | static io_return_t | |||||
| 1411 | device_read (void *d, ipc_port_t reply_port, | |||||
| 1412 | mach_msg_type_name_t reply_port_type, dev_mode_t mode, | |||||
| 1413 | recnum_t bn, int count, io_buf_ptr_t *data, | |||||
| 1414 | unsigned *bytes_read) | |||||
| 1415 | { | |||||
| 1416 | boolean_t dirty; | |||||
| 1417 | int resid, amt; | |||||
| 1418 | io_return_t err = 0; | |||||
| 1419 | queue_head_t pages; | |||||
| 1420 | vm_map_copy_t copy; | |||||
| 1421 | vm_offset_t addr, offset, alloc_offset, o; | |||||
| 1422 | vm_object_t object; | |||||
| 1423 | vm_page_t m; | |||||
| 1424 | vm_size_t len, size; | |||||
| 1425 | struct block_data *bd = d; | |||||
| 1426 | DECL_DATAstruct temp_data td; | |||||
| 1427 | ||||||
| 1428 | INIT_DATA (){ ((&td.pages)->next = (&td.pages)->prev = & td.pages); td.inode.i_rdev = bd->dev; td.file.f_mode = bd-> mode; td.file.f_flags = bd->flags; (active_threads[(0)])-> pcb->data = &td; }; | |||||
| 1429 | ||||||
| 1430 | *data = 0; | |||||
| 1431 | *bytes_read = 0; | |||||
| 1432 | ||||||
| 1433 | if (! bd->ds->fops->read) | |||||
| 1434 | return D_INVALID_OPERATION2505; | |||||
| 1435 | count = check_limit (bd, &td.file.f_pos, bn, count); | |||||
| 1436 | if (count < 0) | |||||
| 1437 | return D_INVALID_SIZE2507; | |||||
| 1438 | if (count == 0) | |||||
| 1439 | return 0; | |||||
| 1440 | ||||||
| 1441 | /* Allocate an object to hold the data. */ | |||||
| 1442 | size = round_page (count)((vm_offset_t)((((vm_offset_t)(count)) + ((1 << 12)-1)) & ~((1 << 12)-1))); | |||||
| 1443 | object = vm_object_allocate (size); | |||||
| 1444 | if (! object) | |||||
| 1445 | { | |||||
| 1446 | err = D_NO_MEMORY2508; | |||||
| 1447 | goto out; | |||||
| 1448 | } | |||||
| 1449 | alloc_offset = offset = 0; | |||||
| 1450 | resid = count; | |||||
| 1451 | ||||||
| 1452 | /* Allocate a kernel buffer. */ | |||||
| 1453 | addr = vm_map_min (device_io_map)((device_io_map)->hdr.links.start); | |||||
| 1454 | if (size > MAX_COPY(64 << 12)) | |||||
| 1455 | size = MAX_COPY(64 << 12); | |||||
| 1456 | err = vm_map_enter (device_io_map, &addr, size, 0, TRUE((boolean_t) 1), NULL((void *) 0), | |||||
| 1457 | 0, FALSE((boolean_t) 0), VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02), | |||||
| 1458 | VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02), VM_INHERIT_NONE((vm_inherit_t) 2)); | |||||
| 1459 | if (err) | |||||
| 1460 | goto out; | |||||
| 1461 | ||||||
| 1462 | queue_init (&pages)((&pages)->next = (&pages)->prev = &pages); | |||||
| 1463 | ||||||
| 1464 | while (resid) | |||||
| 1465 | { | |||||
| 1466 | /* Determine size of I/O this time around. */ | |||||
| 1467 | len = round_page (offset + resid)((vm_offset_t)((((vm_offset_t)(offset + resid)) + ((1 << 12)-1)) & ~((1 << 12)-1))) - trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12 )-1))); | |||||
| 1468 | if (len > MAX_COPY(64 << 12)) | |||||
| 1469 | len = MAX_COPY(64 << 12); | |||||
| 1470 | ||||||
| 1471 | /* Map any pages left from previous operation. */ | |||||
| 1472 | o = trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12 )-1))); | |||||
| 1473 | queue_iterate (&pages, m, vm_page_t, pageq)for ((m) = (vm_page_t) ((&pages)->next); !(((&pages )) == ((queue_entry_t)(m))); (m) = (vm_page_t) ((&(m)-> pageq)->next)) | |||||
| 1474 | { | |||||
| 1475 | pmap_enter (vm_map_pmap (device_io_map)((device_io_map)->pmap), | |||||
| 1476 | addr + o - trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12 )-1))), | |||||
| 1477 | m->phys_addr, VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02), TRUE((boolean_t) 1)); | |||||
| 1478 | o += PAGE_SIZE(1 << 12); | |||||
| 1479 | } | |||||
| 1480 | assert (o == alloc_offset)({ if (!(o == alloc_offset)) Assert("o == alloc_offset", "../linux/dev/glue/block.c" , 1480); }); | |||||
| 1481 | ||||||
| 1482 | /* Allocate and map pages. */ | |||||
| 1483 | while (alloc_offset < trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12 )-1))) + len) | |||||
| 1484 | { | |||||
| 1485 | while ((m = vm_page_grab (FALSE((boolean_t) 0))) == 0) | |||||
| 1486 | VM_PAGE_WAIT (0)vm_page_wait(0); | |||||
| 1487 | assert (! m->active && ! m->inactive)({ if (!(! m->active && ! m->inactive)) Assert( "! m->active && ! m->inactive", "../linux/dev/glue/block.c" , 1487); }); | |||||
| 1488 | m->busy = TRUE((boolean_t) 1); | |||||
| 1489 | queue_enter (&pages, m, vm_page_t, pageq){ queue_entry_t prev; prev = (&pages)->prev; if ((& pages) == prev) { (&pages)->next = (queue_entry_t) (m) ; } else { ((vm_page_t)prev)->pageq.next = (queue_entry_t) (m); } (m)->pageq.prev = prev; (m)->pageq.next = &pages ; (&pages)->prev = (queue_entry_t) m; }; | |||||
| 1490 | pmap_enter (vm_map_pmap (device_io_map)((device_io_map)->pmap), | |||||
| 1491 | addr + alloc_offset - trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12 )-1))), | |||||
| 1492 | m->phys_addr, VM_PROT_READ((vm_prot_t) 0x01)|VM_PROT_WRITE((vm_prot_t) 0x02), TRUE((boolean_t) 1)); | |||||
| 1493 | alloc_offset += PAGE_SIZE(1 << 12); | |||||
| 1494 | } | |||||
| 1495 | ||||||
| 1496 | /* Do the read. */ | |||||
| 1497 | amt = len - (offset & PAGE_MASK((1 << 12)-1)); | |||||
| 1498 | if (amt > resid) | |||||
| 1499 | amt = resid; | |||||
| 1500 | amt = (*bd->ds->fops->read) (&td.inode, &td.file, | |||||
| 1501 | (char *) addr + (offset & PAGE_MASK((1 << 12)-1)), amt); | |||||
| 1502 | ||||||
| 1503 | /* Compute number of pages to insert in object. */ | |||||
| 1504 | o = trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12 )-1))); | |||||
| 1505 | if (amt > 0) | |||||
| 1506 | { | |||||
| 1507 | dirty = TRUE((boolean_t) 1); | |||||
| 1508 | resid -= amt; | |||||
| 1509 | if (resid == 0) | |||||
| 1510 | { | |||||
| 1511 | /* Zero any unused space. */ | |||||
| 1512 | if (offset + amt < o + len) | |||||
| 1513 | memset ((void *) (addr + offset - o + amt),(__builtin_constant_p(0) ? (__builtin_constant_p((o + len - offset - amt)) ? __constant_c_and_count_memset((((void *) (addr + offset - o + amt))),((0x01010101UL*(unsigned char)(0))),((o + len - offset - amt))) : __constant_c_memset((((void *) (addr + offset - o + amt))),((0x01010101UL*(unsigned char)(0))),((o + len - offset - amt)))) : (__builtin_constant_p((o + len - offset - amt)) ? __memset_generic(((((void *) (addr + offset - o + amt )))),(((0))),(((o + len - offset - amt)))) : __memset_generic ((((void *) (addr + offset - o + amt))),((0)),((o + len - offset - amt))))) | |||||
| 1514 | 0, o + len - offset - amt)(__builtin_constant_p(0) ? (__builtin_constant_p((o + len - offset - amt)) ? __constant_c_and_count_memset((((void *) (addr + offset - o + amt))),((0x01010101UL*(unsigned char)(0))),((o + len - offset - amt))) : __constant_c_memset((((void *) (addr + offset - o + amt))),((0x01010101UL*(unsigned char)(0))),((o + len - offset - amt)))) : (__builtin_constant_p((o + len - offset - amt)) ? __memset_generic(((((void *) (addr + offset - o + amt )))),(((0))),(((o + len - offset - amt)))) : __memset_generic ((((void *) (addr + offset - o + amt))),((0)),((o + len - offset - amt))))); | |||||
| 1515 | offset = o + len; | |||||
| 1516 | } | |||||
| 1517 | else | |||||
| 1518 | offset += amt; | |||||
| 1519 | } | |||||
| 1520 | else | |||||
| 1521 | { | |||||
| 1522 | dirty = FALSE((boolean_t) 0); | |||||
| 1523 | offset = o + len; | |||||
| 1524 | } | |||||
| 1525 | ||||||
| 1526 | /* Unmap pages and add them to the object. */ | |||||
| 1527 | pmap_remove (vm_map_pmap (device_io_map)((device_io_map)->pmap), addr, addr + len); | |||||
| 1528 | vm_object_lock (object); | |||||
| 1529 | while (o < trunc_page (offset)((vm_offset_t)(((vm_offset_t)(offset)) & ~((1 << 12 )-1)))) | |||||
| 1530 | { | |||||
| 1531 | m = (vm_page_t) queue_first (&pages)((&pages)->next); | |||||
| 1532 | assert (! queue_end (&pages, (queue_entry_t) m))({ if (!(! ((&pages) == ((queue_entry_t) m)))) Assert("! queue_end (&pages, (queue_entry_t) m)" , "../linux/dev/glue/block.c", 1532); }); | |||||
| 1533 | queue_remove (&pages, m, vm_page_t, pageq){ queue_entry_t next, prev; next = (m)->pageq.next; prev = (m)->pageq.prev; if ((&pages) == next) (&pages)-> prev = prev; else ((vm_page_t)next)->pageq.prev = prev; if ((&pages) == prev) (&pages)->next = next; else (( vm_page_t)prev)->pageq.next = next; }; | |||||
| 1534 | assert (m->busy)({ if (!(m->busy)) Assert("m->busy", "../linux/dev/glue/block.c" , 1534); }); | |||||
| 1535 | vm_page_lock_queues (); | |||||
| 1536 | if (dirty) | |||||
| 1537 | { | |||||
| 1538 | PAGE_WAKEUP_DONE (m)({ (m)->busy = ((boolean_t) 0); if ((m)->wanted) { (m)-> wanted = ((boolean_t) 0); thread_wakeup_prim((((event_t) m)), ((boolean_t) 0), 0); } }); | |||||
| 1539 | m->dirty = TRUE((boolean_t) 1); | |||||
| 1540 | vm_page_insert (m, object, o); | |||||
| 1541 | } | |||||
| 1542 | else | |||||
| 1543 | vm_page_free (m); | |||||
| 1544 | vm_page_unlock_queues ()((void)(&vm_page_queue_lock)); | |||||
| 1545 | o += PAGE_SIZE(1 << 12); | |||||
| 1546 | } | |||||
| 1547 | vm_object_unlock (object)((void)(&(object)->Lock)); | |||||
| 1548 | if (amt <= 0) | |||||
| 1549 | { | |||||
| 1550 | if (amt < 0) | |||||
| 1551 | err = linux_to_mach_error (amt); | |||||
| 1552 | break; | |||||
| 1553 | } | |||||
| 1554 | } | |||||
| 1555 | ||||||
| 1556 | /* Delete kernel buffer. */ | |||||
| 1557 | vm_map_remove (device_io_map, addr, addr + size); | |||||
| 1558 | ||||||
| 1559 | assert (queue_empty (&pages))({ if (!((((&pages)) == (((&pages)->next))))) Assert ("queue_empty (&pages)", "../linux/dev/glue/block.c", 1559 ); }); | |||||
| 1560 | ||||||
| 1561 | out: | |||||
| 1562 | if (! err) | |||||
| 1563 | err = vm_map_copyin_object (object, 0, round_page (count)((vm_offset_t)((((vm_offset_t)(count)) + ((1 << 12)-1)) & ~((1 << 12)-1))), ©); | |||||
| 1564 | if (! err) | |||||
| 1565 | { | |||||
| 1566 | *data = (io_buf_ptr_t) copy; | |||||
| 1567 | *bytes_read = count - resid; | |||||
| 1568 | } | |||||
| 1569 | else | |||||
| 1570 | vm_object_deallocate (object); | |||||
| 1571 | if (--bd->iocount == 0 && bd->want) | |||||
| 1572 | { | |||||
| 1573 | bd->want = 0; | |||||
| 1574 | thread_wakeup ((event_t) bd)thread_wakeup_prim(((event_t) bd), ((boolean_t) 0), 0); | |||||
| 1575 | } | |||||
| 1576 | return err; | |||||
| 1577 | } | |||||
| 1578 | ||||||
| 1579 | static io_return_t | |||||
| 1580 | device_get_status (void *d, dev_flavor_t flavor, dev_status_t status, | |||||
| 1581 | mach_msg_type_number_t *status_count) | |||||
| 1582 | { | |||||
| 1583 | struct block_data *bd = d; | |||||
| 1584 | ||||||
| 1585 | switch (flavor) | |||||
| 1586 | { | |||||
| 1587 | case DEV_GET_SIZE0: | |||||
| 1588 | if (disk_major (MAJOR (bd->dev)((bd->dev) >> 8))) | |||||
| 1589 | { | |||||
| 1590 | assert (bd->ds->gd)({ if (!(bd->ds->gd)) Assert("bd->ds->gd", "../linux/dev/glue/block.c" , 1590); }); | |||||
| 1591 | ||||||
| 1592 | if (bd->part >= 0) | |||||
| 1593 | { | |||||
| 1594 | struct disklabel *lp; | |||||
| 1595 | ||||||
| 1596 | assert (bd->ds->labels)({ if (!(bd->ds->labels)) Assert("bd->ds->labels" , "../linux/dev/glue/block.c", 1596); }); | |||||
| 1597 | lp = bd->ds->labels[MINOR (bd->dev)((bd->dev) & ((1<<8) - 1))]; | |||||
| 1598 | assert (lp)({ if (!(lp)) Assert("lp", "../linux/dev/glue/block.c", 1598) ; }); | |||||
| 1599 | (status[DEV_GET_SIZE_DEVICE_SIZE0] | |||||
| 1600 | = lp->d_partitions[bd->part].p_size << 9); | |||||
| 1601 | } | |||||
| 1602 | else | |||||
| 1603 | (status[DEV_GET_SIZE_DEVICE_SIZE0] | |||||
| 1604 | = bd->ds->gd->part[MINOR (bd->dev)((bd->dev) & ((1<<8) - 1))].nr_sects << 9); | |||||
| 1605 | } | |||||
| 1606 | else | |||||
| 1607 | { | |||||
| 1608 | assert (blk_size[MAJOR (bd->dev)])({ if (!(blk_size[((bd->dev) >> 8)])) Assert("blk_size[MAJOR (bd->dev)]" , "../linux/dev/glue/block.c", 1608); }); | |||||
| 1609 | (status[DEV_GET_SIZE_DEVICE_SIZE0] | |||||
| 1610 | = (blk_size[MAJOR (bd->dev)((bd->dev) >> 8)][MINOR (bd->dev)((bd->dev) & ((1<<8) - 1))] | |||||
| 1611 | << BLOCK_SIZE_BITS10)); | |||||
| 1612 | } | |||||
| 1613 | /* It would be nice to return the block size as reported by | |||||
| 1614 | the driver, but a lot of user level code assumes the sector | |||||
| 1615 | size to be 512. */ | |||||
| 1616 | status[DEV_GET_SIZE_RECORD_SIZE1] = 512; | |||||
| 1617 | /* Always return DEV_GET_SIZE_COUNT. This is what all native | |||||
| 1618 | Mach drivers do, and makes it possible to detect the absence | |||||
| 1619 | of the call by setting it to a different value on input. MiG | |||||
| 1620 | makes sure that we will never return more integers than the | |||||
| 1621 | user asked for. */ | |||||
| 1622 | *status_count = DEV_GET_SIZE_COUNT2; | |||||
| 1623 | break; | |||||
| 1624 | ||||||
| 1625 | case DEV_GET_RECORDS1: | |||||
| 1626 | if (disk_major (MAJOR (bd->dev)((bd->dev) >> 8))) | |||||
| 1627 | { | |||||
| 1628 | assert (bd->ds->gd)({ if (!(bd->ds->gd)) Assert("bd->ds->gd", "../linux/dev/glue/block.c" , 1628); }); | |||||
| 1629 | ||||||
| 1630 | if (bd->part >= 0) | |||||
| 1631 | { | |||||
| 1632 | struct disklabel *lp; | |||||
| 1633 | ||||||
| 1634 | assert (bd->ds->labels)({ if (!(bd->ds->labels)) Assert("bd->ds->labels" , "../linux/dev/glue/block.c", 1634); }); | |||||
| 1635 | lp = bd->ds->labels[MINOR (bd->dev)((bd->dev) & ((1<<8) - 1))]; | |||||
| 1636 | assert (lp)({ if (!(lp)) Assert("lp", "../linux/dev/glue/block.c", 1636) ; }); | |||||
| 1637 | (status[DEV_GET_RECORDS_DEVICE_RECORDS0] | |||||
| 1638 | = lp->d_partitions[bd->part].p_size); | |||||
| 1639 | } | |||||
| 1640 | else | |||||
| 1641 | (status[DEV_GET_RECORDS_DEVICE_RECORDS0] | |||||
| 1642 | = bd->ds->gd->part[MINOR (bd->dev)((bd->dev) & ((1<<8) - 1))].nr_sects); | |||||
| 1643 | } | |||||
| 1644 | else | |||||
| 1645 | { | |||||
| 1646 | assert (blk_size[MAJOR (bd->dev)])({ if (!(blk_size[((bd->dev) >> 8)])) Assert("blk_size[MAJOR (bd->dev)]" , "../linux/dev/glue/block.c", 1646); }); | |||||
| 1647 | status[DEV_GET_RECORDS_DEVICE_RECORDS0] | |||||
| 1648 | = (blk_size[MAJOR (bd->dev)((bd->dev) >> 8)][MINOR (bd->dev)((bd->dev) & ((1<<8) - 1))] | |||||
| 1649 | << (BLOCK_SIZE_BITS10 - 9)); | |||||
| 1650 | } | |||||
| 1651 | /* It would be nice to return the block size as reported by | |||||
| 1652 | the driver, but a lot of user level code assumes the sector | |||||
| 1653 | size to be 512. */ | |||||
| 1654 | status[DEV_GET_RECORDS_RECORD_SIZE1] = 512; | |||||
| 1655 | /* Always return DEV_GET_RECORDS_COUNT. This is what all native | |||||
| 1656 | Mach drivers do, and makes it possible to detect the absence | |||||
| 1657 | of the call by setting it to a different value on input. MiG | |||||
| 1658 | makes sure that we will never return more integers than the | |||||
| 1659 | user asked for. */ | |||||
| 1660 | *status_count = DEV_GET_RECORDS_COUNT2; | |||||
| 1661 | break; | |||||
| 1662 | ||||||
| 1663 | case V_GETPARMS(((2U) << (((0 +8)+8)+14)) | ((('v')) << (0 +8)) | (((4)) << 0) | ((sizeof(struct disk_parms)) << ( (0 +8)+8))): | |||||
| 1664 | if (*status_count < (sizeof (struct disk_parms) / sizeof (int))) | |||||
| 1665 | return D_INVALID_OPERATION2505; | |||||
| 1666 | else | |||||
| 1667 | { | |||||
| 1668 | struct disk_parms *dp = status; | |||||
| 1669 | struct hd_geometry hg; | |||||
| 1670 | DECL_DATAstruct temp_data td; | |||||
| 1671 | ||||||
| 1672 | INIT_DATA(){ ((&td.pages)->next = (&td.pages)->prev = & td.pages); td.inode.i_rdev = bd->dev; td.file.f_mode = bd-> mode; td.file.f_flags = bd->flags; (active_threads[(0)])-> pcb->data = &td; }; | |||||
| 1673 | ||||||
| 1674 | if ((*bd->ds->fops->ioctl) (&td.inode, &td.file, | |||||
| 1675 | HDIO_GETGEO0x0301, (unsigned long)&hg)) | |||||
| 1676 | return D_INVALID_OPERATION2505; | |||||
| 1677 | ||||||
| 1678 | dp->dp_type = DPT_WINI1; /* XXX: It may be a floppy... */ | |||||
| 1679 | dp->dp_heads = hg.heads; | |||||
| 1680 | dp->dp_cyls = hg.cylinders; | |||||
| 1681 | dp->dp_sectors = hg.sectors; | |||||
| 1682 | dp->dp_dosheads = hg.heads; | |||||
| 1683 | dp->dp_doscyls = hg.cylinders; | |||||
| 1684 | dp->dp_dossectors = hg.sectors; | |||||
| 1685 | dp->dp_secsiz = 512; /* XXX */ | |||||
| 1686 | dp->dp_ptag = 0; | |||||
| 1687 | dp->dp_pflag = 0; | |||||
| 1688 | ||||||
| 1689 | /* XXX */ | |||||
| 1690 | dp->dp_pstartsec = -1; | |||||
| 1691 | dp->dp_pnumsec = -1; | |||||
| 1692 | ||||||
| 1693 | *status_count = sizeof (struct disk_parms) / sizeof (int); | |||||
| 1694 | } | |||||
| 1695 | ||||||
| 1696 | break; | |||||
| 1697 | ||||||
| 1698 | default: | |||||
| 1699 | return D_INVALID_OPERATION2505; | |||||
| 1700 | } | |||||
| 1701 | ||||||
| 1702 | return D_SUCCESS0; | |||||
| 1703 | } | |||||
| 1704 | ||||||
| 1705 | static io_return_t | |||||
| 1706 | device_set_status (void *d, dev_flavor_t flavor, dev_status_t status, | |||||
| 1707 | mach_msg_type_number_t *status_count) | |||||
| 1708 | { | |||||
| 1709 | struct block_data *bd = d; | |||||
| 1710 | ||||||
| 1711 | switch (flavor) | |||||
| 1712 | { | |||||
| 1713 | case BLKRRPART(((0U) << (((0 +8)+8)+14)) | (((0x12)) << (0 +8)) | (((95)) << 0) | ((0) << ((0 +8)+8))): | |||||
| 1714 | { | |||||
| 1715 | DECL_DATAstruct temp_data td; | |||||
| 1716 | INIT_DATA(){ ((&td.pages)->next = (&td.pages)->prev = & td.pages); td.inode.i_rdev = bd->dev; td.file.f_mode = bd-> mode; td.file.f_flags = bd->flags; (active_threads[(0)])-> pcb->data = &td; }; | |||||
| 1717 | return (*bd->ds->fops->ioctl) (&td.inode, &td.file, flavor, 0); | |||||
| 1718 | } | |||||
| 1719 | } | |||||
| 1720 | ||||||
| 1721 | return D_INVALID_OPERATION2505; | |||||
| 1722 | } | |||||
| 1723 | ||||||
| 1724 | ||||||
| 1725 | static void | |||||
| 1726 | device_no_senders (mach_no_senders_notification_t *ns) | |||||
| 1727 | { | |||||
| 1728 | device_t dev; | |||||
| 1729 | ||||||
| 1730 | dev = dev_port_lookup((ipc_port_t) ns->not_header.msgh_remote_port); | |||||
| 1731 | assert(dev)({ if (!(dev)) Assert("dev", "../linux/dev/glue/block.c", 1731 ); }); | |||||
| 1732 | device_close_forced (dev->emul_data, 1); | |||||
| 1733 | } | |||||
| 1734 | ||||||
| 1735 | struct device_emulation_ops linux_block_emulation_ops = | |||||
| 1736 | { | |||||
| 1737 | NULL((void *) 0), | |||||
| 1738 | NULL((void *) 0), | |||||
| 1739 | dev_to_port, | |||||
| 1740 | device_open, | |||||
| 1741 | device_close, | |||||
| 1742 | device_write, | |||||
| 1743 | NULL((void *) 0), | |||||
| 1744 | device_read, | |||||
| 1745 | NULL((void *) 0), | |||||
| 1746 | device_set_status, | |||||
| 1747 | device_get_status, | |||||
| 1748 | NULL((void *) 0), | |||||
| 1749 | NULL((void *) 0), | |||||
| 1750 | device_no_senders, | |||||
| 1751 | NULL((void *) 0), | |||||
| 1752 | NULL((void *) 0) | |||||
| 1753 | }; |