|
|
1.1 root 1: /* device server routines for oskit block devices
2: *
3: * Some code here stolen from linux/dev/glue/block.c by Shantanu Goel
4: *
5: * Copyright (C) 1996, 1999 The University of Utah and the Computer Systems
6: * Laboratory at the University of Utah (CSL)
7: *
8: * This program is free software; you can redistribute it and/or modify
9: * it under the terms of the GNU General Public License as published by
10: * the Free Software Foundation; either version 2, or (at your option)
11: * any later version.
12: *
13: * This program is distributed in the hope that it will be useful,
14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: * GNU General Public License for more details.
17: *
18: * You should have received a copy of the GNU General Public License
19: * along with this program; if not, write to the Free Software
20: * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21: */
22:
23: #include "ds_oskit.h"
24:
25: #include <vm/vm_map.h>
26: #include <vm/vm_kern.h>
27: #include <vm/vm_page.h>
28:
29: #include <string.h>
30:
31: #include <oskit/io/blkio.h>
32:
33:
34: #define MAX_COPY (VM_MAP_COPY_PAGE_LIST_MAX << PAGE_SHIFT)
35:
36: #if 0
37: /* XXX no point in getting fancy since the oskit (linux/dev) code
38: will allocate its own wired memory and copy the data we pass into it
39: regardless.
40: */
41: io_return_t
42: ds_blkio_write (device_t dev, ipc_port_t reply_port,
43: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
44: recnum_t recnum, io_buf_ptr_t data, unsigned int count,
45: int *bytes_written)
46: {
47: io_return_t err;
48: oskit_error_t rc;
49: vm_map_copy_t copy = (vm_map_copy_t) data;
50: oskit_size_t resid, amt, i;
51: vm_offset_t addr, uaddr;
52: vm_size_t len, size;
53:
54: if (count % dev->com.blk.size)
55: INVALSZ;
56:
57: resid = count;
58: uaddr = copy->offset;
59:
60: /* Allocate a kernel buffer. */
61: size = round_page (uaddr + count) - trunc_page (uaddr);
62: if (size > MAX_COPY)
63: size = MAX_COPY;
64: addr = vm_map_min (device_io_map);
65: err = vm_map_enter (device_io_map, &addr, size, 0, TRUE,
66: 0, 0, FALSE, VM_PROT_READ|VM_PROT_WRITE,
67: VM_PROT_READ|VM_PROT_WRITE, VM_INHERIT_NONE);
68: if (err)
69: {
70: vm_map_copy_discard (copy);
71: return err;
72: }
73:
74: /* Determine size of I/O this time around. */
75: len = size - (uaddr & PAGE_MASK);
76: if (len > resid)
77: len = resid;
78:
79: offset = (oskit_off_t)recnum * dev->com.blk.size;
80:
81: do
82: {
83: /* Map user pages. */
84: for (i = 0; i < copy->cpy_npages; i++)
85: pmap_enter (vm_map_pmap (device_io_map),
86: addr + (i << PAGE_SHIFT),
87: copy->cpy_page_list[i]->phys_addr,
88: VM_PROT_READ /* |VM_PROT_WRITE ? */, TRUE);
89:
90: /* Do the write. */
91: rc = oskit_blkio_write (dev->com.blk.io,
92: (const char *) addr + (uaddr & PAGE_MASK),
93: offset, len, &amt);
94:
95: /* Unmap pages and deallocate copy. */
96: pmap_remove (vm_map_pmap (device_io_map),
97: addr, addr + (copy->cpy_npages << PAGE_SHIFT));
98: vm_map_copy_discard (copy);
99:
100: /* Check result of write. */
101: if (rc)
102: {
103: err = oskit_to_mach_error (rc);
104: break;
105: }
106: else
107: {
108: resid -= amt;
109: if (resid == 0)
110: break;
111: uaddr += amt;
112: offset += amt;
113: }
114:
115: /* Determine size of I/O this time around and copy in pages. */
116: len = round_page (uaddr + resid) - trunc_page (uaddr);
117: if (len > MAX_COPY)
118: len = MAX_COPY;
119: len -= uaddr & PAGE_MASK;
120: if (len > resid)
121: len = resid;
122: err = vm_map_copyin_page_list (current_map (), uaddr, len,
123: FALSE, FALSE, ©, FALSE);
124: } while (!err);
125:
126: /* Delete kernel buffer. */
127: vm_map_remove (device_io_map, addr, addr + size);
128:
129: return err;
130: }
131: #endif
132:
133: io_return_t
134: ds_blkio_write_inband (device_t dev, ipc_port_t reply_port,
135: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
136: recnum_t recnum, io_buf_ptr_t data, unsigned int count,
137: int *bytes_written)
138: {
139: oskit_error_t rc;
140:
141: /* Note that IO_INBAND_MAX is 128, so it is impossible to pass this
142: test for usual block sizes (>= 512) with any device_write_inband RPC.
143: But this function gets called by the generic ds_routines.c code for
144: out-of-band device_write too. */
145:
146: if (count % dev->com.blk.size)
147: INVALSZ;
148:
149: rc = oskit_blkio_write (dev->com.blk.io, data,
150: (oskit_off_t)recnum * dev->com.blk.size,
151: count, (oskit_size_t *) bytes_written);
152:
153: return oskit_to_mach_error (rc);
154: }
155:
156:
157: io_return_t
158: ds_blkio_read (device_t dev, ipc_port_t reply_port,
159: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
160: recnum_t recnum, int count, io_buf_ptr_t *data,
161: unsigned *bytes_read)
162: {
163: io_return_t err;
164: oskit_error_t rc;
165: boolean_t dirty;
166: oskit_size_t resid, amt;
167: queue_head_t pages;
168: vm_map_copy_t copy;
169: vm_offset_t addr, offset, alloc_offset, o;
170: vm_object_t object;
171: vm_page_t m;
172: vm_size_t len, size;
173: oskit_off_t readloc;
174:
175: if (count % dev->com.blk.size)
176: INVALSZ;
177:
178: *data = 0;
179: *bytes_read = 0;
180:
181: /* Allocate an object to hold the data. */
182: size = round_page (count);
183: object = vm_object_allocate (size);
184: if (! object)
185: return D_NO_MEMORY;
186:
187: alloc_offset = offset = 0;
188: resid = count;
189:
190: /* Allocate a kernel buffer. */
191: addr = vm_map_min (device_io_map);
192: if (size > MAX_COPY)
193: size = MAX_COPY;
194: err = vm_map_enter (device_io_map, &addr, size, 0, TRUE, 0,
195: 0, FALSE, VM_PROT_READ|VM_PROT_WRITE,
196: VM_PROT_READ|VM_PROT_WRITE, VM_INHERIT_NONE);
197: if (err)
198: goto out;
199:
200: queue_init (&pages);
201:
202: readloc = (oskit_off_t)recnum * dev->com.blk.size;
203:
204: while (resid)
205: {
206: /* Determine size of I/O this time around. */
207: len = round_page (offset + resid) - trunc_page (offset);
208: if (len > MAX_COPY)
209: len = MAX_COPY;
210:
211: /* Map any pages left from previous operation. */
212: o = trunc_page (offset);
213: queue_iterate (&pages, m, vm_page_t, pageq)
214: {
215: pmap_enter (vm_map_pmap (device_io_map),
216: addr + o - trunc_page (offset),
217: m->phys_addr, VM_PROT_READ|VM_PROT_WRITE, TRUE);
218: o += PAGE_SIZE;
219: }
220: assert (o == alloc_offset);
221:
222: /* Allocate and map pages. */
223: while (alloc_offset < trunc_page (offset) + len)
224: {
225: while ((m = vm_page_grab (FALSE)) == 0)
226: VM_PAGE_WAIT (0);
227: assert (! m->active && ! m->inactive);
228: m->busy = TRUE;
229: queue_enter (&pages, m, vm_page_t, pageq);
230: pmap_enter (vm_map_pmap (device_io_map),
231: addr + alloc_offset - trunc_page (offset),
232: m->phys_addr, VM_PROT_READ|VM_PROT_WRITE, TRUE);
233: alloc_offset += PAGE_SIZE;
234: }
235:
236: /* Do the read. */
237: amt = len - (offset & PAGE_MASK);
238: if (amt > resid)
239: amt = resid;
240: rc = oskit_blkio_read (dev->com.blk.io,
241: (char *) addr + (offset & PAGE_MASK),
242: readloc, amt, &amt);
243:
244: /* Compute number of pages to insert in object. */
245: o = trunc_page (offset);
246: if (rc == 0)
247: {
248: dirty = TRUE;
249: resid -= amt;
250: if (resid == 0)
251: {
252: /* Zero any unused space. */
253: if (offset + amt < o + len)
254: memset ((void *) (addr + offset - o + amt),
255: 0, o + len - offset - amt);
256: offset = o + len;
257: }
258: else
259: offset += amt;
260: }
261: else
262: {
263: dirty = FALSE;
264: offset = o + len;
265: }
266:
267: /* Unmap pages and add them to the object. */
268: pmap_remove (vm_map_pmap (device_io_map), addr, addr + len);
269: vm_object_lock (object);
270: while (o < trunc_page (offset))
271: {
272: m = (vm_page_t) queue_first (&pages);
273: assert (! queue_end (&pages, (queue_entry_t) m));
274: queue_remove (&pages, m, vm_page_t, pageq);
275: assert (m->busy);
276: vm_page_lock_queues ();
277: if (dirty)
278: {
279: PAGE_WAKEUP_DONE (m);
280: m->dirty = TRUE;
281: vm_page_insert (m, object, o);
282: }
283: else
284: vm_page_free (m);
285: vm_page_unlock_queues ();
286: o += PAGE_SIZE;
287: }
288: vm_object_unlock (object);
289:
290: if (rc)
291: {
292: err = oskit_to_mach_error (rc);
293: break;
294: }
295: else if (amt == 0) /* XXX ? */
296: break;
297: else
298: readloc += amt;
299: }
300:
301: /* Delete kernel buffer. */
302: vm_map_remove (device_io_map, addr, addr + size);
303:
304: assert (queue_empty (&pages));
305:
306: out:
307: if (! err)
308: err = vm_map_copyin_object (object, 0, round_page (count), ©);
309: if (! err)
310: {
311: *data = (io_buf_ptr_t) copy;
312: *bytes_read = count - resid;
313: }
314: else
315: vm_object_deallocate (object);
316:
317: return err;
318: }
319:
320: io_return_t
321: ds_blkio_get_status (device_t dev, dev_flavor_t flavor, dev_status_t status,
322: mach_msg_type_number_t *status_count)
323: {
324: oskit_error_t rc;
325: switch (flavor)
326: {
327: case DEV_GET_SIZE:
328: {
329: oskit_off_t size;
330:
331: /* DEV->com.blk.size was initialized on open. */
332: status[DEV_GET_SIZE_RECORD_SIZE] = dev->com.blk.size;
333:
334: rc = oskit_blkio_getsize (dev->com.blk.io, &size);
335: if (rc == OSKIT_E_NOTIMPL)
336: status[DEV_GET_SIZE_DEVICE_SIZE] = 0;
337: else if (rc)
338: return oskit_to_mach_error (rc);
339: else
340: status[DEV_GET_SIZE_DEVICE_SIZE] = size;
341:
342: *status_count = 2;
343: return D_SUCCESS;
344: }
345: case DEV_GET_RECORDS:
346: {
347: oskit_off_t size;
348:
349: /* DEV->com.blk.size was initialized on open. */
350: status[DEV_GET_RECORDS_RECORD_SIZE] = dev->com.blk.size;
351: assert (dev->com.blk.size > 0);
352:
353: rc = oskit_blkio_getsize (dev->com.blk.io, &size);
354: if (rc == OSKIT_E_NOTIMPL)
355: size = 0;
356: else if (rc)
357: return oskit_to_mach_error (rc);
358:
359: status[DEV_GET_RECORDS_DEVICE_RECORDS]
360: = (recnum_t) (size / (oskit_off_t) dev->com.blk.size);
361:
362: /* Always return DEV_GET_RECORDS_COUNT. This is what all native
363: Mach drivers do, and makes it possible to detect the absence
364: of the call by setting it to a different value on input. MiG
365: makes sure that we will never return more integers than the
366: user asked for. */
367: *status_count = DEV_GET_RECORDS_COUNT;
368: return D_SUCCESS;
369: }
370: }
371: INVALOP;
372: }
373:
374: void
375: ds_blkio_close (device_t dev)
376: {
377: /* Free any partition info we cached about this disk. */
378: if (dev->com.blk.parts)
379: kfree ((vm_offset_t) dev->com.blk.parts,
380: MAX_PARTS * sizeof dev->com.blk.parts[0]);
381: }
382:
383: const struct device_ops block_device_ops =
384: {
385: write_inband: ds_blkio_write_inband,
386: read: ds_blkio_read,
387: get_status: ds_blkio_get_status,
388: close: ds_blkio_close
389: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.