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