Bug Summary

File:obj-scan-build/../linux/dev/glue/block.c
Location:line 1322, column 7
Description:Function call argument is an uninitialized value

Annotated Source Code

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