Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ps3stor_lib.c
Go to the documentation of this file.
1 /*
2  * PS3 Storage Library
3  *
4  * Copyright (C) 2007 Sony Computer Entertainment Inc.
5  * Copyright 2007 Sony Corp.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published
9  * by the Free Software Foundation; version 2 of the License.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include <linux/dma-mapping.h>
22 #include <linux/module.h>
23 
24 #include <asm/lv1call.h>
25 #include <asm/ps3stor.h>
26 
27 /*
28  * A workaround for flash memory I/O errors when the internal hard disk
29  * has not been formatted for OtherOS use. Delay disk close until flash
30  * memory is closed.
31  */
32 
33 static struct ps3_flash_workaround {
34  int flash_open;
35  int disk_open;
36  struct ps3_system_bus_device *disk_sbd;
37 } ps3_flash_workaround;
38 
39 static int ps3stor_open_hv_device(struct ps3_system_bus_device *sbd)
40 {
41  int error = ps3_open_hv_device(sbd);
42 
43  if (error)
44  return error;
45 
47  ps3_flash_workaround.flash_open = 1;
48 
49  if (sbd->match_id == PS3_MATCH_ID_STOR_DISK)
50  ps3_flash_workaround.disk_open = 1;
51 
52  return 0;
53 }
54 
55 static int ps3stor_close_hv_device(struct ps3_system_bus_device *sbd)
56 {
57  int error;
58 
60  && ps3_flash_workaround.disk_open
61  && ps3_flash_workaround.flash_open) {
62  ps3_flash_workaround.disk_sbd = sbd;
63  return 0;
64  }
65 
66  error = ps3_close_hv_device(sbd);
67 
68  if (error)
69  return error;
70 
71  if (sbd->match_id == PS3_MATCH_ID_STOR_DISK)
72  ps3_flash_workaround.disk_open = 0;
73 
74  if (sbd->match_id == PS3_MATCH_ID_STOR_FLASH) {
75  ps3_flash_workaround.flash_open = 0;
76 
77  if (ps3_flash_workaround.disk_sbd) {
78  ps3_close_hv_device(ps3_flash_workaround.disk_sbd);
79  ps3_flash_workaround.disk_open = 0;
80  ps3_flash_workaround.disk_sbd = NULL;
81  }
82  }
83 
84  return 0;
85 }
86 
87 static int ps3stor_probe_access(struct ps3_storage_device *dev)
88 {
89  int res, error;
90  unsigned int i;
91  unsigned long n;
92 
93  if (dev->sbd.match_id == PS3_MATCH_ID_STOR_ROM) {
94  /* special case: CD-ROM is assumed always accessible */
95  dev->accessible_regions = 1;
96  return 0;
97  }
98 
99  error = -EPERM;
100  for (i = 0; i < dev->num_regions; i++) {
101  dev_dbg(&dev->sbd.core,
102  "%s:%u: checking accessibility of region %u\n",
103  __func__, __LINE__, i);
104 
105  dev->region_idx = i;
106  res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, 0, 1,
107  0);
108  if (res) {
109  dev_dbg(&dev->sbd.core, "%s:%u: read failed, "
110  "region %u is not accessible\n", __func__,
111  __LINE__, i);
112  continue;
113  }
114 
115  dev_dbg(&dev->sbd.core, "%s:%u: region %u is accessible\n",
116  __func__, __LINE__, i);
117  set_bit(i, &dev->accessible_regions);
118 
119  /* We can access at least one region */
120  error = 0;
121  }
122  if (error)
123  return error;
124 
125  n = hweight_long(dev->accessible_regions);
126  if (n > 1)
127  dev_info(&dev->sbd.core,
128  "%s:%u: %lu accessible regions found. Only the first "
129  "one will be used\n",
130  __func__, __LINE__, n);
131  dev->region_idx = __ffs(dev->accessible_regions);
132  dev_info(&dev->sbd.core,
133  "First accessible region has index %u start %llu size %llu\n",
134  dev->region_idx, dev->regions[dev->region_idx].start,
135  dev->regions[dev->region_idx].size);
136 
137  return 0;
138 }
139 
140 
149 {
150  int error, res, alignment;
152 
153  error = ps3stor_open_hv_device(&dev->sbd);
154  if (error) {
155  dev_err(&dev->sbd.core,
156  "%s:%u: ps3_open_hv_device failed %d\n", __func__,
157  __LINE__, error);
158  goto fail;
159  }
160 
162  &dev->irq);
163  if (error) {
164  dev_err(&dev->sbd.core,
165  "%s:%u: ps3_sb_event_receive_port_setup failed %d\n",
166  __func__, __LINE__, error);
167  goto fail_close_device;
168  }
169 
170  error = request_irq(dev->irq, handler, 0,
171  dev->sbd.core.driver->name, dev);
172  if (error) {
173  dev_err(&dev->sbd.core, "%s:%u: request_irq failed %d\n",
174  __func__, __LINE__, error);
175  goto fail_sb_event_receive_port_destroy;
176  }
177 
178  alignment = min(__ffs(dev->bounce_size),
179  __ffs((unsigned long)dev->bounce_buf));
180  if (alignment < 12) {
181  dev_err(&dev->sbd.core,
182  "%s:%u: bounce buffer not aligned (%lx at 0x%p)\n",
183  __func__, __LINE__, dev->bounce_size, dev->bounce_buf);
184  error = -EINVAL;
185  goto fail_free_irq;
186  } else if (alignment < 16)
187  page_size = PS3_DMA_4K;
188  else
189  page_size = PS3_DMA_64K;
190  dev->sbd.d_region = &dev->dma_region;
191  ps3_dma_region_init(&dev->sbd, &dev->dma_region, page_size,
192  PS3_DMA_OTHER, dev->bounce_buf, dev->bounce_size);
193  res = ps3_dma_region_create(&dev->dma_region);
194  if (res) {
195  dev_err(&dev->sbd.core, "%s:%u: cannot create DMA region\n",
196  __func__, __LINE__);
197  error = -ENOMEM;
198  goto fail_free_irq;
199  }
200 
202  dev->bounce_dma = dma_map_single(&dev->sbd.core, dev->bounce_buf,
204  if (!dev->bounce_dma) {
205  dev_err(&dev->sbd.core, "%s:%u: map DMA region failed\n",
206  __func__, __LINE__);
207  error = -ENODEV;
208  goto fail_free_dma;
209  }
210 
211  error = ps3stor_probe_access(dev);
212  if (error) {
213  dev_err(&dev->sbd.core, "%s:%u: No accessible regions found\n",
214  __func__, __LINE__);
215  goto fail_unmap_dma;
216  }
217  return 0;
218 
219 fail_unmap_dma:
220  dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size,
222 fail_free_dma:
224 fail_free_irq:
225  free_irq(dev->irq, dev);
226 fail_sb_event_receive_port_destroy:
228 fail_close_device:
229  ps3stor_close_hv_device(&dev->sbd);
230 fail:
231  return error;
232 }
234 
235 
241 {
242  int error;
243 
244  dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size,
247 
248  free_irq(dev->irq, dev);
249 
250  error = ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq);
251  if (error)
252  dev_err(&dev->sbd.core,
253  "%s:%u: destroy event receive port failed %d\n",
254  __func__, __LINE__, error);
255 
256  error = ps3stor_close_hv_device(&dev->sbd);
257  if (error)
258  dev_err(&dev->sbd.core,
259  "%s:%u: ps3_close_hv_device failed %d\n", __func__,
260  __LINE__, error);
261 }
263 
264 
278 {
279  unsigned int region_id = dev->regions[dev->region_idx].id;
280  const char *op = write ? "write" : "read";
281  int res;
282 
283  dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu\n",
284  __func__, __LINE__, op, sectors, start_sector);
285 
286  init_completion(&dev->done);
287  res = write ? lv1_storage_write(dev->sbd.dev_id, region_id,
288  start_sector, sectors, 0, lpar,
289  &dev->tag)
290  : lv1_storage_read(dev->sbd.dev_id, region_id,
291  start_sector, sectors, 0, lpar,
292  &dev->tag);
293  if (res) {
294  dev_dbg(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
295  __LINE__, op, res);
296  return -1;
297  }
298 
299  wait_for_completion(&dev->done);
300  if (dev->lv1_status) {
301  dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
302  __LINE__, op, dev->lv1_status);
303  return dev->lv1_status;
304  }
305 
306  dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__, __LINE__,
307  op);
308 
309  return 0;
310 }
312 
313 
327  u64 arg2, u64 arg3, u64 arg4)
328 {
329  int res;
330 
331  dev_dbg(&dev->sbd.core, "%s:%u: send device command 0x%llx\n", __func__,
332  __LINE__, cmd);
333 
334  init_completion(&dev->done);
335 
336  res = lv1_storage_send_device_command(dev->sbd.dev_id, cmd, arg1,
337  arg2, arg3, arg4, &dev->tag);
338  if (res) {
339  dev_err(&dev->sbd.core,
340  "%s:%u: send_device_command 0x%llx failed %d\n",
341  __func__, __LINE__, cmd, res);
342  return -1;
343  }
344 
345  wait_for_completion(&dev->done);
346  if (dev->lv1_status) {
347  dev_dbg(&dev->sbd.core, "%s:%u: command 0x%llx failed 0x%llx\n",
348  __func__, __LINE__, cmd, dev->lv1_status);
349  return dev->lv1_status;
350  }
351 
352  dev_dbg(&dev->sbd.core, "%s:%u: command 0x%llx completed\n", __func__,
353  __LINE__, cmd);
354 
355  return 0;
356 }
358 
359 
360 MODULE_LICENSE("GPL");
361 MODULE_DESCRIPTION("PS3 Storage Bus Library");
362 MODULE_AUTHOR("Sony Corporation");