summaryrefslogtreecommitdiff
path: root/device/blkio.c
diff options
context:
space:
mode:
Diffstat (limited to 'device/blkio.c')
-rw-r--r--device/blkio.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/device/blkio.c b/device/blkio.c
new file mode 100644
index 0000000..26d4a75
--- /dev/null
+++ b/device/blkio.c
@@ -0,0 +1,238 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/89
+ *
+ * Block IO driven from generic kernel IO interface.
+ */
+#include <mach/kern_return.h>
+
+#include <device/param.h>
+#include <device/device_types.h>
+#include <device/io_req.h>
+#include <device/ds_routines.h>
+
+
+
+io_return_t block_io(strat, max_count, ior)
+ void (*strat)();
+ void (*max_count)();
+ register io_req_t ior;
+{
+ register kern_return_t rc;
+ boolean_t wait = FALSE;
+
+ /*
+ * Make sure the size is not too large by letting max_count
+ * change io_count. If we are doing a write, then io_alloc_size
+ * preserves the original io_count.
+ */
+ (*max_count)(ior);
+
+ /*
+ * If reading, allocate memory. If writing, wire
+ * down the incoming memory.
+ */
+ if (ior->io_op & IO_READ)
+ rc = device_read_alloc(ior, (vm_size_t)ior->io_count);
+ else
+ rc = device_write_get(ior, &wait);
+
+ if (rc != KERN_SUCCESS)
+ return (rc);
+
+ /*
+ * Queue the operation for the device.
+ */
+ (*strat)(ior);
+
+ /*
+ * The io is now queued. Wait for it if needed.
+ */
+ if (wait) {
+ iowait(ior);
+ return(D_SUCCESS);
+ }
+
+ return (D_IO_QUEUED);
+}
+
+/*
+ * 'standard' max_count routine. VM continuations mean that this
+ * code can cope with arbitrarily-sized write operations (they won't be
+ * atomic, but any caller that cares will do the op synchronously).
+ */
+#define MAX_PHYS (256 * 1024)
+
+void minphys(ior)
+ register io_req_t ior;
+{
+ if ((ior->io_op & (IO_WRITE | IO_READ | IO_OPEN)) == IO_WRITE)
+ return;
+
+ if (ior->io_count > MAX_PHYS)
+ ior->io_count = MAX_PHYS;
+}
+
+/*
+ * Dummy routine placed in device switch entries to indicate that
+ * block device may be mapped.
+ */
+vm_offset_t block_io_mmap()
+{
+ return (0);
+}
+
+/*
+ * Disk sort routine.
+ *
+ * We order the disk request chain so that the disk head will sweep
+ * back and forth across the disk. The chain is divided into two
+ * pieces, with requests ordered in opposite directions. Assume that
+ * the first part of the chain holds increasing cylinder numbers.
+ * If a new request has a higher cylinder number than the head of
+ * the chain, the disk head has not yet reached it; the new request
+ * can go in the first part of the chain. If the new request has
+ * a lower cylinder number, the disk head has already passed it and
+ * must catch it on the way back; so the new request goes in the
+ * second (descending) part of the chain.
+ * When all of the requests in the ascending portion are filled,
+ * the descending chain becomes the first chain, and requests above
+ * the first now go in the second part of the chain (ascending).
+ */
+
+#define io_cylinder io_residual
+ /* Disk drivers put cylinder here */
+#define h_head io_next
+#define h_tail io_prev
+ /* IORs are chained here */
+
+void disksort(head, ior)
+ io_req_t head; /* (sort of) */
+ io_req_t ior;
+{
+ register int cylinder = ior->io_cylinder;
+ register io_req_t next, prev;
+
+ next = head->h_head;
+ if (next == 0) {
+ head->h_head = ior;
+ head->h_tail = ior;
+ ior->io_next = 0;
+ return;
+ }
+
+ do {
+ prev = next;
+ next = prev->io_next;
+ } while (next != 0 && prev->io_cylinder == next->io_cylinder);
+
+ if (next == 0) {
+ prev->io_next = ior;
+ head->h_tail = ior;
+ ior->io_next = 0;
+ return;
+ }
+
+ if (prev->io_cylinder < next->io_cylinder) {
+ /*
+ * Ascending list first.
+ */
+ if (prev->io_cylinder <= cylinder) {
+ /*
+ * Insert in ascending list.
+ */
+ while (next != 0 &&
+ next->io_cylinder <= cylinder &&
+ prev->io_cylinder <= next->io_cylinder)
+ {
+ prev = next;
+ next = prev->io_next;
+ }
+ }
+ else {
+ /*
+ * Insert in descending list
+ */
+ do {
+ prev = next;
+ next = prev->io_next;
+ } while (next != 0 &&
+ prev->io_cylinder <= next->io_cylinder);
+
+ while (next != 0 &&
+ next->io_cylinder >= cylinder)
+ {
+ prev = next;
+ next = prev->io_next;
+ }
+ }
+ }
+ else {
+ /*
+ * Descending first.
+ */
+ if (prev->io_cylinder >= cylinder) {
+ /*
+ * Insert in descending list.
+ */
+ while (next != 0 &&
+ next->io_cylinder >= cylinder &&
+ prev->io_cylinder >= next->io_cylinder)
+ {
+ prev = next;
+ next = prev->io_next;
+ }
+ }
+ else {
+ /*
+ * Insert in ascending list
+ */
+ do {
+ prev = next;
+ next = prev->io_next;
+ } while (next != 0 &&
+ prev->io_cylinder >= next->io_cylinder);
+ while (next != 0 &&
+ next->io_cylinder <= cylinder)
+ {
+ prev = next;
+ next = prev->io_next;
+ }
+ }
+ }
+ /*
+ * Insert between prev and next.
+ */
+ prev->io_next = ior;
+ ior->io_next = next;
+ if (next == 0) {
+ /* At tail of list. */
+ head->h_tail = ior;
+ }
+}
+