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