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