1 /* ofdisk.c - Open Firmware disk access. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2004,2006,2007,2008,2009,2011 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/misc.h>
21 #include <grub/disk.h>
23 #include <grub/arc/arc.h>
24 #include <grub/i18n.h>
26 static grub_arc_fileno_t last_handle
= 0;
27 static char *last_path
= NULL
;
28 static int handle_writable
= 0;
32 struct arcdisk_hash_ent
36 struct arcdisk_hash_ent
*next
;
39 #define ARCDISK_HASH_SZ 8
40 static struct arcdisk_hash_ent
*arcdisk_hash
[ARCDISK_HASH_SZ
];
43 arcdisk_hash_fn (const char *devpath
)
48 return (hash
& (ARCDISK_HASH_SZ
- 1));
51 static struct arcdisk_hash_ent
*
52 arcdisk_hash_find (const char *devpath
)
54 struct arcdisk_hash_ent
*p
= arcdisk_hash
[arcdisk_hash_fn (devpath
)];
58 if (!grub_strcmp (p
->devpath
, devpath
))
65 static struct arcdisk_hash_ent
*
66 arcdisk_hash_add (char *devpath
)
68 struct arcdisk_hash_ent
*p
;
69 struct arcdisk_hash_ent
**head
= &arcdisk_hash
[arcdisk_hash_fn(devpath
)];
71 p
= grub_malloc (sizeof (*p
));
83 /* Context for grub_arcdisk_iterate. */
84 struct grub_arcdisk_iterate_ctx
86 grub_disk_dev_iterate_hook_t hook
;
90 /* Helper for grub_arcdisk_iterate. */
92 grub_arcdisk_iterate_iter (const char *name
,
93 const struct grub_arc_component
*comp
, void *data
)
95 struct grub_arcdisk_iterate_ctx
*ctx
= data
;
97 if (!(comp
->type
== GRUB_ARC_COMPONENT_TYPE_DISK
98 || comp
->type
== GRUB_ARC_COMPONENT_TYPE_FLOPPY
99 || comp
->type
== GRUB_ARC_COMPONENT_TYPE_TAPE
))
101 return ctx
->hook (name
, ctx
->hook_data
);
105 grub_arcdisk_iterate (grub_disk_dev_iterate_hook_t hook
, void *hook_data
,
106 grub_disk_pull_t pull
)
108 struct grub_arcdisk_iterate_ctx ctx
= { hook
, hook_data
};
110 if (pull
!= GRUB_DISK_PULL_NONE
)
113 return grub_arc_iterate_devs (grub_arcdisk_iterate_iter
, &ctx
, 1);
116 #ifdef GRUB_CPU_MIPSEL
117 #define RAW_SUFFIX "partition(0)"
119 #define RAW_SUFFIX "partition(10)"
123 reopen (const char *name
, int writable
)
125 grub_arc_fileno_t handle
;
127 if (last_path
&& grub_strcmp (last_path
, name
) == 0
128 && (!writable
|| handle_writable
))
130 grub_dprintf ("arcdisk", "using already opened %s\n", name
);
131 return GRUB_ERR_NONE
;
135 GRUB_ARC_FIRMWARE_VECTOR
->close (last_handle
);
136 grub_free (last_path
);
141 if (GRUB_ARC_FIRMWARE_VECTOR
->open (name
,
142 writable
? GRUB_ARC_FILE_ACCESS_OPEN_RW
143 : GRUB_ARC_FILE_ACCESS_OPEN_RO
, &handle
))
145 grub_dprintf ("arcdisk", "couldn't open %s\n", name
);
146 return grub_error (GRUB_ERR_IO
, "couldn't open %s", name
);
148 handle_writable
= writable
;
149 last_path
= grub_strdup (name
);
152 last_handle
= handle
;
153 grub_dprintf ("arcdisk", "opened %s\n", name
);
154 return GRUB_ERR_NONE
;
158 grub_arcdisk_open (const char *name
, grub_disk_t disk
)
163 struct grub_arc_fileinfo info
;
164 struct arcdisk_hash_ent
*hash
;
166 if (grub_memcmp (name
, "arc/", 4) != 0)
167 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "not arc device");
168 fullname
= grub_arc_alt_name_to_norm (name
, RAW_SUFFIX
);
169 disk
->data
= fullname
;
170 grub_dprintf ("arcdisk", "opening %s\n", fullname
);
172 hash
= arcdisk_hash_find (fullname
);
174 hash
= arcdisk_hash_add (fullname
);
178 err
= reopen (fullname
, 0);
182 r
= GRUB_ARC_FIRMWARE_VECTOR
->getfileinformation (last_handle
, &info
);
185 grub_uint64_t res
= 0;
188 grub_dprintf ("arcdisk", "couldn't retrieve size: %ld\n", r
);
189 for (i
= 40; i
>= 9; i
--)
191 grub_uint64_t pos
= res
| (1ULL << i
);
193 long unsigned count
= 0;
194 grub_dprintf ("arcdisk",
195 "seek to 0x%" PRIxGRUB_UINT64_T
"\n", pos
);
196 if (GRUB_ARC_FIRMWARE_VECTOR
->seek (last_handle
, &pos
, 0))
198 if (GRUB_ARC_FIRMWARE_VECTOR
->read (last_handle
, buf
,
205 grub_dprintf ("arcdisk",
206 "determined disk size 0x%" PRIxGRUB_UINT64_T
"\n", res
);
207 disk
->total_sectors
= (res
+ 0x200) >> 9;
210 disk
->total_sectors
= (info
.end
>> 9);
212 disk
->id
= hash
->num
;
213 return GRUB_ERR_NONE
;
217 grub_arcdisk_close (grub_disk_t disk
)
219 grub_free (disk
->data
);
223 grub_arcdisk_read (grub_disk_t disk
, grub_disk_addr_t sector
,
224 grub_size_t size
, char *buf
)
227 grub_uint64_t pos
= sector
<< 9;
229 grub_uint64_t totl
= size
<< 9;
232 err
= reopen (disk
->data
, 0);
235 r
= GRUB_ARC_FIRMWARE_VECTOR
->seek (last_handle
, &pos
, 0);
238 grub_dprintf ("arcdisk", "seek to 0x%" PRIxGRUB_UINT64_T
" failed: %ld\n",
240 return grub_error (GRUB_ERR_IO
, "couldn't seek");
245 if (GRUB_ARC_FIRMWARE_VECTOR
->read (last_handle
, buf
,
247 return grub_error (GRUB_ERR_READ_ERROR
,
248 N_("failure reading sector 0x%llx "
250 (unsigned long long) sector
,
256 return GRUB_ERR_NONE
;
260 grub_arcdisk_write (grub_disk_t disk
, grub_disk_addr_t sector
,
261 grub_size_t size
, const char *buf
)
264 grub_uint64_t pos
= sector
<< 9;
266 grub_uint64_t totl
= size
<< 9;
269 err
= reopen (disk
->data
, 1);
272 r
= GRUB_ARC_FIRMWARE_VECTOR
->seek (last_handle
, &pos
, 0);
275 grub_dprintf ("arcdisk", "seek to 0x%" PRIxGRUB_UINT64_T
" failed: %ld\n",
277 return grub_error (GRUB_ERR_IO
, "couldn't seek");
282 if (GRUB_ARC_FIRMWARE_VECTOR
->write (last_handle
, buf
,
284 return grub_error (GRUB_ERR_WRITE_ERROR
, N_("failure writing sector 0x%llx "
286 (unsigned long long) sector
,
292 return GRUB_ERR_NONE
;
295 static struct grub_disk_dev grub_arcdisk_dev
=
298 .id
= GRUB_DISK_DEVICE_ARCDISK_ID
,
299 .iterate
= grub_arcdisk_iterate
,
300 .open
= grub_arcdisk_open
,
301 .close
= grub_arcdisk_close
,
302 .read
= grub_arcdisk_read
,
303 .write
= grub_arcdisk_write
,
308 grub_arcdisk_init (void)
310 grub_disk_dev_register (&grub_arcdisk_dev
);
314 grub_arcdisk_fini (void)
318 GRUB_ARC_FIRMWARE_VECTOR
->close (last_handle
);
319 grub_free (last_path
);
324 grub_disk_dev_unregister (&grub_arcdisk_dev
);