|
|
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: {
387: ll_rw_block (READ, 1, &bh);
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
447: ll_rw_block (int rw, int nr, struct buffer_head **bh)
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;
479: r->sector = bh[0]->b_blocknr << (bshift - 9);
480: r->current_nr_sectors = bh[0]->b_size >> 9;
481: r->buffer = bh[0]->b_data;
482: r->bh = bh[0];
483: r->bhtail = bh[nr - 1];
484: r->sem = NULL;
485: r->next = NULL;
486:
487: enqueue_request (r);
488: }
489:
490: #define BSIZE (1 << bshift)
491: #define BMASK (BSIZE - 1)
492:
493: /* Perform read/write operation RW on device DEV
494: starting at *off to/from buffer *BUF of size *RESID.
495: The device block size is given by BSHIFT. *OFF and
496: *RESID may be non-multiples of the block size.
497: *OFF, *BUF and *RESID are updated if the operation
498: completed successfully. */
499: static int
500: rdwr_partial (int rw, kdev_t dev, loff_t *off,
501: char **buf, int *resid, int bshift)
502: {
503: int c, err = 0, o;
504: long sect, nsect;
505: struct buffer_head bhead, *bh = &bhead;
506: struct gendisk *gd;
507:
508: memset (bh, 0, sizeof (struct buffer_head));
509: bh->b_state = 1 << BH_Lock;
510: bh->b_dev = dev;
511: bh->b_blocknr = *off >> bshift;
512: bh->b_size = BSIZE;
513:
514: /* Check if this device has non even number of blocks. */
515: for (gd = gendisk_head, nsect = -1; gd; gd = gd->next)
516: if (gd->major == MAJOR (dev))
517: {
518: nsect = gd->part[MINOR (dev)].nr_sects;
519: break;
520: }
521: if (nsect > 0)
522: {
523: sect = bh->b_blocknr << (bshift - 9);
524: assert ((nsect - sect) > 0);
525: if (nsect - sect < (BSIZE >> 9))
526: bh->b_size = (nsect - sect) << 9;
527: }
528: bh->b_data = alloc_buffer (bh->b_size);
529: if (! bh->b_data)
1.1.1.3 ! root 530: return -ENOMEM;
1.1 root 531: ll_rw_block (READ, 1, &bh);
532: wait_on_buffer (bh);
533: if (buffer_uptodate (bh))
534: {
535: o = *off & BMASK;
536: c = bh->b_size - o;
537: if (c > *resid)
538: c = *resid;
539: if (rw == READ)
540: memcpy (*buf, bh->b_data + o, c);
541: else
542: {
543: memcpy (bh->b_data + o, *buf, c);
544: bh->b_state = (1 << BH_Dirty) | (1 << BH_Lock);
545: ll_rw_block (WRITE, 1, &bh);
546: wait_on_buffer (bh);
547: if (! buffer_uptodate (bh))
548: {
1.1.1.3 ! root 549: err = -EIO;
1.1 root 550: goto out;
551: }
552: }
553: *buf += c;
554: *resid -= c;
555: *off += c;
556: }
557: else
1.1.1.3 ! root 558: err = -EIO;
1.1 root 559: out:
560: free_buffer (bh->b_data, bh->b_size);
561: return err;
562: }
563:
564: #define BH_Bounce 16
1.1.1.3 ! root 565: #define MAX_BUF 8
1.1 root 566:
567: /* Perform read/write operation RW on device DEV
568: starting at *off to/from buffer *BUF of size *RESID.
569: The device block size is given by BSHIFT. *OFF and
570: *RESID must be multiples of the block size.
571: *OFF, *BUF and *RESID are updated if the operation
572: completed successfully. */
573: static int
574: rdwr_full (int rw, kdev_t dev, loff_t *off, char **buf, int *resid, int bshift)
575: {
576: int cc, err = 0, i, j, nb, nbuf;
577: long blk;
578: struct buffer_head bhead[MAX_BUF], *bh, *bhp[MAX_BUF];
579:
580: assert ((*off & BMASK) == 0);
581:
582: nbuf = *resid >> bshift;
583: blk = *off >> bshift;
584: for (i = nb = 0, bh = bhead; nb < nbuf; bh++)
585: {
586: memset (bh, 0, sizeof (*bh));
587: bh->b_dev = dev;
588: bh->b_blocknr = blk;
589: set_bit (BH_Lock, &bh->b_state);
590: if (rw == WRITE)
591: set_bit (BH_Dirty, &bh->b_state);
1.1.1.3 ! root 592: cc = PAGE_SIZE - (((int) *buf + (nb << bshift)) & PAGE_MASK);
! 593: if (cc >= BSIZE && (((int) *buf + (nb << bshift)) & 511) == 0)
1.1 root 594: cc &= ~BMASK;
595: else
596: {
597: cc = PAGE_SIZE;
598: set_bit (BH_Bounce, &bh->b_state);
599: }
600: if (cc > ((nbuf - nb) << bshift))
601: cc = (nbuf - nb) << bshift;
602: if (! test_bit (BH_Bounce, &bh->b_state))
1.1.1.3 ! root 603: bh->b_data = (char *) phystokv(pmap_extract (vm_map_pmap (device_io_map),
1.1 root 604: (((vm_offset_t) *buf)
1.1.1.3 ! root 605: + (nb << bshift))));
1.1 root 606: else
607: {
608: bh->b_data = alloc_buffer (cc);
609: if (! bh->b_data)
610: {
1.1.1.3 ! root 611: err = -ENOMEM;
1.1 root 612: break;
613: }
614: if (rw == WRITE)
615: memcpy (bh->b_data, *buf + (nb << bshift), cc);
616: }
617: bh->b_size = cc;
618: bhp[i] = bh;
619: nb += cc >> bshift;
1.1.1.3 ! root 620: blk += cc >> bshift;
1.1 root 621: if (++i == MAX_BUF)
622: break;
623: }
624: if (! err)
625: {
626: ll_rw_block (rw, i, bhp);
627: wait_on_buffer (bhp[i - 1]);
628: }
629: for (bh = bhead, cc = 0, j = 0; j < i; cc += bh->b_size, bh++, j++)
630: {
631: if (! err && buffer_uptodate (bh)
632: && rw == READ && test_bit (BH_Bounce, &bh->b_state))
633: memcpy (*buf + cc, bh->b_data, bh->b_size);
634: else if (! err && ! buffer_uptodate (bh))
1.1.1.3 ! root 635: err = -EIO;
1.1 root 636: if (test_bit (BH_Bounce, &bh->b_state))
637: free_buffer (bh->b_data, bh->b_size);
638: }
639: if (! err)
640: {
641: *buf += cc;
642: *resid -= cc;
643: *off += cc;
644: }
645: return err;
646: }
647:
648: /* Perform read/write operation RW on device DEV
649: starting at *off to/from buffer BUF of size COUNT.
650: *OFF is updated if the operation completed successfully. */
651: static int
652: do_rdwr (int rw, kdev_t dev, loff_t *off, char *buf, int count)
653: {
654: int bsize, bshift, err = 0, resid = count;
655:
656: get_block_size (dev, &bsize, &bshift);
657: if (*off & BMASK)
658: err = rdwr_partial (rw, dev, off, &buf, &resid, bshift);
659: while (resid >= bsize && ! err)
660: err = rdwr_full (rw, dev, off, &buf, &resid, bshift);
661: if (! err && resid)
662: err = rdwr_partial (rw, dev, off, &buf, &resid, bshift);
663: return err ? err : count - resid;
664: }
665:
666: int
667: block_write (struct inode *inode, struct file *filp,
668: const char *buf, int count)
669: {
670: return do_rdwr (WRITE, inode->i_rdev, &filp->f_pos, (char *) buf, count);
671: }
672:
673: int
674: block_read (struct inode *inode, struct file *filp, char *buf, int count)
675: {
676: return do_rdwr (READ, inode->i_rdev, &filp->f_pos, buf, count);
677: }
678:
679: /*
680: * This routine checks whether a removable media has been changed,
681: * and invalidates all buffer-cache-entries in that case. This
682: * is a relatively slow routine, so we have to try to minimize using
683: * it. Thus it is called only upon a 'mount' or 'open'. This
684: * is the best way of combining speed and utility, I think.
685: * People changing diskettes in the middle of an operation deserve
686: * to loose :-)
687: */
688: int
689: check_disk_change (kdev_t dev)
690: {
691: unsigned i;
692: struct file_operations * fops;
693:
694: i = MAJOR(dev);
695: if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
696: return 0;
697: if (fops->check_media_change == NULL)
698: return 0;
699: if (! (*fops->check_media_change) (dev))
700: return 0;
701:
702: /* printf ("Disk change detected on device %s\n", kdevname(dev));*/
703:
704: if (fops->revalidate)
705: (*fops->revalidate) (dev);
706:
707: return 1;
708: }
709:
710: /* Mach device interface routines. */
711:
712: /* Mach name to Linux major/minor number mapping table. */
713: static struct name_map name_to_major[] =
714: {
715: /* IDE disks */
716: { "hd0", IDE0_MAJOR, 0, 0 },
717: { "hd1", IDE0_MAJOR, 1, 0 },
718: { "hd2", IDE1_MAJOR, 0, 0 },
719: { "hd3", IDE1_MAJOR, 1, 0 },
720: { "hd4", IDE2_MAJOR, 0, 0 },
721: { "hd5", IDE2_MAJOR, 1, 0 },
722: { "hd6", IDE3_MAJOR, 0, 0 },
723: { "hd7", IDE3_MAJOR, 1, 0 },
724:
725: /* IDE CDROMs */
726: { "wcd0", IDE0_MAJOR, 0, 1 },
727: { "wcd1", IDE0_MAJOR, 1, 1 },
728: { "wcd2", IDE1_MAJOR, 0, 1 },
729: { "wcd3", IDE1_MAJOR, 1, 1 },
730: { "wcd4", IDE2_MAJOR, 0, 1 },
731: { "wcd5", IDE2_MAJOR, 1, 1 },
732: { "wcd6", IDE3_MAJOR, 0, 1 },
733: { "wcd7", IDE3_MAJOR, 1, 1 },
734:
735: /* SCSI disks */
736: { "sd0", SCSI_DISK_MAJOR, 0, 0 },
737: { "sd1", SCSI_DISK_MAJOR, 1, 0 },
738: { "sd2", SCSI_DISK_MAJOR, 2, 0 },
739: { "sd3", SCSI_DISK_MAJOR, 3, 0 },
740: { "sd4", SCSI_DISK_MAJOR, 4, 0 },
741: { "sd5", SCSI_DISK_MAJOR, 5, 0 },
742: { "sd6", SCSI_DISK_MAJOR, 6, 0 },
743: { "sd7", SCSI_DISK_MAJOR, 7, 0 },
744:
745: /* SCSI CDROMs */
746: { "cd0", SCSI_CDROM_MAJOR, 0, 1 },
747: { "cd1", SCSI_CDROM_MAJOR, 1, 1 },
748:
749: /* Floppy disks */
750: { "fd0", FLOPPY_MAJOR, 0, 0 },
751: { "fd1", FLOPPY_MAJOR, 1, 0 },
752: };
753:
754: #define NUM_NAMES (sizeof (name_to_major) / sizeof (name_to_major[0]))
755:
756: /* One of these is associated with each open instance of a device. */
757: struct block_data
758: {
759: const char *name; /* Mach name for device */
760: int want:1; /* someone is waiting for I/O to complete */
761: int open_count; /* number of opens */
762: int iocount; /* number of pending I/O operations */
763: int part; /* BSD partition number (-1 if none) */
764: int flags; /* Linux file flags */
765: int mode; /* Linux file mode */
766: kdev_t dev; /* Linux device number */
767: ipc_port_t port; /* port representing device */
768: struct device_struct *ds; /* driver operation table entry */
769: struct device device; /* generic device header */
770: struct name_map *np; /* name to inode map */
771: struct block_data *next; /* forward link */
772: };
773:
774: /* List of open devices. */
775: static struct block_data *open_list;
776:
777: /* Forward declarations. */
778:
779: extern struct device_emulation_ops linux_block_emulation_ops;
780:
781: static io_return_t device_close (void *);
1.1.1.3 ! root 782: static io_return_t device_close_forced (void *, int);
1.1 root 783:
784: /* Return a send right for block device BD. */
785: static ipc_port_t
786: dev_to_port (void *bd)
787: {
788: return (bd
789: ? ipc_port_make_send (((struct block_data *) bd)->port)
790: : IP_NULL);
791: }
792:
793: /* Return 1 if C is a letter of the alphabet. */
794: static inline int
795: isalpha (int c)
796: {
797: return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
798: }
799:
800: /* Return 1 if C is a digit. */
801: static inline int
802: isdigit (int c)
803: {
804: return c >= '0' && c <= '9';
805: }
806:
807: /* Find the name map entry for device NAME.
808: Set *SLICE to be the DOS partition and
809: *PART the BSD/Mach partition, if any. */
810: static struct name_map *
811: find_name (char *name, int *slice, int *part)
812: {
813: char *p, *q;
814: int i, len;
815: struct name_map *np;
816:
817: /* Parse name into name, unit, DOS partition (slice) and partition. */
818: for (*slice = 0, *part = -1, p = name; isalpha (*p); p++)
819: ;
820: if (p == name || ! isdigit (*p))
821: return NULL;
822: do
823: p++;
824: while (isdigit (*p));
825: if (*p)
826: {
827: q = p;
828: if (*q == 's' && isdigit (*(q + 1)))
829: {
830: q++;
831: do
832: *slice = *slice * 10 + *q++ - '0';
833: while (isdigit (*q));
834: if (! *q)
835: goto find_major;
836: }
837: if (! isalpha (*q) || *(q + 1))
838: return NULL;
839: *part = *q - 'a';
840: }
841:
842: find_major:
843: /* Convert name to major number. */
844: for (i = 0, np = name_to_major; i < NUM_NAMES; i++, np++)
845: {
846: len = strlen (np->name);
847: if (len == (p - name) && ! strncmp (np->name, name, len))
848: return np;
849: }
850: return NULL;
851: }
852:
853: /* Attempt to read a BSD disklabel from device DEV. */
854: static struct disklabel *
855: read_bsd_label (kdev_t dev)
856: {
857: int bsize, bshift;
858: struct buffer_head *bh;
859: struct disklabel *dlp, *lp = NULL;
860:
861: get_block_size (dev, &bsize, &bshift);
862: bh = bread (dev, LBLLOC >> (bshift - 9), bsize);
863: if (bh)
864: {
865: dlp = (struct disklabel *) (bh->b_data + ((LBLLOC << 9) & (bsize - 1)));
866: if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC)
867: {
868: lp = (struct disklabel *) kalloc (sizeof (*lp));
869: assert (lp);
870: memcpy (lp, dlp, sizeof (*lp));
871: }
872: __brelse (bh);
873: }
874: return lp;
875: }
876:
877: /* Attempt to read a VTOC from device DEV. */
878: static struct disklabel *
879: read_vtoc (kdev_t dev)
880: {
881: int bshift, bsize, i;
882: struct buffer_head *bh;
883: struct evtoc *evp;
884: struct disklabel *lp = NULL;
885:
886: get_block_size (dev, &bsize, &bshift);
887: bh = bread (dev, PDLOCATION >> (bshift - 9), bsize);
888: if (bh)
889: {
890: evp = (struct evtoc *) (bh->b_data + ((PDLOCATION << 9) & (bsize - 1)));
891: if (evp->sanity == VTOC_SANE)
892: {
893: lp = (struct disklabel *) kalloc (sizeof (*lp));
894: assert (lp);
895: lp->d_npartitions = evp->nparts;
896: if (lp->d_npartitions > MAXPARTITIONS)
897: lp->d_npartitions = MAXPARTITIONS;
898: for (i = 0; i < lp->d_npartitions; i++)
899: {
900: lp->d_partitions[i].p_size = evp->part[i].p_size;
901: lp->d_partitions[i].p_offset = evp->part[i].p_start;
902: lp->d_partitions[i].p_fstype = FS_BSDFFS;
903: }
904: }
905: __brelse (bh);
906: }
907: return lp;
908: }
909:
910: /* Initialize BSD/Mach partition table for device
911: specified by NP, DS and *DEV. Check SLICE and *PART for validity. */
912: static kern_return_t
913: init_partition (struct name_map *np, kdev_t *dev,
914: struct device_struct *ds, int slice, int *part)
915: {
1.1.1.3 ! root 916: int i, j;
1.1 root 917: struct disklabel *lp;
918: struct gendisk *gd = ds->gd;
919: struct partition *p;
920: struct temp_data *d = current_thread ()->pcb->data;
921:
922: if (! gd)
923: {
924: *part = -1;
925: return 0;
926: }
927: if (ds->labels)
928: goto check;
929: ds->labels = (struct disklabel **) kalloc (sizeof (struct disklabel *)
930: * gd->max_nr * gd->max_p);
931: if (! ds->labels)
932: return D_NO_MEMORY;
933: memset ((void *) ds->labels, 0,
934: sizeof (struct disklabel *) * gd->max_nr * gd->max_p);
935: for (i = 1; i < gd->max_p; i++)
936: {
937: d->inode.i_rdev = *dev | i;
938: if (gd->part[MINOR (d->inode.i_rdev)].nr_sects <= 0
939: || gd->part[MINOR (d->inode.i_rdev)].start_sect < 0)
940: continue;
1.1.1.3 ! root 941: linux_intr_pri = SPL6;
1.1 root 942: d->file.f_flags = 0;
943: d->file.f_mode = O_RDONLY;
944: if (ds->fops->open && (*ds->fops->open) (&d->inode, &d->file))
945: continue;
946: lp = read_bsd_label (d->inode.i_rdev);
1.1.1.3 ! root 947: if (! lp && gd->part[MINOR (d->inode.i_rdev)].nr_sects > PDLOCATION)
1.1 root 948: lp = read_vtoc (d->inode.i_rdev);
949: if (ds->fops->release)
950: (*ds->fops->release) (&d->inode, &d->file);
951: if (lp)
952: {
953: if (ds->default_slice == 0)
954: ds->default_slice = i;
955: for (j = 0, p = lp->d_partitions; j < lp->d_npartitions; j++, p++)
956: {
957: if (p->p_offset < 0 || p->p_size <= 0)
958: continue;
959:
960: /* Sanity check. */
961: if (p->p_size > gd->part[MINOR (d->inode.i_rdev)].nr_sects)
962: p->p_size = gd->part[MINOR (d->inode.i_rdev)].nr_sects;
963: }
964: }
965: ds->labels[MINOR (d->inode.i_rdev)] = lp;
966: }
967:
968: check:
969: if (*part >= 0 && slice == 0)
970: slice = ds->default_slice;
971: if (*part >= 0 && slice == 0)
972: return D_NO_SUCH_DEVICE;
973: *dev = MKDEV (MAJOR (*dev), MINOR (*dev) | slice);
974: if (slice >= gd->max_p
975: || gd->part[MINOR (*dev)].start_sect < 0
976: || gd->part[MINOR (*dev)].nr_sects <= 0)
977: return D_NO_SUCH_DEVICE;
978: if (*part >= 0)
979: {
980: lp = ds->labels[MINOR (*dev)];
981: if (! lp
982: || *part >= lp->d_npartitions
983: || lp->d_partitions[*part].p_offset < 0
984: || lp->d_partitions[*part].p_size <= 0)
985: return D_NO_SUCH_DEVICE;
986: }
987: return 0;
988: }
989:
990: #define DECL_DATA struct temp_data td
991: #define INIT_DATA() \
992: { \
993: queue_init (&td.pages); \
994: td.inode.i_rdev = bd->dev; \
995: td.file.f_mode = bd->mode; \
996: td.file.f_flags = bd->flags; \
997: current_thread ()->pcb->data = &td; \
998: }
999:
1000: static io_return_t
1001: device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
1002: dev_mode_t mode, char *name, device_t *devp)
1003: {
1004: int part, slice, err;
1005: unsigned major, minor;
1006: kdev_t dev;
1007: ipc_port_t notify;
1008: struct block_data *bd = NULL, *bdp;
1009: struct device_struct *ds;
1010: struct gendisk *gd;
1011: struct name_map *np;
1012: DECL_DATA;
1013:
1014: np = find_name (name, &slice, &part);
1015: if (! np)
1016: return D_NO_SUCH_DEVICE;
1017: major = np->major;
1018: ds = &blkdevs[major];
1019:
1020: /* Check that driver exists. */
1021: if (! ds->fops)
1022: return D_NO_SUCH_DEVICE;
1023:
1024: /* Wait for any other open/close calls to finish. */
1025: ds = &blkdevs[major];
1026: while (ds->busy)
1027: {
1028: ds->want = 1;
1029: assert_wait ((event_t) ds, FALSE);
1030: schedule ();
1031: }
1032: ds->busy = 1;
1033:
1034: /* Compute minor number. */
1035: if (! ds->gd)
1036: {
1037: for (gd = gendisk_head; gd && gd->major != major; gd = gd->next)
1038: ;
1039: ds->gd = gd;
1040: }
1041: minor = np->unit;
1042: gd = ds->gd;
1043: if (gd)
1044: minor <<= gd->minor_shift;
1045: dev = MKDEV (major, minor);
1046:
1047: queue_init (&td.pages);
1048: current_thread ()->pcb->data = &td;
1049:
1050: /* Check partition. */
1051: err = init_partition (np, &dev, ds, slice, &part);
1052: if (err)
1053: goto out;
1054:
1055: /* Initialize file structure. */
1056: switch (mode & (D_READ|D_WRITE))
1057: {
1058: case D_WRITE:
1059: td.file.f_mode = O_WRONLY;
1060: break;
1061:
1062: case D_READ|D_WRITE:
1063: td.file.f_mode = O_RDWR;
1064: break;
1065:
1066: default:
1067: td.file.f_mode = O_RDONLY;
1068: break;
1069: }
1070: td.file.f_flags = (mode & D_NODELAY) ? O_NDELAY : 0;
1071:
1072: /* Check if the device is currently open. */
1073: for (bdp = open_list; bdp; bdp = bdp->next)
1074: if (bdp->dev == dev
1075: && bdp->part == part
1076: && bdp->mode == td.file.f_mode
1077: && bdp->flags == td.file.f_flags)
1078: {
1079: bd = bdp;
1080: goto out;
1081: }
1082:
1083: /* Open the device. */
1084: if (ds->fops->open)
1085: {
1086: td.inode.i_rdev = dev;
1.1.1.3 ! root 1087: linux_intr_pri = SPL6;
1.1 root 1088: err = (*ds->fops->open) (&td.inode, &td.file);
1089: if (err)
1090: {
1091: err = linux_to_mach_error (err);
1092: goto out;
1093: }
1094: }
1095:
1096: /* Allocate and initialize device data. */
1097: bd = (struct block_data *) kalloc (sizeof (struct block_data));
1098: if (! bd)
1099: {
1100: err = D_NO_MEMORY;
1101: goto bad;
1102: }
1103: bd->want = 0;
1104: bd->open_count = 0;
1105: bd->iocount = 0;
1106: bd->part = part;
1107: bd->ds = ds;
1108: bd->device.emul_data = bd;
1109: bd->device.emul_ops = &linux_block_emulation_ops;
1110: bd->dev = dev;
1111: bd->mode = td.file.f_mode;
1112: bd->flags = td.file.f_flags;
1113: bd->port = ipc_port_alloc_kernel ();
1114: if (bd->port == IP_NULL)
1115: {
1116: err = KERN_RESOURCE_SHORTAGE;
1117: goto bad;
1118: }
1119: ipc_kobject_set (bd->port, (ipc_kobject_t) &bd->device, IKOT_DEVICE);
1120: notify = ipc_port_make_sonce (bd->port);
1121: ip_lock (bd->port);
1122: ipc_port_nsrequest (bd->port, 1, notify, ¬ify);
1123: assert (notify == IP_NULL);
1124: goto out;
1125:
1126: bad:
1127: if (ds->fops->release)
1128: (*ds->fops->release) (&td.inode, &td.file);
1129:
1130: out:
1131: ds->busy = 0;
1132: if (ds->want)
1133: {
1134: ds->want = 0;
1135: thread_wakeup ((event_t) ds);
1136: }
1137:
1138: if (bd && bd->open_count > 0)
1139: {
1140: if (err)
1141: *devp = NULL;
1142: else
1143: {
1144: *devp = &bd->device;
1145: bd->open_count++;
1146: }
1147: return err;
1148: }
1149:
1150: if (err)
1151: {
1152: if (bd)
1153: {
1154: if (bd->port != IP_NULL)
1155: {
1156: ipc_kobject_set (bd->port, IKO_NULL, IKOT_NONE);
1157: ipc_port_dealloc_kernel (bd->port);
1.1.1.3 ! root 1158: *devp = IP_NULL;
1.1 root 1159: }
1160: kfree ((vm_offset_t) bd, sizeof (struct block_data));
1161: bd = NULL;
1162: }
1163: }
1164: else
1165: {
1166: bd->open_count = 1;
1167: bd->next = open_list;
1168: open_list = bd;
1.1.1.3 ! root 1169: *devp = &bd -> device;
1.1 root 1170: }
1171:
1.1.1.3 ! root 1172: if (!IP_VALID (reply_port) && ! err)
1.1 root 1173: device_close (bd);
1.1.1.3 ! root 1174: return err;
1.1 root 1175: }
1176:
1177: static io_return_t
1.1.1.3 ! root 1178: device_close_forced (void *d, int force)
1.1 root 1179: {
1180: struct block_data *bd = d, *bdp, **prev;
1181: struct device_struct *ds = bd->ds;
1182: DECL_DATA;
1183:
1184: INIT_DATA ();
1185:
1186: /* Wait for any other open/close to complete. */
1187: while (ds->busy)
1188: {
1189: ds->want = 1;
1190: assert_wait ((event_t) ds, FALSE);
1191: schedule ();
1192: }
1193: ds->busy = 1;
1194:
1.1.1.3 ! root 1195: if (force || --bd->open_count == 0)
1.1 root 1196: {
1197: /* Wait for pending I/O to complete. */
1198: while (bd->iocount > 0)
1199: {
1200: bd->want = 1;
1201: assert_wait ((event_t) bd, FALSE);
1202: schedule ();
1203: }
1204:
1205: /* Remove device from open list. */
1206: prev = &open_list;
1207: bdp = open_list;
1208: while (bdp)
1209: {
1210: if (bdp == bd)
1211: {
1212: *prev = bdp->next;
1213: break;
1214: }
1215: prev = &bdp->next;
1216: bdp = bdp->next;
1217: }
1218:
1219: assert (bdp == bd);
1220:
1221: if (ds->fops->release)
1222: (*ds->fops->release) (&td.inode, &td.file);
1223:
1224: ipc_kobject_set (bd->port, IKO_NULL, IKOT_NONE);
1225: ipc_port_dealloc_kernel (bd->port);
1226: kfree ((vm_offset_t) bd, sizeof (struct block_data));
1227: }
1228:
1229: ds->busy = 0;
1230: if (ds->want)
1231: {
1232: ds->want = 0;
1233: thread_wakeup ((event_t) ds);
1234: }
1235: return D_SUCCESS;
1236: }
1237:
1.1.1.3 ! root 1238: static io_return_t
! 1239: device_close (void *d)
! 1240: {
! 1241: return device_close_forced (d, 0);
! 1242: }
! 1243:
! 1244:
1.1 root 1245: #define MAX_COPY (VM_MAP_COPY_PAGE_LIST_MAX << PAGE_SHIFT)
1246:
1247: /* Check block BN and size COUNT for I/O validity
1248: to from device BD. Set *OFF to the byte offset
1249: where I/O is to begin and return the size of transfer. */
1250: static int
1251: check_limit (struct block_data *bd, loff_t *off, long bn, int count)
1252: {
1253: int major, minor;
1254: long maxsz, sz;
1255: struct disklabel *lp = NULL;
1256:
1257: if (count <= 0)
1258: return count;
1259:
1260: major = MAJOR (bd->dev);
1261: minor = MINOR (bd->dev);
1262:
1263: if (bd->ds->gd)
1264: {
1265: if (bd->part >= 0)
1266: {
1267: assert (bd->ds->labels);
1268: assert (bd->ds->labels[minor]);
1269: lp = bd->ds->labels[minor];
1270: maxsz = lp->d_partitions[bd->part].p_size;
1271: }
1272: else
1273: maxsz = bd->ds->gd->part[minor].nr_sects;
1274: }
1275: else
1276: {
1277: assert (blk_size[major]);
1278: maxsz = blk_size[major][minor] << (BLOCK_SIZE_BITS - 9);
1279: }
1280: assert (maxsz > 0);
1281: sz = maxsz - bn;
1282: if (sz <= 0)
1283: return sz;
1284: if (sz < ((count + 511) >> 9))
1285: count = sz << 9;
1286: if (lp)
1287: bn += (lp->d_partitions[bd->part].p_offset
1288: - bd->ds->gd->part[minor].start_sect);
1289: *off = (loff_t) bn << 9;
1290: bd->iocount++;
1291: return count;
1292: }
1293:
1294: static io_return_t
1295: device_write (void *d, ipc_port_t reply_port,
1296: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
1297: recnum_t bn, io_buf_ptr_t data, unsigned int orig_count,
1298: int *bytes_written)
1299: {
1300: int resid, amt, i;
1301: int count = (int) orig_count;
1302: io_return_t err = 0;
1303: vm_map_copy_t copy;
1304: vm_offset_t addr, uaddr;
1305: vm_size_t len, size;
1306: struct block_data *bd = d;
1307: DECL_DATA;
1308:
1309: INIT_DATA ();
1310:
1311: *bytes_written = 0;
1312:
1313: if (bd->mode == O_RDONLY)
1314: return D_INVALID_OPERATION;
1315: if (! bd->ds->fops->write)
1316: return D_READ_ONLY;
1317: count = check_limit (bd, &td.file.f_pos, bn, count);
1318: if (count < 0)
1319: return D_INVALID_SIZE;
1320: if (count == 0)
1321: {
1322: vm_map_copy_discard (copy);
1323: return 0;
1324: }
1325:
1326: resid = count;
1327: copy = (vm_map_copy_t) data;
1328: uaddr = copy->offset;
1329:
1330: /* Allocate a kernel buffer. */
1331: size = round_page (uaddr + count) - trunc_page (uaddr);
1332: if (size > MAX_COPY)
1333: size = MAX_COPY;
1334: addr = vm_map_min (device_io_map);
1335: err = vm_map_enter (device_io_map, &addr, size, 0, TRUE,
1336: NULL, 0, FALSE, VM_PROT_READ|VM_PROT_WRITE,
1337: VM_PROT_READ|VM_PROT_WRITE, VM_INHERIT_NONE);
1338: if (err)
1339: {
1340: vm_map_copy_discard (copy);
1341: goto out;
1342: }
1343:
1344: /* Determine size of I/O this time around. */
1345: len = size - (uaddr & PAGE_MASK);
1346: if (len > resid)
1347: len = resid;
1348:
1349: while (1)
1350: {
1351: /* Map user pages. */
1352: for (i = 0; i < copy->cpy_npages; i++)
1353: pmap_enter (vm_map_pmap (device_io_map),
1354: addr + (i << PAGE_SHIFT),
1355: copy->cpy_page_list[i]->phys_addr,
1356: VM_PROT_READ|VM_PROT_WRITE, TRUE);
1357:
1358: /* Do the write. */
1359: amt = (*bd->ds->fops->write) (&td.inode, &td.file,
1360: (char *) addr + (uaddr & PAGE_MASK), len);
1361:
1362: /* Unmap pages and deallocate copy. */
1363: pmap_remove (vm_map_pmap (device_io_map),
1364: addr, addr + (copy->cpy_npages << PAGE_SHIFT));
1365: vm_map_copy_discard (copy);
1366:
1367: /* Check result of write. */
1368: if (amt > 0)
1369: {
1370: resid -= amt;
1371: if (resid == 0)
1372: break;
1373: uaddr += amt;
1374: }
1375: else
1376: {
1377: if (amt < 0)
1378: err = linux_to_mach_error (amt);
1379: break;
1380: }
1381:
1382: /* Determine size of I/O this time around and copy in pages. */
1383: len = round_page (uaddr + resid) - trunc_page (uaddr);
1384: if (len > MAX_COPY)
1385: len = MAX_COPY;
1386: len -= uaddr & PAGE_MASK;
1387: if (len > resid)
1388: len = resid;
1389: err = vm_map_copyin_page_list (current_map (), uaddr, len,
1390: FALSE, FALSE, ©, FALSE);
1391: if (err)
1392: break;
1393: }
1394:
1395: /* Delete kernel buffer. */
1396: vm_map_remove (device_io_map, addr, addr + size);
1397:
1398: out:
1399: if (--bd->iocount == 0 && bd->want)
1400: {
1401: bd->want = 0;
1402: thread_wakeup ((event_t) bd);
1403: }
1404: if (IP_VALID (reply_port))
1405: ds_device_write_reply (reply_port, reply_port_type, err, count - resid);
1406: return MIG_NO_REPLY;
1407: }
1408:
1409: static io_return_t
1410: device_read (void *d, ipc_port_t reply_port,
1411: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
1412: recnum_t bn, int count, io_buf_ptr_t *data,
1413: unsigned *bytes_read)
1414: {
1415: boolean_t dirty;
1416: int resid, amt;
1417: io_return_t err = 0;
1418: queue_head_t pages;
1419: vm_map_copy_t copy;
1420: vm_offset_t addr, offset, alloc_offset, o;
1421: vm_object_t object;
1422: vm_page_t m;
1423: vm_size_t len, size;
1424: struct block_data *bd = d;
1425: DECL_DATA;
1426:
1427: INIT_DATA ();
1428:
1429: *data = 0;
1430: *bytes_read = 0;
1431:
1432: if (! bd->ds->fops->read)
1433: return D_INVALID_OPERATION;
1434: count = check_limit (bd, &td.file.f_pos, bn, count);
1435: if (count < 0)
1436: return D_INVALID_SIZE;
1437: if (count == 0)
1438: return 0;
1439:
1440: /* Allocate an object to hold the data. */
1441: size = round_page (count);
1442: object = vm_object_allocate (size);
1443: if (! object)
1444: {
1445: err = D_NO_MEMORY;
1446: goto out;
1447: }
1448: alloc_offset = offset = 0;
1449: resid = count;
1450:
1451: /* Allocate a kernel buffer. */
1452: addr = vm_map_min (device_io_map);
1453: if (size > MAX_COPY)
1454: size = MAX_COPY;
1455: err = vm_map_enter (device_io_map, &addr, size, 0, TRUE, NULL,
1456: 0, FALSE, VM_PROT_READ|VM_PROT_WRITE,
1457: VM_PROT_READ|VM_PROT_WRITE, VM_INHERIT_NONE);
1458: if (err)
1459: goto out;
1460:
1461: queue_init (&pages);
1462:
1463: while (resid)
1464: {
1465: /* Determine size of I/O this time around. */
1466: len = round_page (offset + resid) - trunc_page (offset);
1467: if (len > MAX_COPY)
1468: len = MAX_COPY;
1469:
1470: /* Map any pages left from previous operation. */
1471: o = trunc_page (offset);
1472: queue_iterate (&pages, m, vm_page_t, pageq)
1473: {
1474: pmap_enter (vm_map_pmap (device_io_map),
1475: addr + o - trunc_page (offset),
1476: m->phys_addr, VM_PROT_READ|VM_PROT_WRITE, TRUE);
1477: o += PAGE_SIZE;
1478: }
1479: assert (o == alloc_offset);
1480:
1481: /* Allocate and map pages. */
1482: while (alloc_offset < trunc_page (offset) + len)
1483: {
1.1.1.2 root 1484: while ((m = vm_page_grab (FALSE)) == 0)
1.1 root 1485: VM_PAGE_WAIT (0);
1486: assert (! m->active && ! m->inactive);
1487: m->busy = TRUE;
1488: queue_enter (&pages, m, vm_page_t, pageq);
1489: pmap_enter (vm_map_pmap (device_io_map),
1490: addr + alloc_offset - trunc_page (offset),
1491: m->phys_addr, VM_PROT_READ|VM_PROT_WRITE, TRUE);
1492: alloc_offset += PAGE_SIZE;
1493: }
1494:
1495: /* Do the read. */
1496: amt = len - (offset & PAGE_MASK);
1497: if (amt > resid)
1498: amt = resid;
1499: amt = (*bd->ds->fops->read) (&td.inode, &td.file,
1500: (char *) addr + (offset & PAGE_MASK), amt);
1501:
1502: /* Compute number of pages to insert in object. */
1503: o = trunc_page (offset);
1504: if (amt > 0)
1505: {
1506: dirty = TRUE;
1507: resid -= amt;
1508: if (resid == 0)
1509: {
1510: /* Zero any unused space. */
1511: if (offset + amt < o + len)
1512: memset ((void *) (addr + offset - o + amt),
1513: 0, o + len - offset - amt);
1514: offset = o + len;
1515: }
1516: else
1517: offset += amt;
1518: }
1519: else
1520: {
1521: dirty = FALSE;
1522: offset = o + len;
1523: }
1524:
1525: /* Unmap pages and add them to the object. */
1526: pmap_remove (vm_map_pmap (device_io_map), addr, addr + len);
1527: vm_object_lock (object);
1528: while (o < trunc_page (offset))
1529: {
1530: m = (vm_page_t) queue_first (&pages);
1531: assert (! queue_end (&pages, (queue_entry_t) m));
1532: queue_remove (&pages, m, vm_page_t, pageq);
1533: assert (m->busy);
1534: vm_page_lock_queues ();
1535: if (dirty)
1536: {
1537: PAGE_WAKEUP_DONE (m);
1538: m->dirty = TRUE;
1539: vm_page_insert (m, object, o);
1540: }
1541: else
1542: vm_page_free (m);
1543: vm_page_unlock_queues ();
1544: o += PAGE_SIZE;
1545: }
1546: vm_object_unlock (object);
1547: if (amt <= 0)
1548: {
1549: if (amt < 0)
1550: err = linux_to_mach_error (amt);
1551: break;
1552: }
1553: }
1554:
1555: /* Delete kernel buffer. */
1556: vm_map_remove (device_io_map, addr, addr + size);
1557:
1558: assert (queue_empty (&pages));
1559:
1560: out:
1561: if (! err)
1562: err = vm_map_copyin_object (object, 0, round_page (count), ©);
1563: if (! err)
1564: {
1565: *data = (io_buf_ptr_t) copy;
1566: *bytes_read = count - resid;
1567: }
1568: else
1569: vm_object_deallocate (object);
1570: if (--bd->iocount == 0 && bd->want)
1571: {
1572: bd->want = 0;
1573: thread_wakeup ((event_t) bd);
1574: }
1575: return err;
1576: }
1577:
1578: static io_return_t
1579: device_get_status (void *d, dev_flavor_t flavor, dev_status_t status,
1580: mach_msg_type_number_t *status_count)
1581: {
1582: struct block_data *bd = d;
1583:
1584: switch (flavor)
1585: {
1586: case DEV_GET_SIZE:
1587: if (disk_major (MAJOR (bd->dev)))
1588: {
1589: assert (bd->ds->gd);
1590:
1591: if (bd->part >= 0)
1592: {
1593: struct disklabel *lp;
1594:
1595: assert (bd->ds->labels);
1596: lp = bd->ds->labels[MINOR (bd->dev)];
1597: assert (lp);
1598: (status[DEV_GET_SIZE_DEVICE_SIZE]
1599: = lp->d_partitions[bd->part].p_size << 9);
1600: }
1601: else
1602: (status[DEV_GET_SIZE_DEVICE_SIZE]
1603: = bd->ds->gd->part[MINOR (bd->dev)].nr_sects << 9);
1604: }
1605: else
1606: {
1607: assert (blk_size[MAJOR (bd->dev)]);
1608: (status[DEV_GET_SIZE_DEVICE_SIZE]
1609: = (blk_size[MAJOR (bd->dev)][MINOR (bd->dev)]
1610: << BLOCK_SIZE_BITS));
1611: }
1612: /* It would be nice to return the block size as reported by
1613: the driver, but a lot of user level code assumes the sector
1614: size to be 512. */
1615: status[DEV_GET_SIZE_RECORD_SIZE] = 512;
1616: /* Always return DEV_GET_SIZE_COUNT. This is what all native
1617: Mach drivers do, and makes it possible to detect the absence
1618: of the call by setting it to a different value on input. MiG
1619: makes sure that we will never return more integers than the
1620: user asked for. */
1621: *status_count = DEV_GET_SIZE_COUNT;
1622: break;
1623:
1.1.1.2 root 1624: case DEV_GET_RECORDS:
1625: if (disk_major (MAJOR (bd->dev)))
1626: {
1627: assert (bd->ds->gd);
1628:
1629: if (bd->part >= 0)
1630: {
1631: struct disklabel *lp;
1632:
1633: assert (bd->ds->labels);
1634: lp = bd->ds->labels[MINOR (bd->dev)];
1635: assert (lp);
1636: (status[DEV_GET_RECORDS_DEVICE_RECORDS]
1637: = lp->d_partitions[bd->part].p_size);
1638: }
1639: else
1640: (status[DEV_GET_RECORDS_DEVICE_RECORDS]
1641: = bd->ds->gd->part[MINOR (bd->dev)].nr_sects);
1642: }
1643: else
1644: {
1645: assert (blk_size[MAJOR (bd->dev)]);
1.1.1.3 ! root 1646: status[DEV_GET_RECORDS_DEVICE_RECORDS]
! 1647: = (blk_size[MAJOR (bd->dev)][MINOR (bd->dev)]
! 1648: << (BLOCK_SIZE_BITS - 9));
1.1.1.2 root 1649: }
1650: /* It would be nice to return the block size as reported by
1651: the driver, but a lot of user level code assumes the sector
1652: size to be 512. */
1.1.1.3 ! root 1653: status[DEV_GET_RECORDS_RECORD_SIZE] = 512;
1.1.1.2 root 1654: /* Always return DEV_GET_RECORDS_COUNT. This is what all native
1655: Mach drivers do, and makes it possible to detect the absence
1656: of the call by setting it to a different value on input. MiG
1657: makes sure that we will never return more integers than the
1658: user asked for. */
1659: *status_count = DEV_GET_RECORDS_COUNT;
1660: break;
1661:
1.1 root 1662: case V_GETPARMS:
1663: if (*status_count < (sizeof (struct disk_parms) / sizeof (int)))
1664: return D_INVALID_OPERATION;
1665: else
1666: {
1667: struct disk_parms *dp = status;
1668: struct hd_geometry hg;
1669: DECL_DATA;
1670:
1671: INIT_DATA();
1672:
1673: if ((*bd->ds->fops->ioctl) (&td.inode, &td.file,
1.1.1.3 ! root 1674: HDIO_GETGEO, (unsigned long)&hg))
1.1 root 1675: return D_INVALID_OPERATION;
1676:
1677: dp->dp_type = DPT_WINI; /* XXX: It may be a floppy... */
1678: dp->dp_heads = hg.heads;
1679: dp->dp_cyls = hg.cylinders;
1680: dp->dp_sectors = hg.sectors;
1681: dp->dp_dosheads = hg.heads;
1682: dp->dp_doscyls = hg.cylinders;
1683: dp->dp_dossectors = hg.sectors;
1684: dp->dp_secsiz = 512; /* XXX */
1685: dp->dp_ptag = 0;
1686: dp->dp_pflag = 0;
1.1.1.2 root 1687:
1.1 root 1688: /* XXX */
1689: dp->dp_pstartsec = -1;
1690: dp->dp_pnumsec = -1;
1691:
1692: *status_count = sizeof (struct disk_parms) / sizeof (int);
1693: }
1.1.1.2 root 1694:
1.1 root 1695: break;
1.1.1.2 root 1696:
1.1 root 1697: default:
1698: return D_INVALID_OPERATION;
1699: }
1700:
1701: return D_SUCCESS;
1702: }
1703:
1.1.1.3 ! root 1704: static io_return_t
! 1705: device_set_status (void *d, dev_flavor_t flavor, dev_status_t status,
! 1706: mach_msg_type_number_t *status_count)
! 1707: {
! 1708: struct block_data *bd = d;
! 1709:
! 1710: switch (flavor)
! 1711: {
! 1712: case BLKRRPART:
! 1713: {
! 1714: DECL_DATA;
! 1715: INIT_DATA();
! 1716: return (*bd->ds->fops->ioctl) (&td.inode, &td.file, flavor, 0);
! 1717: }
! 1718: }
! 1719:
! 1720: return D_INVALID_OPERATION;
! 1721: }
! 1722:
! 1723:
! 1724: static void
! 1725: device_no_senders (mach_no_senders_notification_t *ns)
! 1726: {
! 1727: device_t dev;
! 1728:
! 1729: dev = dev_port_lookup((ipc_port_t) ns->not_header.msgh_remote_port);
! 1730: assert(dev);
! 1731: device_close_forced (dev->emul_data, 1);
! 1732: }
! 1733:
1.1 root 1734: struct device_emulation_ops linux_block_emulation_ops =
1735: {
1736: NULL,
1737: NULL,
1738: dev_to_port,
1739: device_open,
1740: device_close,
1741: device_write,
1742: NULL,
1743: device_read,
1744: NULL,
1.1.1.3 ! root 1745: device_set_status,
1.1 root 1746: device_get_status,
1747: NULL,
1748: NULL,
1.1.1.3 ! root 1749: device_no_senders,
1.1 root 1750: NULL,
1751: NULL
1752: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.