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