add patch 0011-ps3stor-send-cmd-timeout.patch
[ps3linux_kernel_patches_314.git] / 0140-ps3strgmngr.patch
blob057ccd2066b244505bbbb9e1050594625c635c00
1 --- a/drivers/char/Makefile 2012-02-08 19:49:18.736981163 +0100
2 +++ b/drivers/char/Makefile 2012-02-10 18:43:23.927197754 +0100
3 @@ -67,3 +67,4 @@
4 obj-$(CONFIG_TILE_SROM) += tile-srom.o
6 obj-$(CONFIG_PS3_PHYSMEM) += ps3physmem.o
7 +obj-$(CONFIG_PS3_STRGMNGR) += ps3strgmngr.o
8 --- a/arch/powerpc/platforms/ps3/Kconfig 2012-02-08 19:49:18.736981163 +0100
9 +++ b/arch/powerpc/platforms/ps3/Kconfig 2012-02-10 18:46:54.907113221 +0100
10 @@ -185,6 +185,13 @@
11 help
12 This driver allows you direct access to the PS3 physical memory.
14 +config PS3_STRGMNGR
15 + tristate "PS3 Storage Manager Driver"
16 + depends on PPC_PS3
17 + help
18 + This driver allows you to create/delete/modify regions
19 + on PS3 storage devices.
21 config PS3GELIC_UDBG
22 bool "PS3 udbg output via UDP broadcasts on Ethernet"
23 depends on PPC_PS3
24 --- a/arch/powerpc/include/uapi/asm/Kbuild 2012-12-11 10:00:27.000000000 -0900
25 +++ b/arch/powerpc/include/uapi/asm/Kbuild 2012-12-11 10:00:46.000000000 -0900
26 @@ -42,3 +42,4 @@
27 header-y += types.h
28 header-y += ucontext.h
29 header-y += unistd.h
30 +header-y += ps3strgmngr.h
31 --- /dev/null 2012-02-10 17:03:27.997801619 +0100
32 +++ b/arch/powerpc/include/asm/ps3strgmngr.h 2012-02-10 18:49:42.806463666 +0100
33 @@ -0,0 +1,101 @@
34 +/*
35 + * PS3 Storage Manager Driver
36 + *
37 + * Copyright (C) 2011 graf_chokolo <grafchokolo@gmail.com>
38 + * Copyright (C) 2011, 2012 glevand <geoffrey.levand@mail.ru>
39 + * All rights reserved.
40 + *
41 + * This program is free software; you can redistribute it and/or modify it
42 + * under the terms of the GNU General Public License as published
43 + * by the Free Software Foundation; version 2 of the License.
44 + *
45 + * This program is distributed in the hope that it will be useful, but
46 + * WITHOUT ANY WARRANTY; without even the implied warranty of
47 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
48 + * General Public License for more details.
49 + *
50 + * You should have received a copy of the GNU General Public License along
51 + * with this program; if not, write to the Free Software Foundation, Inc.,
52 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
53 + */
55 +#ifndef _PS3STRGMNGR_H
56 +#define _PS3STRGMNGR_H
58 +#include <linux/types.h>
59 +#include <linux/ioctl.h>
61 +#define PS3STRGMNGR_MAX_ACL_ENTRIES 8
62 +#define PS3STRGMNGR_MAX_REGIONS 8
63 +#define PS3STRGMNGR_MAX_DEVICES 8
65 +#define PS3STRGMNGR_CTL_GET_DEVICES _IOR('s', 0, int)
66 +#define PS3STRGMNGR_CTL_CREATE_REGION _IOWR('s', 1, int)
67 +#define PS3STRGMNGR_CTL_DELETE_REGION _IOW('s', 2, int)
68 +#define PS3STRGMNGR_CTL_SET_REGION_ACL_ENTRY _IOW('s', 3, int)
70 +enum ps3strgmngr_devtype {
71 + PS3STRGMNGR_DEVTYPE_DISK = 0,
72 + PS3STRGMNGR_DEVTYPE_CDROM,
73 + PS3STRGMNGR_DEVTYPE_FLASH,
74 + PS3STRGMNGR_DEVTYPE_NOR_FLASH,
75 +};
77 +enum ps3strgmngr_region_access_rights {
78 + PS3STRGMNGR_REGION_READ = (1ull << 0),
79 + PS3STRGMNGR_REGION_WRITE = (1ull << 1),
80 +};
82 +struct ps3strgmngr_acl_entry {
83 + __u64 laid;
84 + __u64 access_rights; /* enum ps3strgmngr_region_access_rights */
85 +};
87 +struct ps3strgmngr_region {
88 + __u64 id;
89 + __u64 start_block;
90 + __u64 nr_blocks;
91 + __u64 nr_acl_entries;
92 + struct ps3strgmngr_acl_entry acl_entry[PS3STRGMNGR_MAX_ACL_ENTRIES];
93 +};
95 +struct ps3strgmngr_device {
96 + __u64 type; /* enum ps3strgmngr_devtype */
97 + __u64 id;
98 + __u64 block_size;
99 + __u64 nr_blocks;
100 + __u64 nr_regions;
101 + struct ps3strgmngr_region region[PS3STRGMNGR_MAX_REGIONS];
104 +struct ps3strgmngr_ctl_get_devices {
105 + /* out */
106 + __u64 nr_devices;
107 + struct ps3strgmngr_device device[PS3STRGMNGR_MAX_DEVICES];
110 +struct ps3strgmngr_ctl_create_region {
111 + /* in */
112 + __u64 device_id;
113 + __u64 start_block;
114 + __u64 nr_blocks;
115 + __u64 laid;
116 + /* out */
117 + __u64 region_id;
120 +struct ps3strgmngr_ctl_delete_region {
121 + /* in */
122 + __u64 device_id;
123 + __u64 region_id;
126 +struct ps3strgmngr_ctl_set_region_acl_entry {
127 + /* in */
128 + __u64 device_id;
129 + __u64 region_id;
130 + __u64 laid;
131 + __u64 access_rights;
134 +#endif /* _PS3STRGMNGR_H */
135 --- /dev/null 2012-02-10 17:03:27.997801619 +0100
136 +++ b/drivers/char/ps3strgmngr.c 2012-02-10 23:29:41.429492084 +0100
137 @@ -0,0 +1,428 @@
139 + * PS3 Storage Manager Driver
141 + * Copyright (C) 2011 graf_chokolo <grafchokolo@gmail.com>
142 + * Copyright (C) 2011, 2012 glevand <geoffrey.levand@mail.ru>
143 + * All rights reserved.
145 + * This program is free software; you can redistribute it and/or modify it
146 + * under the terms of the GNU General Public License as published
147 + * by the Free Software Foundation; version 2 of the License.
149 + * This program is distributed in the hope that it will be useful, but
150 + * WITHOUT ANY WARRANTY; without even the implied warranty of
151 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
152 + * General Public License for more details.
154 + * You should have received a copy of the GNU General Public License along
155 + * with this program; if not, write to the Free Software Foundation, Inc.,
156 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
157 + */
159 +#include <linux/module.h>
160 +#include <linux/kernel.h>
161 +#include <linux/init.h>
162 +#include <linux/slab.h>
163 +#include <linux/fs.h>
164 +#include <linux/uaccess.h>
165 +#include <linux/compat.h>
166 +#include <linux/miscdevice.h>
168 +#include <asm/ps3.h>
169 +#include <asm/lv1call.h>
170 +#include <asm/ps3strgmngr.h>
172 +#define STORAGE_BUS_TYPE 5
174 +#define STORAGE_DEV_TYPE_DISK 0
175 +#define STORAGE_DEV_TYPE_CDROM 5
176 +#define STORAGE_DEV_TYPE_FLASH 14
177 +#define STORAGE_DEV_TYPE_NOR_FLASH 254
179 +static int ps3strgmngr_read_acl(u64 dev_id, struct ps3strgmngr_region *rgn)
181 + struct ps3strgmngr_acl_entry *acl_entry;
182 + unsigned int acl_entry_index;
183 + int res;
185 + rgn->nr_acl_entries = 0;
186 + acl_entry = rgn->acl_entry;
188 + for (acl_entry_index = 0; acl_entry_index < PS3STRGMNGR_MAX_ACL_ENTRIES; acl_entry_index++) {
189 + res = lv1_storage_get_region_acl(dev_id, rgn->id, acl_entry_index,
190 + &acl_entry->laid, &acl_entry->access_rights);
191 + if (res)
192 + continue;
194 + rgn->nr_acl_entries++;
195 + acl_entry++;
198 + return (0);
201 +static int ps3strgmngr_read_region(u64 bus_index, u64 dev_index, u64 dev_id, u64 dev_type,
202 + u64 rgn_index, struct ps3strgmngr_region *rgn)
204 + u64 flash_ext_flag, junk;
205 + int res;
207 + res = lv1_read_repository_node(1, 0x0000000062757300ul | bus_index /* bus */,
208 + 0x6465760000000000ul | dev_index /* dev */,
209 + 0x726567696f6e0000ul | rgn_index /* region */,
210 + 0x6964000000000000ul /* id */,
211 + &rgn->id, &junk);
212 + if (res)
213 + return (-ENXIO);
215 + if (dev_type == STORAGE_DEV_TYPE_DISK) {
216 + res = lv1_read_repository_node(1, 0x0000000073797300ul /* sys */,
217 + 0x666c617368000000ul /* flash */,
218 + 0x6578740000000000ul /* ext */,
219 + 0, &flash_ext_flag, &junk);
220 + if (res)
221 + return (-ENXIO);
223 + if (!(flash_ext_flag & 0x1) && (rgn->id > 0))
224 + rgn->id += 1;
227 + res = lv1_read_repository_node(1, 0x0000000062757300ul | bus_index /* bus */,
228 + 0x6465760000000000ul | dev_index /* dev */,
229 + 0x726567696f6e0000ul | rgn_index /* region */,
230 + 0x7374617274000000ul /* start */,
231 + &rgn->start_block, &junk);
232 + if (res)
233 + return (-ENXIO);
235 + res = lv1_read_repository_node(1, 0x0000000062757300ul | bus_index /* bus */,
236 + 0x6465760000000000ul | dev_index /* dev */,
237 + 0x726567696f6e0000ul | rgn_index /* region */,
238 + 0x73697a6500000000ul /* size */,
239 + &rgn->nr_blocks, &junk);
240 + if (res)
241 + return (-ENXIO);
243 + res = ps3strgmngr_read_acl(dev_id, rgn);
244 + if (res)
245 + return (res);
247 + return (0);
250 +static int ps3strgmngr_read_device(u64 bus_index, u64 dev_index,
251 + struct ps3strgmngr_device *dev)
253 + struct ps3strgmngr_region *rgn;
254 + u64 type, nr_regions, junk;
255 + unsigned int rgn_index;
256 + int res;
258 + res = lv1_read_repository_node(1, 0x0000000062757300ul | bus_index /* bus */,
259 + 0x6465760000000000ul | dev_index /* dev */,
260 + 0x7479706500000000ul /* type */,
261 + 0, &type, &junk);
262 + if (res)
263 + return (-ENXIO);
265 + switch (type) {
266 + case STORAGE_DEV_TYPE_DISK:
267 + dev->type = PS3STRGMNGR_DEVTYPE_DISK;
268 + break;
269 + case STORAGE_DEV_TYPE_CDROM:
270 + dev->type = PS3STRGMNGR_DEVTYPE_CDROM;
271 + break;
272 + case STORAGE_DEV_TYPE_FLASH:
273 + dev->type = PS3STRGMNGR_DEVTYPE_FLASH;
274 + break;
275 + case STORAGE_DEV_TYPE_NOR_FLASH:
276 + dev->type = PS3STRGMNGR_DEVTYPE_NOR_FLASH;
277 + break;
278 + default:
279 + return (-ENOTSUPP);
280 + break;
283 + res = lv1_read_repository_node(1, 0x0000000062757300ul | bus_index /* bus */,
284 + 0x6465760000000000ul | dev_index /* dev */,
285 + 0x6964000000000000ul /* id */,
286 + 0, &dev->id, &junk);
287 + if (res)
288 + return (-ENXIO);
290 + res = lv1_read_repository_node(1, 0x0000000062757300ul | bus_index /* bus */,
291 + 0x6465760000000000ul | dev_index /* dev */,
292 + 0x626c6b5f73697a65ul /* blk_size */,
293 + 0, &dev->block_size, &junk);
294 + if (res)
295 + return (-ENXIO);
297 + res = lv1_read_repository_node(1, 0x0000000062757300ul | bus_index /* bus */,
298 + 0x6465760000000000ul | dev_index /* dev */,
299 + 0x6e5f626c6f636b73ul /* n_blocks */,
300 + 0, &dev->nr_blocks, &junk);
301 + if (res)
302 + return (-ENXIO);
304 + res = lv1_read_repository_node(1, 0x0000000062757300ul | bus_index /* bus */,
305 + 0x6465760000000000ul | dev_index /* dev */,
306 + 0x6e5f726567730000ul /* n_regs */,
307 + 0, &nr_regions, &junk);
308 + if (res)
309 + return (-ENXIO);
311 + rgn = dev->region;
313 + for (rgn_index = 0; rgn_index < nr_regions; rgn_index++) {
314 + res = ps3strgmngr_read_region(bus_index, dev_index, dev->id, type,
315 + rgn_index, rgn);
316 + if (res)
317 + continue;
319 + dev->nr_regions++;
320 + rgn++;
323 + return (0);
326 +static int ps3strgmngr_ctl_get_devices(struct ps3strgmngr_ctl_get_devices *get_devices)
328 + struct ps3strgmngr_device *dev;
329 + unsigned int bus_index, dev_index;
330 + u64 bus_type, bus_id, nr_devices, junk;
331 + int res;
333 + get_devices->nr_devices = 0;
334 + dev = get_devices->device;
336 + for (bus_index = 0; bus_index < 10; bus_index++) {
337 + res = lv1_read_repository_node(1, 0x0000000062757300ul | bus_index /* bus */,
338 + 0x7479706500000000ul /* type */,
339 + 0, 0, &bus_type, &junk);
340 + if (res)
341 + continue;
343 + if (bus_type == STORAGE_BUS_TYPE)
344 + break;
347 + if (bus_index >= 10)
348 + return (-ENXIO);
350 + res = lv1_read_repository_node(1, 0x0000000062757300ul | bus_index /* bus */,
351 + 0x6964000000000000ul /* id */,
352 + 0, 0, &bus_id, &junk);
353 + if (res)
354 + return (-ENXIO);
356 + res = lv1_read_repository_node(1, 0x0000000062757300ul | bus_index /* bus */,
357 + 0x6e756d5f64657600ul /* num_dev */,
358 + 0, 0, &nr_devices, &junk);
359 + if (res)
360 + return (-ENXIO);
362 + for (dev_index = 0; dev_index < nr_devices; dev_index++) {
363 + res = ps3strgmngr_read_device(bus_index, dev_index, dev);
364 + if (res)
365 + continue;
367 + get_devices->nr_devices++;
368 + dev++;
371 + return (0);
374 +static int ps3strgmngr_ctl_create_region(struct ps3strgmngr_ctl_create_region *create_region)
376 + u64 tag;
377 + int res;
379 + res = lv1_storage_create_region(create_region->device_id, create_region->start_block,
380 + create_region->nr_blocks, 0, create_region->laid, &create_region->region_id, &tag);
381 + if (res)
382 + return (-ENXIO);
384 + return (0);
387 +static int ps3strgmngr_ctl_delete_region(struct ps3strgmngr_ctl_delete_region *delete_region)
389 + u64 tag;
390 + int res;
392 + res = lv1_storage_delete_region(delete_region->device_id, delete_region->region_id, &tag);
393 + if (res)
394 + return (-ENXIO);
396 + return (0);
399 +static int ps3strgmngr_ctl_set_region_acl_entry(struct ps3strgmngr_ctl_set_region_acl_entry *set_region_acl_entry)
401 + u64 tag;
402 + int res;
404 + res = lv1_storage_set_region_acl(set_region_acl_entry->device_id, set_region_acl_entry->region_id,
405 + set_region_acl_entry->laid, set_region_acl_entry->access_rights,
406 + &tag);
407 + if (res)
408 + return (-ENXIO);
410 + return (0);
413 +static long ps3strgmngr_ioctl(struct file *file, unsigned int cmd,
414 + unsigned long arg)
416 + void __user *argp = (void __user *) arg;
417 + struct ps3strgmngr_ctl_get_devices *get_devices;
418 + struct ps3strgmngr_ctl_create_region *create_region;
419 + struct ps3strgmngr_ctl_delete_region *delete_region;
420 + struct ps3strgmngr_ctl_set_region_acl_entry *set_region_acl_entry;
421 + int res;
423 + if (is_compat_task())
424 + argp = compat_ptr(arg);
425 + else
426 + argp = (void __user *) arg;
428 + switch (cmd) {
429 + case PS3STRGMNGR_CTL_GET_DEVICES:
430 + get_devices = kmalloc(sizeof(*get_devices), GFP_KERNEL);
431 + if (!get_devices)
432 + return (-ENOMEM);
434 + if (copy_from_user(get_devices, argp, sizeof(*get_devices))) {
435 + kfree(get_devices);
436 + return (-EFAULT);
439 + res = ps3strgmngr_ctl_get_devices(get_devices);
440 + if (res) {
441 + kfree(get_devices);
442 + return (res);
445 + if (copy_to_user(argp, get_devices, sizeof(*get_devices))) {
446 + kfree(get_devices);
447 + return (-EFAULT);
450 + kfree(get_devices);
451 + break;
452 + case PS3STRGMNGR_CTL_CREATE_REGION:
453 + create_region = kmalloc(sizeof(*create_region), GFP_KERNEL);
454 + if (!create_region)
455 + return (-ENOMEM);
457 + if (copy_from_user(create_region, argp, sizeof(*create_region))) {
458 + kfree(create_region);
459 + return (-EFAULT);
462 + res = ps3strgmngr_ctl_create_region(create_region);
463 + if (res) {
464 + kfree(create_region);
465 + return (res);
468 + if (copy_to_user(argp, create_region, sizeof(*create_region))) {
469 + kfree(create_region);
470 + return (-EFAULT);
473 + kfree(create_region);
474 + break;
475 + case PS3STRGMNGR_CTL_DELETE_REGION:
476 + delete_region = kmalloc(sizeof(*delete_region), GFP_KERNEL);
477 + if (!delete_region)
478 + return (-ENOMEM);
480 + if (copy_from_user(delete_region, argp, sizeof(*delete_region))) {
481 + kfree(delete_region);
482 + return (-EFAULT);
485 + res = ps3strgmngr_ctl_delete_region(delete_region);
486 + if (res) {
487 + kfree(delete_region);
488 + return (res);
491 + if (copy_to_user(argp, delete_region, sizeof(*delete_region))) {
492 + kfree(delete_region);
493 + return (-EFAULT);
496 + kfree(delete_region);
497 + break;
498 + case PS3STRGMNGR_CTL_SET_REGION_ACL_ENTRY:
499 + set_region_acl_entry = kmalloc(sizeof(*set_region_acl_entry), GFP_KERNEL);
500 + if (!set_region_acl_entry)
501 + return (-ENOMEM);
503 + if (copy_from_user(set_region_acl_entry, argp, sizeof(*set_region_acl_entry))) {
504 + kfree(set_region_acl_entry);
505 + return (-EFAULT);
508 + res = ps3strgmngr_ctl_set_region_acl_entry(set_region_acl_entry);
509 + if (res) {
510 + kfree(set_region_acl_entry);
511 + return (res);
514 + if (copy_to_user(argp, set_region_acl_entry, sizeof(*set_region_acl_entry))) {
515 + kfree(set_region_acl_entry);
516 + return (-EFAULT);
519 + kfree(set_region_acl_entry);
520 + break;
521 + default:
522 + return (-ENOIOCTLCMD);
523 + break;
526 + return (0);
529 +static const struct file_operations ps3strgmngr_fops = {
530 + .owner = THIS_MODULE,
531 + .unlocked_ioctl = ps3strgmngr_ioctl,
532 + .compat_ioctl = ps3strgmngr_ioctl,
535 +static struct miscdevice ps3strgmngr_misc = {
536 + .minor = MISC_DYNAMIC_MINOR,
537 + .name = "ps3strgmngr",
538 + .fops = &ps3strgmngr_fops,
541 +static int __init ps3strgmngr_init(void)
543 + int res;
545 + res = misc_register(&ps3strgmngr_misc);
546 + if (res) {
547 + pr_info("%s:%u: misc_register failed %d\n",
548 + __func__, __LINE__, res);
549 + return (res);
552 + return (0);
555 +static void __exit ps3strgmngr_exit(void)
557 + misc_deregister(&ps3strgmngr_misc);
560 +module_init(ps3strgmngr_init);
561 +module_exit(ps3strgmngr_exit);
563 +MODULE_AUTHOR("glevand");
564 +MODULE_DESCRIPTION("PS3 Storage Manager Driver");
565 +MODULE_LICENSE("GPL");