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